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