1 /*
2 sw32_rmain.c
3
4 (description)
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #define NH_DEFINE
32 #include "namehack.h"
33
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40
41 #include <math.h>
42
43 #include "QF/cmd.h"
44 #include "QF/cvar.h"
45 #include "QF/locs.h"
46 #include "QF/mathlib.h"
47 #include "QF/render.h"
48 #include "QF/screen.h"
49 #include "QF/sound.h"
50 #include "QF/sys.h"
51
52 #include "compat.h"
53 #include "mod_internal.h"
54 #include "r_internal.h"
55 #include "vid_internal.h"
56
57 //define PASSAGES
58
59 static vec3_t viewlightvec;
60 static alight_t r_viewlighting = { 128, 192, viewlightvec };
61 int sw32_r_numallocatededges;
62 qboolean sw32_r_drawpolys;
63 qboolean sw32_r_drawculledpolys;
64 qboolean sw32_r_worldpolysbacktofront;
65 int sw32_r_pixbytes = 1;
66 float sw32_r_aliasuvscale = 1.0;
67 int sw32_r_outofsurfaces;
68 int sw32_r_outofedges;
69
70 qboolean sw32_r_dowarp, sw32_r_dowarpold, sw32_r_viewchanged;
71
72 int sw32_c_surf;
73 int sw32_r_maxsurfsseen, sw32_r_maxedgesseen;
74 static int r_cnumsurfs;
75 static qboolean r_surfsonstack;
76 int sw32_r_clipflags;
77
78 byte *sw32_r_warpbuffer;
79
80 static byte *r_stack_start;
81
82 // screen size info
83 float sw32_xcenter, sw32_ycenter;
84 float sw32_xscale, sw32_yscale;
85 float sw32_xscaleinv, sw32_yscaleinv;
86 float sw32_xscaleshrink, sw32_yscaleshrink;
87 float sw32_aliasxscale, sw32_aliasyscale, sw32_aliasxcenter, sw32_aliasycenter;
88
89 int sw32_screenwidth;
90
91 float sw32_pixelAspect;
92 static float screenAspect;
93 static float verticalFieldOfView;
94 static float xOrigin, yOrigin;
95
96 plane_t sw32_screenedge[4];
97
98 // refresh flags
99 int sw32_r_polycount;
100 int sw32_r_drawnpolycount;
101
102 int *sw32_pfrustum_indexes[4];
103 int sw32_r_frustum_indexes[4 * 6];
104
105 float sw32_r_aliastransition, sw32_r_resfudge;
106
107 static float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
108 static float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
109
110 void
sw32_R_Textures_Init(void)111 sw32_R_Textures_Init (void)
112 {
113 int x, y, m;
114 byte *dest;
115
116 // create a simple checkerboard texture for the default
117 r_notexture_mip =
118 Hunk_AllocName (sizeof (texture_t) + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2,
119 "notexture");
120
121 r_notexture_mip->width = r_notexture_mip->height = 16;
122 r_notexture_mip->offsets[0] = sizeof (texture_t);
123
124 r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16 * 16;
125 r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8 * 8;
126 r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4 * 4;
127
128 for (m = 0; m < 4; m++) {
129 dest = (byte *) r_notexture_mip + r_notexture_mip->offsets[m];
130 for (y = 0; y < (16 >> m); y++)
131 for (x = 0; x < (16 >> m); x++) {
132 if ((y < (8 >> m)) ^ (x < (8 >> m)))
133 *dest++ = 0;
134 else
135 *dest++ = 0xff;
136 }
137 }
138 }
139
140 void
sw32_R_Init(void)141 sw32_R_Init (void)
142 {
143 int dummy;
144
145 // get stack position so we can guess if we are going to overflow
146 r_stack_start = (byte *) & dummy;
147
148 R_Init_Cvars ();
149 sw32_R_Particles_Init_Cvars ();
150
151 sw32_Draw_Init ();
152 SCR_Init ();
153 sw32_R_InitTurb ();
154
155 Cmd_AddCommand ("timerefresh", sw32_R_TimeRefresh_f, "Tests the current "
156 "refresh rate for the current location");
157 Cmd_AddCommand ("pointfile", sw32_R_ReadPointFile_f, "Load a pointfile to "
158 "determine map leaks");
159 Cmd_AddCommand ("loadsky", sw32_R_LoadSky_f, "Load a skybox");
160
161 Cvar_SetValue (r_maxedges, (float) NUMSTACKEDGES);
162 Cvar_SetValue (r_maxsurfs, (float) NUMSTACKSURFACES);
163
164 sw32_view_clipplanes[0].leftedge = true;
165 sw32_view_clipplanes[1].rightedge = true;
166 sw32_view_clipplanes[1].leftedge = sw32_view_clipplanes[2].leftedge =
167 sw32_view_clipplanes[3].leftedge = false;
168 sw32_view_clipplanes[0].rightedge = sw32_view_clipplanes[2].rightedge =
169 sw32_view_clipplanes[3].rightedge = false;
170
171 r_refdef.xOrigin = XCENTERING;
172 r_refdef.yOrigin = YCENTERING;
173
174 sw32_D_Init ();
175
176 Skin_Init ();
177 }
178
179 void
sw32_R_NewMap(model_t * worldmodel,struct model_s ** models,int num_models)180 sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
181 {
182 int i;
183
184 memset (&r_worldentity, 0, sizeof (r_worldentity));
185 r_worldentity.model = worldmodel;
186
187 R_FreeAllEntities ();
188
189 // clear out efrags in case the level hasn't been reloaded
190 // FIXME: is this one short?
191 for (i = 0; i < r_worldentity.model->numleafs; i++)
192 r_worldentity.model->leafs[i].efrags = NULL;
193
194 if (worldmodel->skytexture)
195 sw32_R_InitSky (worldmodel->skytexture);
196
197 // Force a vis update
198 r_viewleaf = NULL;
199 R_MarkLeaves ();
200
201 sw32_R_ClearParticles ();
202
203 r_cnumsurfs = r_maxsurfs->int_val;
204
205 if (r_cnumsurfs <= MINSURFACES)
206 r_cnumsurfs = MINSURFACES;
207
208 if (r_cnumsurfs > NUMSTACKSURFACES) {
209 sw32_surfaces = Hunk_AllocName (r_cnumsurfs * sizeof (surf_t), "surfaces");
210
211 sw32_surface_p = sw32_surfaces;
212 sw32_surf_max = &sw32_surfaces[r_cnumsurfs];
213 r_surfsonstack = false;
214 // surface 0 doesn't really exist; it's just a dummy because index 0
215 // is used to indicate no edge attached to surface
216 sw32_surfaces--;
217 } else {
218 r_surfsonstack = true;
219 }
220
221 sw32_r_maxedgesseen = 0;
222 sw32_r_maxsurfsseen = 0;
223
224 sw32_r_numallocatededges = r_maxedges->int_val;
225
226 if (sw32_r_numallocatededges < MINEDGES)
227 sw32_r_numallocatededges = MINEDGES;
228
229 if (sw32_r_numallocatededges <= NUMSTACKEDGES) {
230 sw32_auxedges = NULL;
231 } else {
232 sw32_auxedges = Hunk_AllocName (sw32_r_numallocatededges * sizeof (edge_t),
233 "edges");
234 }
235
236 sw32_r_dowarpold = false;
237 sw32_r_viewchanged = false;
238 }
239
240 /*
241 R_ViewChanged
242
243 Called every time the vid structure or r_refdef changes.
244 Guaranteed to be called before the first refresh
245 */
246 void
sw32_R_ViewChanged(float aspect)247 sw32_R_ViewChanged (float aspect)
248 {
249 int i;
250 float res_scale;
251
252 sw32_r_viewchanged = true;
253
254 r_refdef.horizontalFieldOfView = 2.0 * tan (r_refdef.fov_x / 360 * M_PI);
255 r_refdef.fvrectx = (float) r_refdef.vrect.x;
256 r_refdef.fvrectx_adj = (float) r_refdef.vrect.x - 0.5;
257 r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x << 20) + (1 << 19) - 1;
258 r_refdef.fvrecty = (float) r_refdef.vrect.y;
259 r_refdef.fvrecty_adj = (float) r_refdef.vrect.y - 0.5;
260 r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
261 r_refdef.vrectright_adj_shift20 =
262 (r_refdef.vrectright << 20) + (1 << 19) - 1;
263 r_refdef.fvrectright = (float) r_refdef.vrectright;
264 r_refdef.fvrectright_adj = (float) r_refdef.vrectright - 0.5;
265 r_refdef.vrectrightedge = (float) r_refdef.vrectright - 0.99;
266 r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
267 r_refdef.fvrectbottom = (float) r_refdef.vrectbottom;
268 r_refdef.fvrectbottom_adj = (float) r_refdef.vrectbottom - 0.5;
269
270 r_refdef.aliasvrect.x = (int) (r_refdef.vrect.x * sw32_r_aliasuvscale);
271 r_refdef.aliasvrect.y = (int) (r_refdef.vrect.y * sw32_r_aliasuvscale);
272 r_refdef.aliasvrect.width = (int) (r_refdef.vrect.width * sw32_r_aliasuvscale);
273 r_refdef.aliasvrect.height = (int) (r_refdef.vrect.height *
274 sw32_r_aliasuvscale);
275 r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
276 r_refdef.aliasvrect.width;
277 r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
278 r_refdef.aliasvrect.height;
279
280 sw32_pixelAspect = aspect;
281 xOrigin = r_refdef.xOrigin;
282 yOrigin = r_refdef.yOrigin;
283
284 screenAspect = r_refdef.vrect.width * sw32_pixelAspect / r_refdef.vrect.height;
285 // 320*200 1.0 sw32_pixelAspect = 1.6 screenAspect
286 // 320*240 1.0 sw32_pixelAspect = 1.3333 screenAspect
287 // proper 320*200 sw32_pixelAspect = 0.8333333
288
289 verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect;
290
291 // values for perspective projection
292 // if math were exact, the values would range from 0.5 to to range+0.5
293 // hopefully they wll be in the 0.000001 to range+.999999 and truncate
294 // the polygon rasterization will never render in the first row or column
295 // but will definately render in the [range] row and column, so adjust the
296 // buffer origin to get an exact edge to edge fill
297 sw32_xcenter = ((float) r_refdef.vrect.width * XCENTERING) +
298 r_refdef.vrect.x - 0.5;
299 sw32_aliasxcenter = sw32_xcenter * sw32_r_aliasuvscale;
300 sw32_ycenter = ((float) r_refdef.vrect.height * YCENTERING) +
301 r_refdef.vrect.y - 0.5;
302 sw32_aliasycenter = sw32_ycenter * sw32_r_aliasuvscale;
303
304 sw32_xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
305 sw32_aliasxscale = sw32_xscale * sw32_r_aliasuvscale;
306 sw32_xscaleinv = 1.0 / sw32_xscale;
307 sw32_yscale = sw32_xscale * sw32_pixelAspect;
308 sw32_aliasyscale = sw32_yscale * sw32_r_aliasuvscale;
309 sw32_yscaleinv = 1.0 / sw32_yscale;
310 sw32_xscaleshrink = (r_refdef.vrect.width - 6) / r_refdef.horizontalFieldOfView;
311 sw32_yscaleshrink = sw32_xscaleshrink * sw32_pixelAspect;
312
313 // left side clip
314 sw32_screenedge[0].normal[0] = -1.0 / (xOrigin *
315 r_refdef.horizontalFieldOfView);
316 sw32_screenedge[0].normal[1] = 0;
317 sw32_screenedge[0].normal[2] = 1;
318 sw32_screenedge[0].type = PLANE_ANYZ;
319
320 // right side clip
321 sw32_screenedge[1].normal[0] = 1.0 / ((1.0 - xOrigin) *
322 r_refdef.horizontalFieldOfView);
323 sw32_screenedge[1].normal[1] = 0;
324 sw32_screenedge[1].normal[2] = 1;
325 sw32_screenedge[1].type = PLANE_ANYZ;
326
327 // top side clip
328 sw32_screenedge[2].normal[0] = 0;
329 sw32_screenedge[2].normal[1] = -1.0 / (yOrigin * verticalFieldOfView);
330 sw32_screenedge[2].normal[2] = 1;
331 sw32_screenedge[2].type = PLANE_ANYZ;
332
333 // bottom side clip
334 sw32_screenedge[3].normal[0] = 0;
335 sw32_screenedge[3].normal[1] = 1.0 / ((1.0 - yOrigin) * verticalFieldOfView);
336 sw32_screenedge[3].normal[2] = 1;
337 sw32_screenedge[3].type = PLANE_ANYZ;
338
339 for (i = 0; i < 4; i++)
340 VectorNormalize (sw32_screenedge[i].normal);
341
342 res_scale = sqrt ((double) (r_refdef.vrect.width * r_refdef.vrect.height) /
343 (320.0 * 152.0)) * (2.0 /
344 r_refdef.horizontalFieldOfView);
345 sw32_r_aliastransition = r_aliastransbase->value * res_scale;
346 sw32_r_resfudge = r_aliastransadj->value * res_scale;
347
348 sw32_D_ViewChanged ();
349 }
350
351 static void
R_DrawEntitiesOnList(void)352 R_DrawEntitiesOnList (void)
353 {
354 int j;
355 unsigned int lnum;
356 alight_t lighting;
357 entity_t *ent;
358
359 // FIXME: remove and do real lighting
360 float lightvec[3] = { -1, 0, 0 };
361 vec3_t dist;
362 float add;
363 float minlight;
364
365 if (!r_drawentities->int_val)
366 return;
367
368 for (ent = r_ent_queue; ent; ent = ent->next) {
369 currententity = ent;
370
371 switch (currententity->model->type) {
372 case mod_sprite:
373 VectorCopy (currententity->origin, r_entorigin);
374 VectorSubtract (r_origin, r_entorigin, modelorg);
375 sw32_R_DrawSprite ();
376 break;
377
378 case mod_alias:
379 case mod_iqm:
380 VectorCopy (currententity->origin, r_entorigin);
381 VectorSubtract (r_origin, r_entorigin, modelorg);
382
383 minlight = max (currententity->min_light, currententity->model->min_light);
384
385 // see if the bounding box lets us trivially reject, also
386 // sets trivial accept status
387 currententity->trivial_accept = 0; //FIXME
388 if (currententity->model->type == mod_iqm//FIXME
389 || sw32_R_AliasCheckBBox ()) {
390 // 128 instead of 255 due to clamping below
391 j = max (R_LightPoint (currententity->origin), minlight * 128);
392
393 lighting.ambientlight = j;
394 lighting.shadelight = j;
395
396 lighting.plightvec = lightvec;
397
398 for (lnum = 0; lnum < r_maxdlights; lnum++) {
399 if (r_dlights[lnum].die >= vr_data.realtime) {
400 VectorSubtract (currententity->origin,
401 r_dlights[lnum].origin, dist);
402 add = r_dlights[lnum].radius - VectorLength (dist);
403
404 if (add > 0)
405 lighting.ambientlight += add;
406 }
407 }
408
409 // clamp lighting so it doesn't overbright as much
410 if (lighting.ambientlight > 128)
411 lighting.ambientlight = 128;
412 if (lighting.ambientlight + lighting.shadelight > 192)
413 lighting.shadelight = 192 - lighting.ambientlight;
414
415 if (currententity->model->type == mod_iqm)
416 sw32_R_IQMDrawModel (&lighting);
417 else
418 sw32_R_AliasDrawModel (&lighting);
419 }
420
421 break;
422
423 default:
424 break;
425 }
426 }
427 }
428
429 static void
R_DrawViewModel(void)430 R_DrawViewModel (void)
431 {
432 // FIXME: remove and do real lighting
433 float lightvec[3] = { -1, 0, 0 };
434 int j;
435 unsigned int lnum;
436 vec3_t dist;
437 float add;
438 float minlight;
439 dlight_t *dl;
440
441 if (vr_data.inhibit_viewmodel || !r_drawviewmodel->int_val
442 || !r_drawentities->int_val)
443 return;
444
445 currententity = vr_data.view_model;
446 if (!currententity->model)
447 return;
448
449 VectorCopy (currententity->origin, r_entorigin);
450 VectorSubtract (r_origin, r_entorigin, modelorg);
451
452 VectorCopy (vup, viewlightvec);
453 VectorNegate (viewlightvec, viewlightvec);
454
455 minlight = max (currententity->min_light, currententity->model->min_light);
456
457 j = max (R_LightPoint (currententity->origin), minlight * 128);
458
459 r_viewlighting.ambientlight = j;
460 r_viewlighting.shadelight = j;
461
462 // add dynamic lights
463 for (lnum = 0; lnum < r_maxdlights; lnum++) {
464 dl = &r_dlights[lnum];
465 if (!dl->radius)
466 continue;
467 if (!dl->radius)
468 continue;
469 if (dl->die < vr_data.realtime)
470 continue;
471
472 VectorSubtract (currententity->origin, dl->origin, dist);
473 add = dl->radius - VectorLength (dist);
474 if (add > 0)
475 r_viewlighting.ambientlight += add;
476 }
477
478 // clamp lighting so it doesn't overbright as much
479 if (r_viewlighting.ambientlight > 128)
480 r_viewlighting.ambientlight = 128;
481 if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192)
482 r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight;
483
484 r_viewlighting.plightvec = lightvec;
485
486 sw32_R_AliasDrawModel (&r_viewlighting);
487 }
488
489 static int
R_BmodelCheckBBox(model_t * clmodel,float * minmaxs)490 R_BmodelCheckBBox (model_t *clmodel, float *minmaxs)
491 {
492 int i, *pindex, clipflags;
493 vec3_t acceptpt, rejectpt;
494 double d;
495
496 clipflags = 0;
497
498 if (currententity->transform[0] != 1 || currententity->transform[5] != 1
499 || currententity->transform[10] != 1) {
500 for (i = 0; i < 4; i++) {
501 d = DotProduct (currententity->origin, sw32_view_clipplanes[i].normal);
502 d -= sw32_view_clipplanes[i].dist;
503
504 if (d <= -clmodel->radius)
505 return BMODEL_FULLY_CLIPPED;
506
507 if (d <= clmodel->radius)
508 clipflags |= (1 << i);
509 }
510 } else {
511 for (i = 0; i < 4; i++) {
512 // generate accept and reject points
513 // FIXME: do with fast look-ups or integer tests based on the
514 // sign bit of the floating point values
515
516 pindex = sw32_pfrustum_indexes[i];
517
518 rejectpt[0] = minmaxs[pindex[0]];
519 rejectpt[1] = minmaxs[pindex[1]];
520 rejectpt[2] = minmaxs[pindex[2]];
521
522 d = DotProduct (rejectpt, sw32_view_clipplanes[i].normal);
523 d -= sw32_view_clipplanes[i].dist;
524
525 if (d <= 0)
526 return BMODEL_FULLY_CLIPPED;
527
528 acceptpt[0] = minmaxs[pindex[3 + 0]];
529 acceptpt[1] = minmaxs[pindex[3 + 1]];
530 acceptpt[2] = minmaxs[pindex[3 + 2]];
531
532 d = DotProduct (acceptpt, sw32_view_clipplanes[i].normal);
533 d -= sw32_view_clipplanes[i].dist;
534
535 if (d <= 0)
536 clipflags |= (1 << i);
537 }
538 }
539
540 return clipflags;
541 }
542
543 static void
R_DrawBEntitiesOnList(void)544 R_DrawBEntitiesOnList (void)
545 {
546 int j, clipflags;
547 unsigned int k;
548 vec3_t oldorigin;
549 model_t *clmodel;
550 float minmaxs[6];
551 entity_t *ent;
552
553 if (!r_drawentities->int_val)
554 return;
555
556 VectorCopy (modelorg, oldorigin);
557 insubmodel = true;
558
559 for (ent = r_ent_queue; ent; ent = ent->next) {
560 currententity = ent;
561
562 switch (currententity->model->type) {
563 case mod_brush:
564 clmodel = currententity->model;
565
566 // see if the bounding box lets us trivially reject, also
567 // sets trivial accept status
568 for (j = 0; j < 3; j++) {
569 minmaxs[j] = currententity->origin[j] + clmodel->mins[j];
570 minmaxs[3 + j] = currententity->origin[j] +
571 clmodel->maxs[j];
572 }
573
574 clipflags = R_BmodelCheckBBox (clmodel, minmaxs);
575
576 if (clipflags != BMODEL_FULLY_CLIPPED) {
577 VectorCopy (currententity->origin, r_entorigin);
578 VectorSubtract (r_origin, r_entorigin, modelorg);
579
580 // FIXME: is this needed?
581 VectorCopy (modelorg, sw32_r_worldmodelorg);
582 r_pcurrentvertbase = clmodel->vertexes;
583
584 // FIXME: stop transforming twice
585 sw32_R_RotateBmodel ();
586
587 // calculate dynamic lighting for bmodel if it's not an
588 // instanced model
589 if (clmodel->firstmodelsurface != 0) {
590 vec3_t lightorigin;
591
592 for (k = 0; k < r_maxdlights; k++) {
593 if ((r_dlights[k].die < vr_data.realtime) ||
594 (!r_dlights[k].radius)) continue;
595
596 VectorSubtract (r_dlights[k].origin,
597 currententity->origin,
598 lightorigin);
599 R_RecursiveMarkLights (lightorigin, &r_dlights[k],
600 1 << k, clmodel->nodes +
601 clmodel->hulls[0].firstclipnode);
602 }
603 }
604 // if the driver wants polygons, deliver those.
605 // Z-buffering is on at this point, so no clipping to the
606 // world tree is needed, just frustum clipping
607 if (sw32_r_drawpolys | sw32_r_drawculledpolys) {
608 sw32_R_ZDrawSubmodelPolys (clmodel);
609 } else {
610 if (currententity->topnode) {
611 mnode_t *topnode = currententity->topnode;
612
613 if (topnode->contents >= 0) {
614 // not a leaf; has to be clipped to the world
615 // BSP
616 sw32_r_clipflags = clipflags;
617 sw32_R_DrawSolidClippedSubmodelPolygons (clmodel);
618 } else {
619 // falls entirely in one leaf, so we just put
620 // all the edges in the edge list and let 1/z
621 // sorting handle drawing order
622 sw32_R_DrawSubmodelPolygons (clmodel, clipflags);
623 }
624 }
625 }
626
627 // put back world rotation and frustum clipping
628 // FIXME: sw32_R_RotateBmodel should just work off base_vxx
629 VectorCopy (base_vpn, vpn);
630 VectorCopy (base_vup, vup);
631 VectorCopy (base_vright, vright);
632 VectorCopy (base_modelorg, modelorg);
633 VectorCopy (oldorigin, modelorg);
634 sw32_R_TransformFrustum ();
635 }
636 break;
637 default:
638 break;
639 }
640 }
641
642 insubmodel = false;
643 }
644
645 static void
R_PrintDSpeeds(void)646 R_PrintDSpeeds (void)
647 {
648 float ms, dp_time, r_time2, rw_time, db_time, se_time, de_time,
649
650 dv_time;
651
652 r_time2 = Sys_DoubleTime ();
653
654 dp_time = (dp_time2 - dp_time1) * 1000;
655 rw_time = (rw_time2 - rw_time1) * 1000;
656 db_time = (db_time2 - db_time1) * 1000;
657 se_time = (se_time2 - se_time1) * 1000;
658 de_time = (de_time2 - de_time1) * 1000;
659 dv_time = (dv_time2 - dv_time1) * 1000;
660 ms = (r_time2 - r_time1) * 1000;
661
662 Sys_Printf ("%3i %4.1fp %3iw %4.1fb %3is %4.1fe %4.1fv\n",
663 (int) ms, dp_time, (int) rw_time, db_time, (int) se_time,
664 de_time, dv_time);
665 }
666
667 static void
R_EdgeDrawing(void)668 R_EdgeDrawing (void)
669 {
670 edge_t ledges[NUMSTACKEDGES +
671 ((CACHE_SIZE - 1) / sizeof (edge_t)) + 1];
672 surf_t lsurfs[NUMSTACKSURFACES +
673 ((CACHE_SIZE - 1) / sizeof (surf_t)) + 1];
674
675 if (sw32_auxedges) {
676 sw32_r_edges = sw32_auxedges;
677 } else {
678 sw32_r_edges = (edge_t *)
679 (((intptr_t) &ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
680 }
681
682 if (r_surfsonstack) {
683 sw32_surfaces = (surf_t *)
684 (((intptr_t) &lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
685 sw32_surf_max = &sw32_surfaces[r_cnumsurfs];
686 // surface 0 doesn't really exist; it's just a dummy because index 0
687 // is used to indicate no edge attached to surface
688 sw32_surfaces--;
689 }
690
691 sw32_R_BeginEdgeFrame ();
692
693 if (r_dspeeds->int_val) {
694 rw_time1 = Sys_DoubleTime ();
695 }
696
697 sw32_R_RenderWorld ();
698
699 if (sw32_r_drawculledpolys)
700 sw32_R_ScanEdges ();
701
702 // only the world can be drawn back to front with no z reads or compares,
703 // just z writes, so have the driver turn z compares on now
704 sw32_D_TurnZOn ();
705
706 if (r_dspeeds->int_val) {
707 rw_time2 = Sys_DoubleTime ();
708 db_time1 = rw_time2;
709 }
710
711 R_DrawBEntitiesOnList ();
712
713 if (r_dspeeds->int_val) {
714 db_time2 = Sys_DoubleTime ();
715 se_time1 = db_time2;
716 }
717
718 if (!r_dspeeds->int_val) {
719 VID_UnlockBuffer ();
720 S_ExtraUpdate (); // don't let sound get messed up if going slow
721 VID_LockBuffer ();
722 }
723
724 if (!(sw32_r_drawpolys | sw32_r_drawculledpolys))
725 sw32_R_ScanEdges ();
726 }
727
728 // LordHavoc: took out of stack and made 4x size for 32bit capacity
729 static byte warpbuffer[WARP_WIDTH * WARP_HEIGHT * 4];
730
731 /*
732 R_RenderView
733
734 r_refdef must be set before the first call
735 */
736 static void
R_RenderView_(void)737 R_RenderView_ (void)
738 {
739 if (r_norefresh->int_val)
740 return;
741
742 sw32_r_warpbuffer = warpbuffer;
743
744 if (r_timegraph->int_val || r_speeds->int_val || r_dspeeds->int_val)
745 r_time1 = Sys_DoubleTime ();
746
747 sw32_R_SetupFrame ();
748
749 #ifdef PASSAGES
750 SetVisibilityByPassages ();
751 #else
752 R_MarkLeaves (); // done here so we know if we're in water
753 #endif
754 R_PushDlights (vec3_origin);
755
756 if (!r_worldentity.model)
757 Sys_Error ("R_RenderView: NULL worldmodel");
758
759 if (!r_dspeeds->int_val) {
760 VID_UnlockBuffer ();
761 S_ExtraUpdate (); // don't let sound get messed up if going slow
762 VID_LockBuffer ();
763 }
764
765 R_EdgeDrawing ();
766
767 if (!r_dspeeds->int_val) {
768 VID_UnlockBuffer ();
769 S_ExtraUpdate (); // don't let sound get messed up if going slow
770 VID_LockBuffer ();
771 }
772
773 if (r_dspeeds->int_val) {
774 se_time2 = Sys_DoubleTime ();
775 de_time1 = se_time2;
776 }
777
778 R_DrawEntitiesOnList ();
779
780 if (r_dspeeds->int_val) {
781 de_time2 = Sys_DoubleTime ();
782 dv_time1 = de_time2;
783 }
784
785 R_DrawViewModel ();
786
787 if (r_dspeeds->int_val) {
788 dv_time2 = Sys_DoubleTime ();
789 dp_time1 = Sys_DoubleTime ();
790 }
791
792 sw32_R_DrawParticles ();
793
794 if (r_dspeeds->int_val)
795 dp_time2 = Sys_DoubleTime ();
796
797 if (sw32_r_dowarp)
798 sw32_D_WarpScreen ();
799
800 if (r_timegraph->int_val)
801 R_TimeGraph ();
802
803 if (r_zgraph->int_val)
804 R_ZGraph ();
805
806 if (r_aliasstats->int_val)
807 sw32_R_PrintAliasStats ();
808
809 if (r_speeds->int_val)
810 sw32_R_PrintTimes ();
811
812 if (r_dspeeds->int_val)
813 R_PrintDSpeeds ();
814
815 if (r_reportsurfout->int_val && sw32_r_outofsurfaces)
816 Sys_Printf ("Short %d surfaces\n", sw32_r_outofsurfaces);
817
818 if (r_reportedgeout->int_val && sw32_r_outofedges)
819 Sys_Printf ("Short roughly %d edges\n", sw32_r_outofedges * 2 / 3);
820 }
821
822 void
sw32_R_RenderView(void)823 sw32_R_RenderView (void)
824 {
825 int dummy;
826 int delta;
827
828 delta = (byte *) & dummy - r_stack_start;
829 if (delta < -10000 || delta > 10000)
830 Sys_Error ("R_RenderView: called without enough stack");
831
832 if (Hunk_LowMark () & 3)
833 Sys_Error ("Hunk is missaligned");
834
835 if ((intptr_t) (&dummy) & 3)
836 Sys_Error ("Stack is missaligned");
837
838 if ((intptr_t) (&sw32_r_warpbuffer) & 3)
839 Sys_Error ("Globals are missaligned");
840
841 R_RenderView_ ();
842 }
843
844 void
sw32_R_InitTurb(void)845 sw32_R_InitTurb (void)
846 {
847 int i;
848
849 for (i = 0; i < MAXWIDTH; i++) {
850 sw32_sintable[i] = AMP + sin (i * 3.14159 * 2 / CYCLE) * AMP;
851 sw32_intsintable[i] = AMP2 + sin (i * 3.14159 * 2 / CYCLE) * AMP2;
852 // AMP2 not 20
853 }
854 }
855
856 void
sw32_R_ClearState(void)857 sw32_R_ClearState (void)
858 {
859 R_ClearEfrags ();
860 R_ClearDlights ();
861 sw32_R_ClearParticles ();
862 }
863