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