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