]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
added cvars r_lerpsprites, r_lerpmodels, and r_waterscroll (and to menu as well)
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 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 "quakedef.h"
23
24 // used for dlight push checking and other things
25 int r_framecount;
26
27 mplane_t frustum[4];
28
29 matrix4x4_t r_identitymatrix;
30
31 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
32
33 // true during envmap command capture
34 qboolean envmap;
35
36 float r_farclip;
37
38 // view origin
39 vec3_t r_origin;
40 vec3_t vpn;
41 vec3_t vright;
42 vec3_t vup;
43
44 //
45 // screen size info
46 //
47 refdef_t r_refdef;
48
49 // 8.8 fraction of base light value
50 unsigned short d_lightstylevalue[256];
51
52 cvar_t r_drawentities = {0, "r_drawentities","1"};
53 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
54 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0"};
55 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
56 cvar_t r_speeds = {0, "r_speeds","0"};
57 cvar_t r_fullbright = {0, "r_fullbright","0"};
58 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
59 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
60 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
61 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
62
63 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
64 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
65 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
66 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
67 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
68 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
69 cvar_t gl_fogend = {0, "gl_fogend","0"};
70
71 cvar_t r_textureunits = {0, "r_textureunits", "32"};
72
73 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
74 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
75 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
76
77
78
79 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
80 {
81         int i;
82         for (i = 0;i < verts;i++)
83         {
84                 out[0] = in[0] * r;
85                 out[1] = in[1] * g;
86                 out[2] = in[2] * b;
87                 out[3] = in[3];
88                 in += 4;
89                 out += 4;
90         }
91 }
92
93 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
94 {
95         int i;
96         for (i = 0;i < verts;i++)
97         {
98                 out[0] = r;
99                 out[1] = g;
100                 out[2] = b;
101                 out[3] = a;
102                 out += 4;
103         }
104 }
105
106 /*
107 ====================
108 R_TimeRefresh_f
109
110 For program optimization
111 ====================
112 */
113 qboolean intimerefresh = 0;
114 static void R_TimeRefresh_f (void)
115 {
116         int i;
117         float start, stop, time;
118
119         intimerefresh = 1;
120         start = Sys_DoubleTime ();
121         for (i = 0;i < 128;i++)
122         {
123                 r_refdef.viewangles[0] = 0;
124                 r_refdef.viewangles[1] = i/128.0*360.0;
125                 r_refdef.viewangles[2] = 0;
126                 CL_UpdateScreen();
127         }
128
129         stop = Sys_DoubleTime ();
130         intimerefresh = 0;
131         time = stop-start;
132         Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
133 }
134
135 vec3_t fogcolor;
136 vec_t fogdensity;
137 float fog_density, fog_red, fog_green, fog_blue;
138 qboolean fogenabled;
139 qboolean oldgl_fogenable;
140 void R_SetupFog(void)
141 {
142         if (gamemode == GAME_NEHAHRA)
143         {
144                 if (gl_fogenable.integer)
145                 {
146                         oldgl_fogenable = true;
147                         fog_density = gl_fogdensity.value;
148                         fog_red = gl_fogred.value;
149                         fog_green = gl_foggreen.value;
150                         fog_blue = gl_fogblue.value;
151                 }
152                 else if (oldgl_fogenable)
153                 {
154                         oldgl_fogenable = false;
155                         fog_density = 0;
156                         fog_red = 0;
157                         fog_green = 0;
158                         fog_blue = 0;
159                 }
160         }
161         if (fog_density)
162         {
163                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
164                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
165                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
166         }
167         if (fog_density)
168         {
169                 fogenabled = true;
170                 fogdensity = -4000.0f / (fog_density * fog_density);
171                 // fog color was already set
172         }
173         else
174                 fogenabled = false;
175 }
176
177 // FIXME: move this to client?
178 void FOG_clear(void)
179 {
180         if (gamemode == GAME_NEHAHRA)
181         {
182                 Cvar_Set("gl_fogenable", "0");
183                 Cvar_Set("gl_fogdensity", "0.2");
184                 Cvar_Set("gl_fogred", "0.3");
185                 Cvar_Set("gl_foggreen", "0.3");
186                 Cvar_Set("gl_fogblue", "0.3");
187         }
188         fog_density = fog_red = fog_green = fog_blue = 0.0f;
189 }
190
191 // FIXME: move this to client?
192 void FOG_registercvars(void)
193 {
194         if (gamemode == GAME_NEHAHRA)
195         {
196                 Cvar_RegisterVariable (&gl_fogenable);
197                 Cvar_RegisterVariable (&gl_fogdensity);
198                 Cvar_RegisterVariable (&gl_fogred);
199                 Cvar_RegisterVariable (&gl_foggreen);
200                 Cvar_RegisterVariable (&gl_fogblue);
201                 Cvar_RegisterVariable (&gl_fogstart);
202                 Cvar_RegisterVariable (&gl_fogend);
203         }
204 }
205
206 void gl_main_start(void)
207 {
208 }
209
210 void gl_main_shutdown(void)
211 {
212 }
213
214 extern void CL_ParseEntityLump(char *entitystring);
215 void gl_main_newmap(void)
216 {
217         if (cl.worldmodel && cl.worldmodel->entities)
218                 CL_ParseEntityLump(cl.worldmodel->entities);
219         r_framecount = 1;
220 }
221
222 void GL_Main_Init(void)
223 {
224         Matrix4x4_CreateIdentity(&r_identitymatrix);
225 // FIXME: move this to client?
226         FOG_registercvars();
227         Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
228         Cvar_RegisterVariable (&r_drawentities);
229         Cvar_RegisterVariable (&r_drawviewmodel);
230         Cvar_RegisterVariable (&r_shadows);
231         Cvar_RegisterVariable (&r_shadow_staticworldlights);
232         Cvar_RegisterVariable (&r_speeds);
233         Cvar_RegisterVariable (&r_fullbrights);
234         Cvar_RegisterVariable (&r_wateralpha);
235         Cvar_RegisterVariable (&r_dynamic);
236         Cvar_RegisterVariable (&r_fullbright);
237         Cvar_RegisterVariable (&r_textureunits);
238         Cvar_RegisterVariable (&r_shadow_cull);
239         Cvar_RegisterVariable (&r_lerpsprites);
240         Cvar_RegisterVariable (&r_lerpmodels);
241         Cvar_RegisterVariable (&r_waterscroll);
242         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
243                 Cvar_SetValue("r_fullbrights", 0);
244         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
245 }
246
247 vec3_t r_farclip_origin;
248 vec3_t r_farclip_direction;
249 vec_t r_farclip_directiondist;
250 vec_t r_farclip_meshfarclip;
251 int r_farclip_directionbit0;
252 int r_farclip_directionbit1;
253 int r_farclip_directionbit2;
254
255 // start a farclip measuring session
256 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
257 {
258         VectorCopy(origin, r_farclip_origin);
259         VectorCopy(direction, r_farclip_direction);
260         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
261         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
262         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
263         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
264         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
265 }
266
267 // enlarge farclip to accomodate box
268 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
269 {
270         float d;
271         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
272           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
273           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
274         if (r_farclip_meshfarclip < d)
275                 r_farclip_meshfarclip = d;
276 }
277
278 // return farclip value
279 float R_FarClip_Finish(void)
280 {
281         return r_farclip_meshfarclip - r_farclip_directiondist;
282 }
283
284 extern void R_Textures_Init(void);
285 extern void Mod_RenderInit(void);
286 extern void GL_Draw_Init(void);
287 extern void GL_Main_Init(void);
288 extern void R_Shadow_Init(void);
289 extern void GL_Models_Init(void);
290 extern void R_Sky_Init(void);
291 extern void GL_Surf_Init(void);
292 extern void R_Crosshairs_Init(void);
293 extern void R_Light_Init(void);
294 extern void R_Particles_Init(void);
295 extern void R_Explosion_Init(void);
296 extern void ui_init(void);
297 extern void gl_backend_init(void);
298 extern void Sbar_Init(void);
299
300 void Render_Init(void)
301 {
302         R_Textures_Init();
303         Mod_RenderInit();
304         gl_backend_init();
305         R_MeshQueue_Init();
306         GL_Draw_Init();
307         GL_Main_Init();
308         R_Shadow_Init();
309         GL_Models_Init();
310         R_Sky_Init();
311         GL_Surf_Init();
312         R_Crosshairs_Init();
313         R_Light_Init();
314         R_Particles_Init();
315         R_Explosion_Init();
316         ui_init();
317         Sbar_Init();
318 }
319
320 /*
321 ===============
322 GL_Init
323 ===============
324 */
325 extern char *ENGINE_EXTENSIONS;
326 void GL_Init (void)
327 {
328         VID_CheckExtensions();
329
330         // LordHavoc: report supported extensions
331         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
332 }
333
334 int R_CullBox(const vec3_t mins, const vec3_t maxs)
335 {
336         int i;
337         mplane_t *p;
338         for (i = 0;i < 4;i++)
339         {
340                 p = frustum + i;
341                 switch(p->signbits)
342                 {
343                 default:
344                 case 0:
345                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
346                                 return true;
347                         break;
348                 case 1:
349                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
350                                 return true;
351                         break;
352                 case 2:
353                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
354                                 return true;
355                         break;
356                 case 3:
357                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
358                                 return true;
359                         break;
360                 case 4:
361                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
362                                 return true;
363                         break;
364                 case 5:
365                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
366                                 return true;
367                         break;
368                 case 6:
369                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
370                                 return true;
371                         break;
372                 case 7:
373                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
374                                 return true;
375                         break;
376                 }
377         }
378         return false;
379 }
380
381 int PVS_CullBox(const vec3_t mins, const vec3_t maxs)
382 {
383         int stackpos, sides;
384         mnode_t *node, *stack[4096];
385         if (cl.worldmodel == NULL)
386                 return false;
387         stackpos = 0;
388         stack[stackpos++] = cl.worldmodel->nodes;
389         while (stackpos)
390         {
391                 node = stack[--stackpos];
392                 if (node->contents < 0)
393                 {
394                         if (((mleaf_t *)node)->pvsframe == cl.worldmodel->pvsframecount)
395                                 return false;
396                 }
397                 else
398                 {
399                         sides = BoxOnPlaneSide(mins, maxs, node->plane);
400                         if (sides & 2 && stackpos < 4096)
401                                 stack[stackpos++] = node->children[1];
402                         if (sides & 1 && stackpos < 4096)
403                                 stack[stackpos++] = node->children[0];
404                 }
405         }
406         return true;
407 }
408
409 int VIS_CullBox(const vec3_t mins, const vec3_t maxs)
410 {
411         int stackpos, sides;
412         mnode_t *node, *stack[4096];
413         if (R_CullBox(mins, maxs))
414                 return true;
415         if (cl.worldmodel == NULL)
416                 return false;
417         stackpos = 0;
418         stack[stackpos++] = cl.worldmodel->nodes;
419         while (stackpos)
420         {
421                 node = stack[--stackpos];
422                 if (node->contents < 0)
423                 {
424                         if (((mleaf_t *)node)->visframe == r_framecount)
425                                 return false;
426                 }
427                 else
428                 {
429                         sides = BoxOnPlaneSide(mins, maxs, node->plane);
430                         if (sides & 2 && stackpos < 4096)
431                                 stack[stackpos++] = node->children[1];
432                         if (sides & 1 && stackpos < 4096)
433                                 stack[stackpos++] = node->children[0];
434                 }
435         }
436         return true;
437 }
438
439 int R_CullSphere(const vec3_t origin, vec_t radius)
440 {
441         return (DotProduct(frustum[0].normal, origin) + radius < frustum[0].dist
442              || DotProduct(frustum[1].normal, origin) + radius < frustum[1].dist
443              || DotProduct(frustum[2].normal, origin) + radius < frustum[2].dist
444              || DotProduct(frustum[3].normal, origin) + radius < frustum[3].dist);
445 }
446
447 int PVS_CullSphere(const vec3_t origin, vec_t radius)
448 {
449         int stackpos;
450         mnode_t *node, *stack[4096];
451         float dist;
452         if (cl.worldmodel == NULL)
453                 return false;
454         stackpos = 0;
455         stack[stackpos++] = cl.worldmodel->nodes;
456         while (stackpos)
457         {
458                 node = stack[--stackpos];
459                 if (node->contents < 0)
460                 {
461                         if (((mleaf_t *)node)->pvsframe == cl.worldmodel->pvsframecount)
462                                 return false;
463                 }
464                 else
465                 {
466                         dist = PlaneDiff(origin, node->plane);
467                         if (dist <= radius)
468                                 stack[stackpos++] = node->children[1];
469                         if (dist >= -radius)
470                                 stack[stackpos++] = node->children[0];
471                 }
472         }
473         return true;
474 }
475
476 int VIS_CullSphere(const vec3_t origin, vec_t radius)
477 {
478         int stackpos;
479         mnode_t *node, *stack[4096];
480         float dist;
481         if (R_CullSphere(origin, radius))
482                 return true;
483         if (cl.worldmodel == NULL)
484                 return false;
485         stackpos = 0;
486         stack[stackpos++] = cl.worldmodel->nodes;
487         while (stackpos)
488         {
489                 node = stack[--stackpos];
490                 if (node->contents < 0)
491                 {
492                         if (((mleaf_t *)node)->visframe == r_framecount)
493                                 return false;
494                 }
495                 else
496                 {
497                         dist = PlaneDiff(origin, node->plane);
498                         if (dist <= radius)
499                                 stack[stackpos++] = node->children[1];
500                         if (dist >= -radius)
501                                 stack[stackpos++] = node->children[0];
502                 }
503         }
504         return true;
505 }
506
507
508 //==================================================================================
509
510 static void R_MarkEntities (void)
511 {
512         int i;
513         entity_render_t *ent;
514
515         ent = &cl_entities[0].render;
516         Matrix4x4_CreateIdentity(&ent->matrix);
517         Matrix4x4_CreateIdentity(&ent->inversematrix);
518
519         if (cl.worldmodel)
520                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
521
522         if (!r_drawentities.integer)
523                 return;
524
525         for (i = 0;i < r_refdef.numentities;i++)
526         {
527                 ent = r_refdef.entities[i];
528                 Mod_CheckLoaded(ent->model);
529                 // some of the renderer still relies on origin...
530                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
531                 // some of the renderer still relies on scale...
532                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
533                 R_LerpAnimation(ent);
534                 R_UpdateEntLights(ent);
535                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
536                  && !VIS_CullSphere(ent->origin, (ent->model != NULL ? ent->model->radius : 16) * ent->scale)
537                  && !VIS_CullBox(ent->mins, ent->maxs))
538                 {
539                         ent->visframe = r_framecount;
540                         R_FarClip_Box(ent->mins, ent->maxs);
541                 }
542         }
543 }
544
545 // only used if skyrendermasked, and normally returns false
546 int R_DrawBrushModelsSky (void)
547 {
548         int i, sky;
549         entity_render_t *ent;
550
551         if (!r_drawentities.integer)
552                 return false;
553
554         sky = false;
555         for (i = 0;i < r_refdef.numentities;i++)
556         {
557                 ent = r_refdef.entities[i];
558                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
559                 {
560                         ent->model->DrawSky(ent);
561                         sky = true;
562                 }
563         }
564         return sky;
565 }
566
567 /*
568 =============
569 R_DrawViewModel
570 =============
571 */
572 /*
573 void R_DrawViewModel (void)
574 {
575         entity_render_t *ent;
576
577         // FIXME: move these checks to client
578         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
579                 return;
580
581         ent = &cl.viewent.render;
582         Mod_CheckLoaded(ent->model);
583         R_LerpAnimation(ent);
584         Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
585         Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
586         R_UpdateEntLights(ent);
587         ent->model->Draw(ent);
588 }
589 */
590
591 void R_DrawNoModel(entity_render_t *ent);
592 void R_DrawModels ()
593 {
594         int i;
595         entity_render_t *ent;
596
597         if (!r_drawentities.integer)
598                 return;
599
600         for (i = 0;i < r_refdef.numentities;i++)
601         {
602                 ent = r_refdef.entities[i];
603                 if (ent->visframe == r_framecount)
604                 {
605                         if (ent->model && ent->model->Draw != NULL)
606                                 ent->model->Draw(ent);
607                         else
608                                 R_DrawNoModel(ent);
609                 }
610         }
611 }
612
613 void R_DrawFakeShadows (void)
614 {
615         int i;
616         entity_render_t *ent;
617
618         ent = &cl_entities[0].render;
619         if (ent->model && ent->model->DrawFakeShadow)
620                 ent->model->DrawFakeShadow(ent);
621
622         if (!r_drawentities.integer)
623                 return;
624         for (i = 0;i < r_refdef.numentities;i++)
625         {
626                 ent = r_refdef.entities[i];
627                 if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawFakeShadow)
628                         ent->model->DrawFakeShadow(ent);
629         }
630 }
631
632 #include "r_shadow.h"
633
634 int shadowframecount = 0;
635
636 int Light_CullBox(const vec3_t mins, const vec3_t maxs)
637 {
638         int stackpos, sides;
639         mnode_t *node, *stack[4096];
640         if (cl.worldmodel == NULL)
641                 return false;
642         stackpos = 0;
643         stack[stackpos++] = cl.worldmodel->nodes;
644         while (stackpos)
645         {
646                 node = stack[--stackpos];
647                 if (node->contents < 0)
648                 {
649                         if (((mleaf_t *)node)->worldnodeframe == shadowframecount)
650                                 return false;
651                 }
652                 else
653                 {
654                         sides = BoxOnPlaneSide(mins, maxs, node->plane);
655                         if (sides & 2 && stackpos < 4096)
656                                 stack[stackpos++] = node->children[1];
657                         if (sides & 1 && stackpos < 4096)
658                                 stack[stackpos++] = node->children[0];
659                 }
660         }
661         return true;
662 }
663
664 int LightAndVis_CullBox(const vec3_t mins, const vec3_t maxs)
665 {
666         int stackpos, sides;
667         mnode_t *node, *stack[4096];
668         if (R_CullBox(mins, maxs))
669                 return true;
670         if (cl.worldmodel == NULL)
671                 return false;
672         stackpos = 0;
673         stack[stackpos++] = cl.worldmodel->nodes;
674         while (stackpos)
675         {
676                 node = stack[--stackpos];
677                 if (node->contents < 0)
678                 {
679                         if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount)
680                                 return false;
681                 }
682                 else
683                 {
684                         sides = BoxOnPlaneSide(mins, maxs, node->plane);
685                         if (sides & 2 && stackpos < 4096)
686                                 stack[stackpos++] = node->children[1];
687                         if (sides & 1 && stackpos < 4096)
688                                 stack[stackpos++] = node->children[0];
689                 }
690         }
691         return true;
692 }
693
694 int LightAndVis_CullPointCloud(int numpoints, const float *points)
695 {
696         int i;
697         const float *p;
698         int stackpos, sides;
699         mnode_t *node, *stack[4096];
700         //if (R_CullBox(mins, maxs))
701         //      return true;
702         if (cl.worldmodel == NULL)
703                 return false;
704         stackpos = 0;
705         stack[stackpos++] = cl.worldmodel->nodes;
706         while (stackpos)
707         {
708                 node = stack[--stackpos];
709                 if (node->contents < 0)
710                 {
711                         if (((mleaf_t *)node)->visframe == r_framecount && ((mleaf_t *)node)->worldnodeframe == shadowframecount)
712                                 return false;
713                 }
714                 else
715                 {
716                         sides = 0;
717                         for (i = 0, p = points;i < numpoints && sides != 3;i++, p += 3)
718                         {
719                                 if (DotProduct(p, node->plane->normal) < node->plane->dist)
720                                         sides |= 1;
721                                 else
722                                         sides |= 2;
723                         }
724                         if (sides & 2 && stackpos < 4096)
725                                 stack[stackpos++] = node->children[1];
726                         if (sides & 1 && stackpos < 4096)
727                                 stack[stackpos++] = node->children[0];
728                 }
729         }
730         return true;
731 }
732
733
734 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs, int lightmarked)
735 {
736         vec3_t relativelightorigin;
737         #if 0
738         int i;
739         vec3_t temp;
740         float dist, projectdistance;
741         float points[16][3];
742         #endif
743         // rough checks
744         if (!(ent->flags & RENDER_SHADOW) || ent->model == NULL || ent->model->DrawShadowVolume == NULL)
745                 return;
746         if (r_shadow_cull.integer)
747         {
748                 if (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0]
749                  || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1]
750                  || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2]
751                  || (lightmarked && Light_CullBox(ent->mins, ent->maxs)))
752                         return;
753         }
754         #if 0
755         if (r_shadow_cull.integer)
756         {
757                 projectdistance = cullradius;
758                 // calculate projected bounding box and decide if it is on-screen
759                 for (i = 0;i < 8;i++)
760                 {
761                         temp[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0];
762                         temp[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1];
763                         temp[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2];
764                         Matrix4x4_Transform(&ent->matrix, temp, points[i]);
765                         VectorSubtract(points[i], lightorigin, temp);
766                         dist = projectdistance / sqrt(DotProduct(temp, temp));
767                         VectorMA(lightorigin, dist, temp, points[i+8]);
768                 }
769                 if (LightAndVis_CullPointCloud(16, points[0]))
770                         return;
771                 /*
772                 for (i = 0;i < 8;i++)
773                 {
774                         p2[0] = i & 1 ? ent->model->normalmaxs[0] : ent->model->normalmins[0];
775                         p2[1] = i & 2 ? ent->model->normalmaxs[1] : ent->model->normalmins[1];
776                         p2[2] = i & 4 ? ent->model->normalmaxs[2] : ent->model->normalmins[2];
777                         Matrix4x4_Transform(&ent->matrix, p2, p);
778                         VectorSubtract(p, lightorigin, temp);
779                         dist = projectdistance / sqrt(DotProduct(temp, temp));
780                         VectorMA(p, dist, temp, p2);
781                         if (i)
782                         {
783                                 if (mins[0] > p[0]) mins[0] = p[0];if (maxs[0] < p[0]) maxs[0] = p[0];
784                                 if (mins[1] > p[1]) mins[1] = p[1];if (maxs[1] < p[1]) maxs[1] = p[1];
785                                 if (mins[2] > p[2]) mins[2] = p[2];if (maxs[2] < p[2]) maxs[2] = p[2];
786                         }
787                         else
788                         {
789                                 VectorCopy(p, mins);
790                                 VectorCopy(p, maxs);
791                         }
792                         if (mins[0] > p2[0]) mins[0] = p2[0];if (maxs[0] < p2[0]) maxs[0] = p2[0];
793                         if (mins[1] > p2[1]) mins[1] = p2[1];if (maxs[1] < p2[1]) maxs[1] = p2[1];
794                         if (mins[2] > p2[2]) mins[2] = p2[2];if (maxs[2] < p2[2]) maxs[2] = p2[2];
795                 }
796                 if (mins[0] >= clipmaxs[0] || maxs[0] <= clipmins[0]
797                  || mins[1] >= clipmaxs[1] || maxs[1] <= clipmins[1]
798                  || mins[2] >= clipmaxs[2] || maxs[2] <= clipmins[2]
799                  || LightAndVis_CullBox(mins, maxs))
800                         return;
801                 */
802         }
803         #endif
804         Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
805         ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
806 }
807
808 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
809
810 extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
811 void R_ShadowVolumeLighting (int visiblevolumes)
812 {
813         int i;
814         entity_render_t *ent;
815         int lnum;
816         float f, lightradius, cullradius;
817         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
818         worldlight_t *wl;
819         rdlight_t *rd;
820         rmeshstate_t m;
821         mleaf_t *leaf;
822         matrix4x4_t matrix;
823         matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
824         matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
825
826         if (visiblevolumes)
827         {
828                 memset(&m, 0, sizeof(m));
829                 R_Mesh_State_Texture(&m);
830
831                 GL_BlendFunc(GL_ONE, GL_ONE);
832                 GL_DepthMask(false);
833                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
834                 qglDisable(GL_CULL_FACE);
835                 GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
836         }
837         else
838                 R_Shadow_Stage_Begin();
839         shadowframecount++;
840         if (r_shadow_realtime_world.integer)
841         {
842                 R_Shadow_LoadWorldLightsIfNeeded();
843                 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
844                 {
845                         if (d_lightstylevalue[wl->style] <= 0)
846                                 continue;
847                         if (R_CullBox(wl->mins, wl->maxs))
848                         //if (R_CullSphere(wl->origin, cullradius))
849                                 continue;
850                         //if (R_CullBox(wl->mins, wl->maxs) || R_CullSphere(wl->origin, lightradius))
851                         //      continue;
852                         //if (VIS_CullBox(wl->mins, wl->maxs) || VIS_CullSphere(wl->origin, lightradius))
853                         //      continue;
854                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
855                                 continue;
856
857                         cullradius = wl->cullradius;
858                         lightradius = wl->lightradius;
859
860                         if (cl.worldmodel != NULL)
861                         {
862                                 for (i = 0;i < wl->numleafs;i++)
863                                         if (wl->leafs[i]->visframe == r_framecount)
864                                                 break;
865                                 if (i == wl->numleafs)
866                                         continue;
867                                 leaf = wl->leafs[i++];
868                                 VectorCopy(leaf->mins, clipmins);
869                                 VectorCopy(leaf->maxs, clipmaxs);
870                                 for (;i < wl->numleafs;i++)
871                                 {
872                                         leaf = wl->leafs[i];
873                                         if (leaf->visframe == r_framecount)
874                                         {
875                                                 if (clipmins[0] > leaf->mins[0]) clipmins[0] = leaf->mins[0];
876                                                 if (clipmaxs[0] < leaf->maxs[0]) clipmaxs[0] = leaf->maxs[0];
877                                                 if (clipmins[1] > leaf->mins[1]) clipmins[1] = leaf->mins[1];
878                                                 if (clipmaxs[1] < leaf->maxs[1]) clipmaxs[1] = leaf->maxs[1];
879                                                 if (clipmins[2] > leaf->mins[2]) clipmins[2] = leaf->mins[2];
880                                                 if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
881                                         }
882                                 }
883                                 if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0];
884                                 if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0];
885                                 if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1];
886                                 if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1];
887                                 if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2];
888                                 if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2];
889                         }
890                         else
891                         {
892                                 VectorCopy(wl->mins, clipmins);
893                                 VectorCopy(wl->maxs, clipmaxs);
894                         }
895
896                         //if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius))
897                         if (R_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
898                                 continue;
899
900                         // mark the leafs we care about so only things in those leafs will matter
901                         if (cl.worldmodel != NULL)
902                                 for (i = 0;i < wl->numleafs;i++)
903                                         wl->leafs[i]->worldnodeframe = shadowframecount;
904
905                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
906                         VectorScale(wl->light, f, lightcolor);
907                         if (wl->selected)
908                         {
909                                 f = 2 + sin(realtime * M_PI * 4.0);
910                                 VectorScale(lightcolor, f, lightcolor);
911                         }
912
913                         if (wl->castshadows && (gl_stencil || visiblevolumes))
914                         {
915                                 if (!visiblevolumes)
916                                         R_Shadow_Stage_ShadowVolumes();
917                                 ent = &cl_entities[0].render;
918                                 if (wl->shadowvolume && r_shadow_staticworldlights.integer)
919                                         R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
920                                 else
921                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
922                                 if (r_drawentities.integer)
923                                         for (i = 0;i < r_refdef.numentities;i++)
924                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
925                         }
926
927                         if (!visiblevolumes)
928                         {
929                                 if (wl->castshadows && gl_stencil)
930                                         R_Shadow_Stage_LightWithShadows();
931                                 else
932                                         R_Shadow_Stage_LightWithoutShadows();
933
934                                 // calculate world to filter matrix
935                                 Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
936                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
937                                 // calculate world to attenuationxyz/xy matrix
938                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
939                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
940                                 // calculate world to attenuationz matrix
941                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
942                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
943                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
944                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
945                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
946
947                                 ent = &cl_entities[0].render;
948                                 if (ent->model && ent->model->DrawLight)
949                                 {
950                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
951                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
952                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
953                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
954                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
955                                         if (wl->numsurfaces)
956                                                 R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
957                                         else
958                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
959                                 }
960                                 if (r_drawentities.integer)
961                                 {
962                                         for (i = 0;i < r_refdef.numentities;i++)
963                                         {
964                                                 ent = r_refdef.entities[i];
965                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
966                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
967                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
968                                                 {
969                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
970                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
971                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
972                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
973                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
974                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
975                                                 }
976                                         }
977                                 }
978                         }
979                 }
980         }
981         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
982         {
983                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
984                 {
985                         lightradius = rd->cullradius;
986                         clipmins[0] = rd->origin[0] - lightradius;
987                         clipmins[1] = rd->origin[1] - lightradius;
988                         clipmins[2] = rd->origin[2] - lightradius;
989                         clipmaxs[0] = rd->origin[0] + lightradius;
990                         clipmaxs[1] = rd->origin[1] + lightradius;
991                         clipmaxs[2] = rd->origin[2] + lightradius;
992                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
993                                 continue;
994
995                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
996                         VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
997
998                         if (gl_stencil || visiblevolumes)
999                         {
1000                                 if (!visiblevolumes)
1001                                         R_Shadow_Stage_ShadowVolumes();
1002                                 ent = &cl_entities[0].render;
1003                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
1004                                 if (r_drawentities.integer)
1005                                 {
1006                                         for (i = 0;i < r_refdef.numentities;i++)
1007                                         {
1008                                                 ent = r_refdef.entities[i];
1009                                                 if (ent != rd->ent)
1010                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
1011                                         }
1012                                 }
1013                         }
1014
1015                         if (!visiblevolumes)
1016                         {
1017                                 if (gl_stencil)
1018                                         R_Shadow_Stage_LightWithShadows();
1019                                 else
1020                                         R_Shadow_Stage_LightWithoutShadows();
1021
1022                                 // calculate world to filter matrix
1023                                 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
1024                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
1025                                 // calculate world to attenuationxyz/xy matrix
1026                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
1027                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
1028                                 // calculate world to attenuationz matrix
1029                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
1030                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
1031                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
1032                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
1033                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
1034
1035                                 ent = &cl_entities[0].render;
1036                                 if (ent->model && ent->model->DrawLight)
1037                                 {
1038                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
1039                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
1040                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
1041                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
1042                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
1043                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
1044                                 }
1045                                 if (r_drawentities.integer)
1046                                 {
1047                                         for (i = 0;i < r_refdef.numentities;i++)
1048                                         {
1049                                                 ent = r_refdef.entities[i];
1050                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
1051                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
1052                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
1053                                                 {
1054                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
1055                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
1056                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
1057                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
1058                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
1059                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
1060                                                 }
1061                                         }
1062                                 }
1063                         }
1064                 }
1065         }
1066
1067         if (visiblevolumes)
1068                 qglEnable(GL_CULL_FACE);
1069         else
1070                 R_Shadow_Stage_End();
1071         qglDisable(GL_SCISSOR_TEST);
1072 }
1073
1074 static void R_SetFrustum (void)
1075 {
1076         // LordHavoc: note to all quake engine coders, the special case for 90
1077         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
1078         // disabled as well.
1079
1080         // rotate VPN right by FOV_X/2 degrees
1081         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
1082         frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
1083         PlaneClassify(&frustum[0]);
1084
1085         // rotate VPN left by FOV_X/2 degrees
1086         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
1087         frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
1088         PlaneClassify(&frustum[1]);
1089
1090         // rotate VPN up by FOV_X/2 degrees
1091         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
1092         frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
1093         PlaneClassify(&frustum[2]);
1094
1095         // rotate VPN down by FOV_X/2 degrees
1096         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
1097         frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
1098         PlaneClassify(&frustum[3]);
1099 }
1100
1101 /*
1102 ===============
1103 R_SetupFrame
1104 ===============
1105 */
1106 static void R_SetupFrame (void)
1107 {
1108 // don't allow cheats in multiplayer
1109         if (cl.maxclients > 1)
1110         {
1111                 if (r_fullbright.integer != 0)
1112                         Cvar_Set ("r_fullbright", "0");
1113                 if (r_ambient.value != 0)
1114                         Cvar_Set ("r_ambient", "0");
1115         }
1116
1117         r_framecount++;
1118
1119 // build the transformation matrix for the given view angles
1120         VectorCopy (r_refdef.vieworg, r_origin);
1121
1122         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
1123
1124         R_AnimateLight ();
1125 }
1126
1127
1128 static void R_BlendView(void)
1129 {
1130         rmeshstate_t m;
1131         float r;
1132         float vertex3f[3*3];
1133
1134         if (r_refdef.viewblend[3] < 0.01f)
1135                 return;
1136
1137         R_Mesh_Matrix(&r_identitymatrix);
1138
1139         memset(&m, 0, sizeof(m));
1140         R_Mesh_State_Texture(&m);
1141
1142         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1143         GL_DepthMask(true);
1144         GL_DepthTest(false); // magic
1145         GL_VertexPointer(vertex3f);
1146         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
1147         r = 64000;
1148         vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
1149         vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
1150         vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
1151         vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
1152         vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
1153         vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
1154         vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
1155         vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
1156         vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
1157         R_Mesh_Draw(3, 1, polygonelements);
1158 }
1159
1160 /*
1161 ================
1162 R_RenderView
1163
1164 r_refdef must be set before the first call
1165 ================
1166 */
1167 extern void R_DrawLightningBeams (void);
1168 void R_RenderView (void)
1169 {
1170         entity_render_t *world;
1171         if (!r_refdef.entities/* || !cl.worldmodel*/)
1172                 return; //Host_Error ("R_RenderView: NULL worldmodel");
1173
1174         if (r_shadow_realtime_world.integer)
1175         {
1176                 if (!gl_stencil)
1177                 {
1178                         Con_Printf("Stencil not enabled, turning off r_shadow_realtime_world, please type vid_stencil 1;vid_bitsperpixel 32;vid_restart and try again\n");
1179                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
1180                 }
1181         }
1182
1183         world = &cl_entities[0].render;
1184
1185         // FIXME: move to client
1186         R_MoveExplosions();
1187         R_TimeReport("mexplosion");
1188
1189         R_Textures_Frame();
1190         R_SetupFrame();
1191         R_SetFrustum();
1192         R_SetupFog();
1193         R_SkyStartFrame();
1194         R_BuildLightList();
1195         R_TimeReport("setup");
1196
1197         R_WorldVisibility(world);
1198         R_TimeReport("worldvis");
1199
1200         R_FarClip_Start(r_origin, vpn, 768.0f);
1201         R_MarkEntities();
1202         r_farclip = R_FarClip_Finish() + 256.0f;
1203         R_TimeReport("markentity");
1204
1205         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
1206         if (r_shadow_realtime_world.integer || gl_stencil)
1207                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
1208         else
1209                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
1210         GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
1211         qglDepthFunc(GL_LEQUAL);
1212
1213         R_Mesh_Start();
1214         R_MeshQueue_BeginScene();
1215
1216         R_Shadow_UpdateWorldLightSelection();
1217
1218         if (R_DrawBrushModelsSky())
1219                 R_TimeReport("bmodelsky");
1220
1221         // must occur early because it can draw sky
1222         R_DrawWorld(world);
1223         R_TimeReport("world");
1224
1225         // don't let sound skip if going slow
1226         if (!intimerefresh && !r_speeds.integer)
1227                 S_ExtraUpdate ();
1228
1229         R_DrawModels(r_shadow_realtime_world.integer);
1230         R_TimeReport("models");
1231
1232         if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
1233         {
1234                 R_DrawFakeShadows();
1235                 R_TimeReport("fakeshadow");
1236         }
1237
1238         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
1239         {
1240                 R_ShadowVolumeLighting(false);
1241                 R_TimeReport("dynlight");
1242         }
1243
1244         R_DrawLightningBeams();
1245         R_TimeReport("lightning");
1246
1247         R_DrawParticles();
1248         R_TimeReport("particles");
1249
1250         R_DrawExplosions();
1251         R_TimeReport("explosions");
1252
1253         R_MeshQueue_RenderTransparent();
1254         R_TimeReport("drawtrans");
1255
1256         R_DrawCoronas();
1257         R_TimeReport("coronas");
1258
1259         R_DrawWorldCrosshair();
1260         R_TimeReport("crosshair");
1261
1262         R_BlendView();
1263         R_TimeReport("blendview");
1264
1265         R_MeshQueue_Render();
1266         R_MeshQueue_EndScene();
1267
1268         if (r_shadow_visiblevolumes.integer)
1269         {
1270                 R_ShadowVolumeLighting(true);
1271                 R_TimeReport("shadowvolume");
1272         }
1273
1274         R_Mesh_Finish();
1275         R_TimeReport("meshfinish");
1276 }
1277
1278 /*
1279 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1280 {
1281         int i;
1282         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1283         rmeshstate_t m;
1284         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1285         GL_DepthMask(false);
1286         GL_DepthTest(true);
1287         R_Mesh_Matrix(&r_identitymatrix);
1288
1289         memset(&m, 0, sizeof(m));
1290         R_Mesh_State_Texture(&m);
1291
1292         R_Mesh_GetSpace(8);
1293         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1294         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1295         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1296         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1297         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1298         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1299         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1300         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1301         GL_ColorPointer(color);
1302         R_FillColors(color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1303         if (fogenabled)
1304         {
1305                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1306                 {
1307                         VectorSubtract(v, r_origin, diff);
1308                         f2 = exp(fogdensity/DotProduct(diff, diff));
1309                         f1 = 1 - f2;
1310                         f2 *= r_colorscale;
1311                         c[0] = c[0] * f1 + fogcolor[0] * f2;
1312                         c[1] = c[1] * f1 + fogcolor[1] * f2;
1313                         c[2] = c[2] * f1 + fogcolor[2] * f2;
1314                 }
1315         }
1316         R_Mesh_Draw(8, 12);
1317 }
1318 */
1319
1320 int nomodelelements[24] =
1321 {
1322         5, 2, 0,
1323         5, 1, 2,
1324         5, 0, 3,
1325         5, 3, 1,
1326         0, 2, 4,
1327         2, 1, 4,
1328         3, 0, 4,
1329         1, 3, 4
1330 };
1331
1332 float nomodelvertex3f[6*3] =
1333 {
1334         -16,   0,   0,
1335          16,   0,   0,
1336           0, -16,   0,
1337           0,  16,   0,
1338           0,   0, -16,
1339           0,   0,  16
1340 };
1341
1342 float nomodelcolor4f[6*4] =
1343 {
1344         0.0f, 0.0f, 0.5f, 1.0f,
1345         0.0f, 0.0f, 0.5f, 1.0f,
1346         0.0f, 0.5f, 0.0f, 1.0f,
1347         0.0f, 0.5f, 0.0f, 1.0f,
1348         0.5f, 0.0f, 0.0f, 1.0f,
1349         0.5f, 0.0f, 0.0f, 1.0f
1350 };
1351
1352 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1353 {
1354         const entity_render_t *ent = calldata1;
1355         int i;
1356         float f1, f2, *c, diff[3];
1357         float color4f[6*4];
1358         rmeshstate_t m;
1359         R_Mesh_Matrix(&ent->matrix);
1360
1361         memset(&m, 0, sizeof(m));
1362         R_Mesh_State_Texture(&m);
1363
1364         if (ent->flags & EF_ADDITIVE)
1365         {
1366                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1367                 GL_DepthMask(false);
1368         }
1369         else if (ent->alpha < 1)
1370         {
1371                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1372                 GL_DepthMask(false);
1373         }
1374         else
1375         {
1376                 GL_BlendFunc(GL_ONE, GL_ZERO);
1377                 GL_DepthMask(true);
1378         }
1379         GL_DepthTest(true);
1380         GL_VertexPointer(nomodelvertex3f);
1381         if (fogenabled)
1382         {
1383                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1384                 GL_ColorPointer(color4f);
1385                 VectorSubtract(ent->origin, r_origin, diff);
1386                 f2 = exp(fogdensity/DotProduct(diff, diff));
1387                 f1 = 1 - f2;
1388                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1389                 {
1390                         c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
1391                         c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
1392                         c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
1393                         c[3] *= ent->alpha;
1394                 }
1395         }
1396         else if (r_colorscale != 1 || ent->alpha != 1)
1397         {
1398                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1399                 GL_ColorPointer(color4f);
1400                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1401                 {
1402                         c[0] *= r_colorscale;
1403                         c[1] *= r_colorscale;
1404                         c[2] *= r_colorscale;
1405                         c[3] *= ent->alpha;
1406                 }
1407         }
1408         else
1409                 GL_ColorPointer(nomodelcolor4f);
1410         R_Mesh_Draw(6, 8, nomodelelements);
1411 }
1412
1413 void R_DrawNoModel(entity_render_t *ent)
1414 {
1415         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1416                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1417         //else
1418         //      R_DrawNoModelCallback(ent, 0);
1419 }
1420
1421 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1422 {
1423         vec3_t right1, right2, diff, normal;
1424
1425         VectorSubtract (org2, org1, normal);
1426         VectorNormalizeFast (normal);
1427
1428         // calculate 'right' vector for start
1429         VectorSubtract (r_origin, org1, diff);
1430         VectorNormalizeFast (diff);
1431         CrossProduct (normal, diff, right1);
1432
1433         // calculate 'right' vector for end
1434         VectorSubtract (r_origin, org2, diff);
1435         VectorNormalizeFast (diff);
1436         CrossProduct (normal, diff, right2);
1437
1438         vert[ 0] = org1[0] + width * right1[0];
1439         vert[ 1] = org1[1] + width * right1[1];
1440         vert[ 2] = org1[2] + width * right1[2];
1441         vert[ 3] = org1[0] - width * right1[0];
1442         vert[ 4] = org1[1] - width * right1[1];
1443         vert[ 5] = org1[2] - width * right1[2];
1444         vert[ 6] = org2[0] - width * right2[0];
1445         vert[ 7] = org2[1] - width * right2[1];
1446         vert[ 8] = org2[2] - width * right2[2];
1447         vert[ 9] = org2[0] + width * right2[0];
1448         vert[10] = org2[1] + width * right2[1];
1449         vert[11] = org2[2] + width * right2[2];
1450 }
1451
1452 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1453
1454 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
1455 {
1456         float diff[3];
1457         rmeshstate_t m;
1458
1459         if (fogenabled)
1460         {
1461                 VectorSubtract(origin, r_origin, diff);
1462                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1463         }
1464
1465         R_Mesh_Matrix(&r_identitymatrix);
1466         GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1467         GL_VertexPointer(varray_vertex3f);
1468         GL_BlendFunc(blendfunc1, blendfunc2);
1469         GL_DepthMask(false);
1470         GL_DepthTest(!depthdisable);
1471
1472         memset(&m, 0, sizeof(m));
1473         m.tex[0] = R_GetTexture(texture);
1474         m.pointer_texcoord[0] = spritetexcoord2f;
1475         R_Mesh_State_Texture(&m);
1476
1477         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1478         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1479         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1480         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1481         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1482         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1483         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1484         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1485         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1486         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1487         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1488         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1489         R_Mesh_Draw(4, 2, polygonelements);
1490 }
1491