1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "r_local.h"
23
24 viddef_t vid;
25 refimport_t ri;
26
27 unsigned d_8to24table[256];
28
29 entity_t r_worldentity;
30
31 char skyname[MAX_QPATH];
32 float skyrotate;
33 vec3_t skyaxis;
34 image_t *sky_images[6];
35
36 refdef_t r_newrefdef;
37 model_t *currentmodel;
38
39 model_t *r_worldmodel;
40
41 byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
42
43 swstate_t sw_state;
44
45 void *colormap;
46 vec3_t viewlightvec;
47 alight_t r_viewlighting = {128, 192, viewlightvec};
48 float r_time1;
49 int r_numallocatededges;
50 float r_aliasuvscale = 1.0;
51 int r_outofsurfaces;
52 int r_outofedges;
53
54 qboolean r_dowarp;
55
56 mvertex_t *r_pcurrentvertbase;
57
58 int c_surf;
59 int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
60 qboolean r_surfsonstack;
61 int r_clipflags;
62
63 //
64 // view origin
65 //
66 vec3_t vup, base_vup;
67 vec3_t vpn, base_vpn;
68 vec3_t vright, base_vright;
69 vec3_t r_origin;
70
71 //
72 // screen size info
73 //
74 oldrefdef_t r_refdef;
75 float xcenter, ycenter;
76 float xscale, yscale;
77 float xscaleinv, yscaleinv;
78 float xscaleshrink, yscaleshrink;
79 float aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
80
81 int r_screenwidth;
82
83 float verticalFieldOfView;
84 float xOrigin, yOrigin;
85
86 mplane_t screenedge[4];
87
88 //
89 // refresh flags
90 //
91 int r_framecount = 1; // so frame counts initialized to 0 don't match
92 int r_visframecount;
93 int d_spanpixcount;
94 int r_polycount;
95 int r_drawnpolycount;
96 int r_wholepolycount;
97
98 int *pfrustum_indexes[4];
99 int r_frustum_indexes[4*6];
100
101 mleaf_t *r_viewleaf;
102 int r_viewcluster, r_oldviewcluster;
103
104 image_t *r_notexture_mip;
105
106 float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
107 float se_time1, se_time2, de_time1, de_time2;
108
109 void R_MarkLeaves (void);
110
111 cvar_t *r_lefthand;
112 cvar_t *sw_aliasstats;
113 cvar_t *sw_allow_modex;
114 cvar_t *sw_clearcolor;
115 cvar_t *sw_drawflat;
116 cvar_t *sw_draworder;
117 cvar_t *sw_maxedges;
118 cvar_t *sw_maxsurfs;
119 cvar_t *sw_mode;
120 cvar_t *sw_reportedgeout;
121 cvar_t *sw_reportsurfout;
122 cvar_t *sw_stipplealpha;
123 cvar_t *sw_surfcacheoverride;
124 cvar_t *sw_waterwarp;
125
126 cvar_t *r_drawworld;
127 cvar_t *r_drawentities;
128 cvar_t *r_dspeeds;
129 cvar_t *r_fullbright;
130 cvar_t *r_lerpmodels;
131 cvar_t *r_novis;
132
133 cvar_t *r_speeds;
134 cvar_t *r_lightlevel; //FIXME HACK
135
136 cvar_t *vid_fullscreen;
137 cvar_t *vid_gamma;
138
139 //PGM
140 cvar_t *sw_lockpvs;
141 //PGM
142
143 #define STRINGER(x) "x"
144
145
146 #if !id386
147
148 // r_vars.c
149
150 // all global and static refresh variables are collected in a contiguous block
151 // to avoid cache conflicts.
152
153 //-------------------------------------------------------
154 // global refresh variables
155 //-------------------------------------------------------
156
157 // FIXME: make into one big structure, like cl or sv
158 // FIXME: do separately for refresh engine and driver
159
160
161 // d_vars.c
162
163 // all global and static refresh variables are collected in a contiguous block
164 // to avoid cache conflicts.
165
166 //-------------------------------------------------------
167 // global refresh variables
168 //-------------------------------------------------------
169
170 // FIXME: make into one big structure, like cl or sv
171 // FIXME: do separately for refresh engine and driver
172
173 float d_sdivzstepu, d_tdivzstepu, d_zistepu;
174 float d_sdivzstepv, d_tdivzstepv, d_zistepv;
175 float d_sdivzorigin, d_tdivzorigin, d_ziorigin;
176
177 fixed16_t sadjust, tadjust, bbextents, bbextentt;
178
179 pixel_t *cacheblock;
180 int cachewidth;
181 pixel_t *d_viewbuffer;
182 short *d_pzbuffer;
183 unsigned int d_zrowbytes;
184 unsigned int d_zwidth;
185
186
187 #endif // !id386
188
189 byte r_notexture_buffer[1024];
190
191 /*
192 ==================
193 R_InitTextures
194 ==================
195 */
R_InitTextures(void)196 void R_InitTextures (void)
197 {
198 int x,y, m;
199 byte *dest;
200
201 // create a simple checkerboard texture for the default
202 r_notexture_mip = (image_t *)&r_notexture_buffer;
203
204 r_notexture_mip->width = r_notexture_mip->height = 16;
205 r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
206 r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
207 r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
208 r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
209
210 for (m=0 ; m<4 ; m++)
211 {
212 dest = r_notexture_mip->pixels[m];
213 for (y=0 ; y< (16>>m) ; y++)
214 for (x=0 ; x< (16>>m) ; x++)
215 {
216 if ( (y< (8>>m) ) ^ (x< (8>>m) ) )
217
218 *dest++ = 0;
219 else
220 *dest++ = 0xff;
221 }
222 }
223 }
224
225
226 /*
227 ================
228 R_InitTurb
229 ================
230 */
R_InitTurb(void)231 void R_InitTurb (void)
232 {
233 int i;
234
235 for (i=0 ; i<1280 ; i++)
236 {
237 sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
238 intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20
239 blanktable[i] = 0; //PGM
240 }
241 }
242
243 void R_ImageList_f( void );
244
R_Register(void)245 void R_Register (void)
246 {
247 sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
248 sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );
249 sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
250 sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);
251 sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);
252 sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
253 sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);
254 sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);
255 sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);
256 sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);
257 sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);
258 sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
259 sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);
260 sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);
261 sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );
262
263 r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
264 r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
265 r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
266 r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
267 r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
268 r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);
269 r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
270 r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );
271 r_novis = ri.Cvar_Get( "r_novis", "0", 0 );
272
273 vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
274 vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
275
276 ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);
277 ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
278 ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
279
280 sw_mode->modified = true; // force us to do mode specific stuff later
281 vid_gamma->modified = true; // force us to rebuild the gamma table later
282
283 //PGM
284 sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
285 //PGM
286 }
287
R_UnRegister(void)288 void R_UnRegister (void)
289 {
290 ri.Cmd_RemoveCommand( "screenshot" );
291 ri.Cmd_RemoveCommand ("modellist");
292 ri.Cmd_RemoveCommand( "imagelist" );
293 }
294
295 /*
296 ===============
297 R_Init
298 ===============
299 */
R_Init(void * hInstance,void * wndProc)300 int R_Init( void *hInstance, void *wndProc )
301 {
302 R_InitImages ();
303 Mod_Init ();
304 Draw_InitLocal ();
305 R_InitTextures ();
306
307 R_InitTurb ();
308
309 view_clipplanes[0].leftedge = true;
310 view_clipplanes[1].rightedge = true;
311 view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
312 view_clipplanes[3].leftedge = false;
313 view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
314 view_clipplanes[3].rightedge = false;
315
316 r_refdef.xOrigin = XCENTERING;
317 r_refdef.yOrigin = YCENTERING;
318
319 // TODO: collect 386-specific code in one place
320 #if id386
321 Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
322 (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
323 Sys_SetFPCW (); // get bit masks for FPCW (FIXME: is this id386?)
324 #endif // id386
325
326 r_aliasuvscale = 1.0;
327
328 R_Register ();
329 Draw_GetPalette ();
330 if (SWimp_Init( hInstance, wndProc ) == false)
331 return -1;
332
333 // create the window
334 R_BeginFrame( 0 );
335
336 ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
337
338 return true;
339 }
340
341 /*
342 ===============
343 R_Shutdown
344 ===============
345 */
R_Shutdown(void)346 void R_Shutdown (void)
347 {
348 // free z buffer
349 if (d_pzbuffer)
350 {
351 free (d_pzbuffer);
352 d_pzbuffer = NULL;
353 }
354 // free surface cache
355 if (sc_base)
356 {
357 D_FlushCaches ();
358 free (sc_base);
359 sc_base = NULL;
360 }
361
362 // free colormap
363 if (vid.colormap)
364 {
365 free (vid.colormap);
366 vid.colormap = NULL;
367 }
368 R_UnRegister ();
369 Mod_FreeAll ();
370 R_ShutdownImages ();
371
372 SWimp_Shutdown();
373 }
374
375 /*
376 ===============
377 R_NewMap
378 ===============
379 */
R_NewMap(void)380 void R_NewMap (void)
381 {
382 r_viewcluster = -1;
383
384 r_cnumsurfs = sw_maxsurfs->value;
385
386 if (r_cnumsurfs <= MINSURFACES)
387 r_cnumsurfs = MINSURFACES;
388
389 if (r_cnumsurfs > NUMSTACKSURFACES)
390 {
391 surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
392 surface_p = surfaces;
393 surf_max = &surfaces[r_cnumsurfs];
394 r_surfsonstack = false;
395 // surface 0 doesn't really exist; it's just a dummy because index 0
396 // is used to indicate no edge attached to surface
397 surfaces--;
398 R_SurfacePatch ();
399 }
400 else
401 {
402 r_surfsonstack = true;
403 }
404
405 r_maxedgesseen = 0;
406 r_maxsurfsseen = 0;
407
408 r_numallocatededges = sw_maxedges->value;
409
410 if (r_numallocatededges < MINEDGES)
411 r_numallocatededges = MINEDGES;
412
413 if (r_numallocatededges <= NUMSTACKEDGES)
414 {
415 auxedges = NULL;
416 }
417 else
418 {
419 auxedges = malloc (r_numallocatededges * sizeof(edge_t));
420 }
421 }
422
423
424 /*
425 ===============
426 R_MarkLeaves
427
428 Mark the leaves and nodes that are in the PVS for the current
429 cluster
430 ===============
431 */
R_MarkLeaves(void)432 void R_MarkLeaves (void)
433 {
434 byte *vis;
435 mnode_t *node;
436 int i;
437 mleaf_t *leaf;
438 int cluster;
439
440 if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
441 return;
442
443 // development aid to let you run around and see exactly where
444 // the pvs ends
445 if (sw_lockpvs->value)
446 return;
447
448 r_visframecount++;
449 r_oldviewcluster = r_viewcluster;
450
451 if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
452 {
453 // mark everything
454 for (i=0 ; i<r_worldmodel->numleafs ; i++)
455 r_worldmodel->leafs[i].visframe = r_visframecount;
456 for (i=0 ; i<r_worldmodel->numnodes ; i++)
457 r_worldmodel->nodes[i].visframe = r_visframecount;
458 return;
459 }
460
461 vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
462
463 for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
464 {
465 cluster = leaf->cluster;
466 if (cluster == -1)
467 continue;
468 if (vis[cluster>>3] & (1<<(cluster&7)))
469 {
470 node = (mnode_t *)leaf;
471 do
472 {
473 if (node->visframe == r_visframecount)
474 break;
475 node->visframe = r_visframecount;
476 node = node->parent;
477 } while (node);
478 }
479 }
480
481 #if 0
482 for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
483 {
484 if (vis[i>>3] & (1<<(i&7)))
485 {
486 node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster
487 do
488 {
489 if (node->visframe == r_visframecount)
490 break;
491 node->visframe = r_visframecount;
492 node = node->parent;
493 } while (node);
494 }
495 }
496 #endif
497 }
498
499 /*
500 ** R_DrawNullModel
501 **
502 ** IMPLEMENT THIS!
503 */
R_DrawNullModel(void)504 void R_DrawNullModel( void )
505 {
506 }
507
508 /*
509 =============
510 R_DrawEntitiesOnList
511 =============
512 */
R_DrawEntitiesOnList(void)513 void R_DrawEntitiesOnList (void)
514 {
515 int i;
516 qboolean translucent_entities = false;
517
518 if (!r_drawentities->value)
519 return;
520
521 // all bmodels have already been drawn by the edge list
522 for (i=0 ; i<r_newrefdef.num_entities ; i++)
523 {
524 currententity = &r_newrefdef.entities[i];
525
526 if ( currententity->flags & RF_TRANSLUCENT )
527 {
528 translucent_entities = true;
529 continue;
530 }
531
532 if ( currententity->flags & RF_BEAM )
533 {
534 modelorg[0] = -r_origin[0];
535 modelorg[1] = -r_origin[1];
536 modelorg[2] = -r_origin[2];
537 VectorCopy( vec3_origin, r_entorigin );
538 R_DrawBeam( currententity );
539 }
540 else
541 {
542 currentmodel = currententity->model;
543 if (!currentmodel)
544 {
545 R_DrawNullModel();
546 continue;
547 }
548 VectorCopy (currententity->origin, r_entorigin);
549 VectorSubtract (r_origin, r_entorigin, modelorg);
550
551 switch (currentmodel->type)
552 {
553 case mod_sprite:
554 R_DrawSprite ();
555 break;
556
557 case mod_alias:
558 R_AliasDrawModel ();
559 break;
560
561 default:
562 break;
563 }
564 }
565 }
566
567 if ( !translucent_entities )
568 return;
569
570 for (i=0 ; i<r_newrefdef.num_entities ; i++)
571 {
572 currententity = &r_newrefdef.entities[i];
573
574 if ( !( currententity->flags & RF_TRANSLUCENT ) )
575 continue;
576
577 if ( currententity->flags & RF_BEAM )
578 {
579 modelorg[0] = -r_origin[0];
580 modelorg[1] = -r_origin[1];
581 modelorg[2] = -r_origin[2];
582 VectorCopy( vec3_origin, r_entorigin );
583 R_DrawBeam( currententity );
584 }
585 else
586 {
587 currentmodel = currententity->model;
588 if (!currentmodel)
589 {
590 R_DrawNullModel();
591 continue;
592 }
593 VectorCopy (currententity->origin, r_entorigin);
594 VectorSubtract (r_origin, r_entorigin, modelorg);
595
596 switch (currentmodel->type)
597 {
598 case mod_sprite:
599 R_DrawSprite ();
600 break;
601
602 case mod_alias:
603 R_AliasDrawModel ();
604 break;
605
606 default:
607 break;
608 }
609 }
610 }
611 }
612
613
614 /*
615 =============
616 R_BmodelCheckBBox
617 =============
618 */
R_BmodelCheckBBox(float * minmaxs)619 int R_BmodelCheckBBox (float *minmaxs)
620 {
621 int i, *pindex, clipflags;
622 vec3_t acceptpt, rejectpt;
623 float d;
624
625 clipflags = 0;
626
627 for (i=0 ; i<4 ; i++)
628 {
629 // generate accept and reject points
630 // FIXME: do with fast look-ups or integer tests based on the sign bit
631 // of the floating point values
632
633 pindex = pfrustum_indexes[i];
634
635 rejectpt[0] = minmaxs[pindex[0]];
636 rejectpt[1] = minmaxs[pindex[1]];
637 rejectpt[2] = minmaxs[pindex[2]];
638
639 d = DotProduct (rejectpt, view_clipplanes[i].normal);
640 d -= view_clipplanes[i].dist;
641
642 if (d <= 0)
643 return BMODEL_FULLY_CLIPPED;
644
645 acceptpt[0] = minmaxs[pindex[3+0]];
646 acceptpt[1] = minmaxs[pindex[3+1]];
647 acceptpt[2] = minmaxs[pindex[3+2]];
648
649 d = DotProduct (acceptpt, view_clipplanes[i].normal);
650 d -= view_clipplanes[i].dist;
651
652 if (d <= 0)
653 clipflags |= (1<<i);
654 }
655
656 return clipflags;
657 }
658
659
660 /*
661 ===================
662 R_FindTopnode
663
664 Find the first node that splits the given box
665 ===================
666 */
R_FindTopnode(vec3_t mins,vec3_t maxs)667 mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
668 {
669 mplane_t *splitplane;
670 int sides;
671 mnode_t *node;
672
673 node = r_worldmodel->nodes;
674
675 while (1)
676 {
677 if (node->visframe != r_visframecount)
678 return NULL; // not visible at all
679
680 if (node->contents != CONTENTS_NODE)
681 {
682 if (node->contents != CONTENTS_SOLID)
683 return node; // we've reached a non-solid leaf, so it's
684 // visible and not BSP clipped
685 return NULL; // in solid, so not visible
686 }
687
688 splitplane = node->plane;
689 sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
690
691 if (sides == 3)
692 return node; // this is the splitter
693
694 // not split yet; recurse down the contacted side
695 if (sides & 1)
696 node = node->children[0];
697 else
698 node = node->children[1];
699 }
700 }
701
702
703 /*
704 =============
705 RotatedBBox
706
707 Returns an axially aligned box that contains the input box at the given rotation
708 =============
709 */
RotatedBBox(vec3_t mins,vec3_t maxs,vec3_t angles,vec3_t tmins,vec3_t tmaxs)710 void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
711 {
712 vec3_t tmp, v;
713 int i, j;
714 vec3_t forward, right, up;
715
716 if (!angles[0] && !angles[1] && !angles[2])
717 {
718 VectorCopy (mins, tmins);
719 VectorCopy (maxs, tmaxs);
720 return;
721 }
722
723 for (i=0 ; i<3 ; i++)
724 {
725 tmins[i] = 99999;
726 tmaxs[i] = -99999;
727 }
728
729 AngleVectors (angles, forward, right, up);
730
731 for ( i = 0; i < 8; i++ )
732 {
733 if ( i & 1 )
734 tmp[0] = mins[0];
735 else
736 tmp[0] = maxs[0];
737
738 if ( i & 2 )
739 tmp[1] = mins[1];
740 else
741 tmp[1] = maxs[1];
742
743 if ( i & 4 )
744 tmp[2] = mins[2];
745 else
746 tmp[2] = maxs[2];
747
748
749 VectorScale (forward, tmp[0], v);
750 VectorMA (v, -tmp[1], right, v);
751 VectorMA (v, tmp[2], up, v);
752
753 for (j=0 ; j<3 ; j++)
754 {
755 if (v[j] < tmins[j])
756 tmins[j] = v[j];
757 if (v[j] > tmaxs[j])
758 tmaxs[j] = v[j];
759 }
760 }
761 }
762
763 /*
764 =============
765 R_DrawBEntitiesOnList
766 =============
767 */
R_DrawBEntitiesOnList(void)768 void R_DrawBEntitiesOnList (void)
769 {
770 int i, clipflags;
771 vec3_t oldorigin;
772 vec3_t mins, maxs;
773 float minmaxs[6];
774 mnode_t *topnode;
775
776 if (!r_drawentities->value)
777 return;
778
779 VectorCopy (modelorg, oldorigin);
780 insubmodel = true;
781 r_dlightframecount = r_framecount;
782
783 for (i=0 ; i<r_newrefdef.num_entities ; i++)
784 {
785 currententity = &r_newrefdef.entities[i];
786 currentmodel = currententity->model;
787 if (!currentmodel)
788 continue;
789 if (currentmodel->nummodelsurfaces == 0)
790 continue; // clip brush only
791 if ( currententity->flags & RF_BEAM )
792 continue;
793 if (currentmodel->type != mod_brush)
794 continue;
795 // see if the bounding box lets us trivially reject, also sets
796 // trivial accept status
797 RotatedBBox (currentmodel->mins, currentmodel->maxs,
798 currententity->angles, mins, maxs);
799 VectorAdd (mins, currententity->origin, minmaxs);
800 VectorAdd (maxs, currententity->origin, (minmaxs+3));
801
802 clipflags = R_BmodelCheckBBox (minmaxs);
803 if (clipflags == BMODEL_FULLY_CLIPPED)
804 continue; // off the edge of the screen
805
806 topnode = R_FindTopnode (minmaxs, minmaxs+3);
807 if (!topnode)
808 continue; // no part in a visible leaf
809
810 VectorCopy (currententity->origin, r_entorigin);
811 VectorSubtract (r_origin, r_entorigin, modelorg);
812
813 r_pcurrentvertbase = currentmodel->vertexes;
814
815 // FIXME: stop transforming twice
816 R_RotateBmodel ();
817
818 // calculate dynamic lighting for bmodel
819 R_PushDlights (currentmodel);
820
821 if (topnode->contents == CONTENTS_NODE)
822 {
823 // not a leaf; has to be clipped to the world BSP
824 r_clipflags = clipflags;
825 R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
826 }
827 else
828 {
829 // falls entirely in one leaf, so we just put all the
830 // edges in the edge list and let 1/z sorting handle
831 // drawing order
832 R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
833 }
834
835 // put back world rotation and frustum clipping
836 // FIXME: R_RotateBmodel should just work off base_vxx
837 VectorCopy (base_vpn, vpn);
838 VectorCopy (base_vup, vup);
839 VectorCopy (base_vright, vright);
840 VectorCopy (oldorigin, modelorg);
841 R_TransformFrustum ();
842 }
843
844 insubmodel = false;
845 }
846
847
848 /*
849 ================
850 R_EdgeDrawing
851 ================
852 */
R_EdgeDrawing(void)853 void R_EdgeDrawing (void)
854 {
855 edge_t ledges[NUMSTACKEDGES +
856 ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
857 surf_t lsurfs[NUMSTACKSURFACES +
858 ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
859
860 if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
861 return;
862
863 if (auxedges)
864 {
865 r_edges = auxedges;
866 }
867 else
868 {
869 r_edges = (edge_t *)
870 (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
871 }
872
873 if (r_surfsonstack)
874 {
875 surfaces = (surf_t *)
876 (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
877 surf_max = &surfaces[r_cnumsurfs];
878 // surface 0 doesn't really exist; it's just a dummy because index 0
879 // is used to indicate no edge attached to surface
880 surfaces--;
881 R_SurfacePatch ();
882 }
883
884 R_BeginEdgeFrame ();
885
886 if (r_dspeeds->value)
887 {
888 rw_time1 = Sys_Milliseconds ();
889 }
890
891 R_RenderWorld ();
892
893 if (r_dspeeds->value)
894 {
895 rw_time2 = Sys_Milliseconds ();
896 db_time1 = rw_time2;
897 }
898
899 R_DrawBEntitiesOnList ();
900
901 if (r_dspeeds->value)
902 {
903 db_time2 = Sys_Milliseconds ();
904 se_time1 = db_time2;
905 }
906
907 R_ScanEdges ();
908 }
909
910 //=======================================================================
911
912
913 /*
914 =============
915 R_CalcPalette
916
917 =============
918 */
R_CalcPalette(void)919 void R_CalcPalette (void)
920 {
921 static qboolean modified;
922 byte palette[256][4], *in, *out;
923 int i, j;
924 float alpha, one_minus_alpha;
925 vec3_t premult;
926 int v;
927
928 alpha = r_newrefdef.blend[3];
929 if (alpha <= 0)
930 {
931 if (modified)
932 { // set back to default
933 modified = false;
934 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
935 return;
936 }
937 return;
938 }
939
940 modified = true;
941 if (alpha > 1)
942 alpha = 1;
943
944 premult[0] = r_newrefdef.blend[0]*alpha*255;
945 premult[1] = r_newrefdef.blend[1]*alpha*255;
946 premult[2] = r_newrefdef.blend[2]*alpha*255;
947
948 one_minus_alpha = (1.0 - alpha);
949
950 in = (byte *)d_8to24table;
951 out = palette[0];
952 for (i=0 ; i<256 ; i++, in+=4, out+=4)
953 {
954 for (j=0 ; j<3 ; j++)
955 {
956 v = premult[j] + one_minus_alpha * in[j];
957 if (v > 255)
958 v = 255;
959 out[j] = v;
960 }
961 out[3] = 255;
962 }
963
964 R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
965 // SWimp_SetPalette( palette[0] );
966 }
967
968 //=======================================================================
969
R_SetLightLevel(void)970 void R_SetLightLevel (void)
971 {
972 vec3_t light;
973
974 if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
975 {
976 r_lightlevel->value = 150.0;
977 return;
978 }
979
980 // save off light value for server to look at (BIG HACK!)
981 R_LightPoint (r_newrefdef.vieworg, light);
982 r_lightlevel->value = 150.0 * light[0];
983 }
984
985
986 /*
987 @@@@@@@@@@@@@@@@
988 R_RenderFrame
989
990 @@@@@@@@@@@@@@@@
991 */
R_RenderFrame(refdef_t * fd)992 void R_RenderFrame (refdef_t *fd)
993 {
994 r_newrefdef = *fd;
995
996 if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
997 ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
998
999 VectorCopy (fd->vieworg, r_refdef.vieworg);
1000 VectorCopy (fd->viewangles, r_refdef.viewangles);
1001
1002 if (r_speeds->value || r_dspeeds->value)
1003 r_time1 = Sys_Milliseconds ();
1004
1005 R_SetupFrame ();
1006
1007 R_MarkLeaves (); // done here so we know if we're in water
1008
1009 R_PushDlights (r_worldmodel);
1010
1011 R_EdgeDrawing ();
1012
1013 if (r_dspeeds->value)
1014 {
1015 se_time2 = Sys_Milliseconds ();
1016 de_time1 = se_time2;
1017 }
1018
1019 R_DrawEntitiesOnList ();
1020
1021 if (r_dspeeds->value)
1022 {
1023 de_time2 = Sys_Milliseconds ();
1024 dp_time1 = Sys_Milliseconds ();
1025 }
1026
1027 R_DrawParticles ();
1028
1029 if (r_dspeeds->value)
1030 dp_time2 = Sys_Milliseconds ();
1031
1032 R_DrawAlphaSurfaces();
1033
1034 R_SetLightLevel ();
1035
1036 if (r_dowarp)
1037 D_WarpScreen ();
1038
1039 if (r_dspeeds->value)
1040 da_time1 = Sys_Milliseconds ();
1041
1042 if (r_dspeeds->value)
1043 da_time2 = Sys_Milliseconds ();
1044
1045 R_CalcPalette ();
1046
1047 if (sw_aliasstats->value)
1048 R_PrintAliasStats ();
1049
1050 if (r_speeds->value)
1051 R_PrintTimes ();
1052
1053 if (r_dspeeds->value)
1054 R_PrintDSpeeds ();
1055
1056 if (sw_reportsurfout->value && r_outofsurfaces)
1057 ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
1058
1059 if (sw_reportedgeout->value && r_outofedges)
1060 ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
1061 }
1062
1063 /*
1064 ** R_InitGraphics
1065 */
R_InitGraphics(int width,int height)1066 void R_InitGraphics( int width, int height )
1067 {
1068 vid.width = width;
1069 vid.height = height;
1070
1071 // free z buffer
1072 if ( d_pzbuffer )
1073 {
1074 free( d_pzbuffer );
1075 d_pzbuffer = NULL;
1076 }
1077
1078 // free surface cache
1079 if ( sc_base )
1080 {
1081 D_FlushCaches ();
1082 free( sc_base );
1083 sc_base = NULL;
1084 }
1085
1086 d_pzbuffer = malloc(vid.width*vid.height*2);
1087
1088 R_InitCaches ();
1089
1090 R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
1091 }
1092
1093 #ifdef REDBLUE
1094 void SetStereoBuffer(int buf);
1095 #endif
1096 /*
1097 ** R_BeginFrame
1098 */
R_BeginFrame(float camera_separation)1099 void R_BeginFrame( float camera_separation )
1100 {
1101 extern void Draw_BuildGammaTable( void );
1102 #ifdef REDBLUE
1103 SetStereoBuffer((camera_separation <= 0.0) ? 0 : 1);
1104 #endif
1105 /*
1106 ** rebuild the gamma correction palette if necessary
1107 */
1108 if ( vid_gamma->modified )
1109 {
1110 Draw_BuildGammaTable();
1111 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
1112
1113 vid_gamma->modified = false;
1114 }
1115
1116 while ( sw_mode->modified || vid_fullscreen->modified )
1117 {
1118 rserr_t err;
1119
1120 /*
1121 ** if this returns rserr_invalid_fullscreen then it set the mode but not as a
1122 ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
1123 */
1124 if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
1125 {
1126 R_InitGraphics( vid.width, vid.height );
1127
1128 sw_state.prev_mode = sw_mode->value;
1129 vid_fullscreen->modified = false;
1130 sw_mode->modified = false;
1131 }
1132 else
1133 {
1134 if ( err == rserr_invalid_mode )
1135 {
1136 ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
1137 ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
1138 }
1139 else if ( err == rserr_invalid_fullscreen )
1140 {
1141 R_InitGraphics( vid.width, vid.height );
1142
1143 ri.Cvar_SetValue( "vid_fullscreen", 0);
1144 ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
1145 sw_state.prev_mode = sw_mode->value;
1146 // vid_fullscreen->modified = false;
1147 // sw_mode->modified = false;
1148 }
1149 else
1150 {
1151 ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
1152 }
1153 }
1154 }
1155 }
1156
1157 /*
1158 ** R_GammaCorrectAndSetPalette
1159 */
R_GammaCorrectAndSetPalette(const unsigned char * palette)1160 void R_GammaCorrectAndSetPalette( const unsigned char *palette )
1161 {
1162 int i;
1163
1164 for ( i = 0; i < 256; i++ )
1165 {
1166 sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
1167 sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
1168 sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
1169 }
1170
1171 SWimp_SetPalette( sw_state.currentpalette );
1172 }
1173
1174 /*
1175 ** R_CinematicSetPalette
1176 */
R_CinematicSetPalette(const unsigned char * palette)1177 void R_CinematicSetPalette( const unsigned char *palette )
1178 {
1179 byte palette32[1024];
1180 int i, j, w;
1181 int *d;
1182
1183 // clear screen to black to avoid any palette flash
1184 w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff...
1185 for (i=0 ; i<vid.height ; i++, d+=w)
1186 {
1187 d = (int *)(vid.buffer + i*vid.rowbytes);
1188 for (j=0 ; j<w ; j++)
1189 d[j] = 0;
1190 }
1191 // flush it to the screen
1192 SWimp_EndFrame ();
1193
1194 if ( palette )
1195 {
1196 for ( i = 0; i < 256; i++ )
1197 {
1198 palette32[i*4+0] = palette[i*3+0];
1199 palette32[i*4+1] = palette[i*3+1];
1200 palette32[i*4+2] = palette[i*3+2];
1201 palette32[i*4+3] = 0xFF;
1202 }
1203
1204 R_GammaCorrectAndSetPalette( palette32 );
1205 }
1206 else
1207 {
1208 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
1209 }
1210 }
1211
1212 /*
1213 ================
1214 Draw_BuildGammaTable
1215 ================
1216 */
Draw_BuildGammaTable(void)1217 void Draw_BuildGammaTable (void)
1218 {
1219 int i, inf;
1220 float g;
1221
1222 g = vid_gamma->value;
1223
1224 if (g == 1.0)
1225 {
1226 for (i=0 ; i<256 ; i++)
1227 sw_state.gammatable[i] = i;
1228 return;
1229 }
1230
1231 for (i=0 ; i<256 ; i++)
1232 {
1233 inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
1234 if (inf < 0)
1235 inf = 0;
1236 if (inf > 255)
1237 inf = 255;
1238 sw_state.gammatable[i] = inf;
1239 }
1240 }
1241
1242 /*
1243 ** R_DrawBeam
1244 */
R_DrawBeam(entity_t * e)1245 void R_DrawBeam( entity_t *e )
1246 {
1247 #define NUM_BEAM_SEGS 6
1248
1249 int i;
1250
1251 vec3_t perpvec;
1252 vec3_t direction, normalized_direction;
1253 vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
1254 vec3_t oldorigin, origin;
1255
1256 oldorigin[0] = e->oldorigin[0];
1257 oldorigin[1] = e->oldorigin[1];
1258 oldorigin[2] = e->oldorigin[2];
1259
1260 origin[0] = e->origin[0];
1261 origin[1] = e->origin[1];
1262 origin[2] = e->origin[2];
1263
1264 normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
1265 normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
1266 normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
1267
1268 if ( VectorNormalize( normalized_direction ) == 0 )
1269 return;
1270
1271 PerpendicularVector( perpvec, normalized_direction );
1272 VectorScale( perpvec, e->frame / 2, perpvec );
1273
1274 for ( i = 0; i < NUM_BEAM_SEGS; i++ )
1275 {
1276 RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
1277 VectorAdd( start_points[i], origin, start_points[i] );
1278 VectorAdd( start_points[i], direction, end_points[i] );
1279 }
1280
1281 for ( i = 0; i < NUM_BEAM_SEGS; i++ )
1282 {
1283 R_IMFlatShadedQuad( start_points[i],
1284 end_points[i],
1285 end_points[(i+1)%NUM_BEAM_SEGS],
1286 start_points[(i+1)%NUM_BEAM_SEGS],
1287 e->skinnum & 0xFF,
1288 e->alpha );
1289 }
1290 }
1291
1292
1293 //===================================================================
1294
1295 /*
1296 ============
1297 R_SetSky
1298 ============
1299 */
1300 // 3dstudio environment map names
1301 char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
1302 int r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
1303 extern mtexinfo_t r_skytexinfo[6];
R_SetSky(char * name,float rotate,vec3_t axis)1304 void R_SetSky (char *name, float rotate, vec3_t axis)
1305 {
1306 int i;
1307 char pathname[MAX_QPATH];
1308
1309 strncpy (skyname, name, sizeof(skyname)-1);
1310 skyrotate = rotate;
1311 VectorCopy (axis, skyaxis);
1312
1313 for (i=0 ; i<6 ; i++)
1314 {
1315 Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
1316 r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
1317 }
1318 }
1319
1320
1321 /*
1322 ===============
1323 Draw_GetPalette
1324 ===============
1325 */
Draw_GetPalette(void)1326 void Draw_GetPalette (void)
1327 {
1328 byte *pal, *out;
1329 int i;
1330 int r, g, b;
1331
1332 // get the palette and colormap
1333 LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
1334 if (!vid.colormap)
1335 ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
1336 vid.alphamap = vid.colormap + 64*256;
1337
1338 out = (byte *)d_8to24table;
1339 for (i=0 ; i<256 ; i++, out+=4)
1340 {
1341 r = pal[i*3+0];
1342 g = pal[i*3+1];
1343 b = pal[i*3+2];
1344
1345 out[0] = r;
1346 out[1] = g;
1347 out[2] = b;
1348 }
1349
1350 free (pal);
1351 }
1352
1353 struct image_s *R_RegisterSkin (char *name);
1354
1355 /*
1356 @@@@@@@@@@@@@@@@@@@@@
1357 GetRefAPI
1358
1359 @@@@@@@@@@@@@@@@@@@@@
1360 */
GetRefAPI(refimport_t rimp)1361 refexport_t GetRefAPI (refimport_t rimp)
1362 {
1363 refexport_t re;
1364
1365 ri = rimp;
1366
1367 re.api_version = API_VERSION;
1368
1369 re.BeginRegistration = R_BeginRegistration;
1370 re.RegisterModel = R_RegisterModel;
1371 re.RegisterSkin = R_RegisterSkin;
1372 re.RegisterPic = Draw_FindPic;
1373 re.SetSky = R_SetSky;
1374 re.EndRegistration = R_EndRegistration;
1375
1376 re.RenderFrame = R_RenderFrame;
1377
1378 re.DrawGetPicSize = Draw_GetPicSize;
1379
1380
1381 #ifdef QMAX
1382 re.DrawScaledPic = Draw_ScaledPic;
1383 re.AddStain = R_AddStain;
1384 #endif
1385
1386 re.DrawPic = Draw_Pic;
1387 re.DrawStretchPic = Draw_StretchPic;
1388 re.DrawChar = Draw_Char;
1389 re.DrawTileClear = Draw_TileClear;
1390 re.DrawFill = Draw_Fill;
1391 re.DrawFadeScreen= Draw_FadeScreen;
1392
1393 re.DrawStretchRaw = Draw_StretchRaw;
1394
1395 re.Init = R_Init;
1396 re.Shutdown = R_Shutdown;
1397
1398 re.CinematicSetPalette = R_CinematicSetPalette;
1399 re.BeginFrame = R_BeginFrame;
1400 re.EndFrame = SWimp_EndFrame;
1401
1402 re.AppActivate = SWimp_AppActivate;
1403
1404 Swap_Init ();
1405
1406 return re;
1407 }
1408
1409 #ifndef REF_HARD_LINKED
1410 // this is only here so the functions in q_shared.c and q_shwin.c can link
Sys_Error(char * error,...)1411 void Sys_Error (char *error, ...)
1412 {
1413 va_list argptr;
1414 char text[1024];
1415
1416 va_start (argptr, error);
1417 vsprintf (text, error, argptr);
1418 va_end (argptr);
1419
1420 ri.Sys_Error (ERR_FATAL, "%s", text);
1421 }
1422
Com_Printf(char * fmt,...)1423 void Com_Printf (char *fmt, ...)
1424 {
1425 va_list argptr;
1426 char text[1024];
1427
1428 va_start (argptr, fmt);
1429 vsprintf (text, fmt, argptr);
1430 va_end (argptr);
1431
1432 ri.Con_Printf (PRINT_ALL, "%s", text);
1433 }
1434
1435 #endif
1436
1437 #ifdef QMAX
R_AddStain(vec3_t org,float intensity,float r,float g,float b)1438 void R_AddStain (vec3_t org, float intensity, float r, float g, float b) {
1439 }
1440
Draw_ScaledPic(int x,int y,float scale,float alpha,char * pic)1441 void Draw_ScaledPic (int x, int y, float scale, float alpha, char *pic) {
1442 }
1443 #endif
1444