]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
some more minor cleanups
[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 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                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
958                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
959                                                 {
960                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
961                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
962                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
963                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
964                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
965                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
966                                                 }
967                                         }
968                                 }
969                         }
970                 }
971         }
972         if (r_shadow_realtime_dlight.integer)
973         {
974                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
975                 {
976                         lightradius = rd->cullradius;
977                         clipmins[0] = rd->origin[0] - lightradius;
978                         clipmins[1] = rd->origin[1] - lightradius;
979                         clipmins[2] = rd->origin[2] - lightradius;
980                         clipmaxs[0] = rd->origin[0] + lightradius;
981                         clipmaxs[1] = rd->origin[1] + lightradius;
982                         clipmaxs[2] = rd->origin[2] + lightradius;
983                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
984                                 continue;
985
986                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
987                         VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
988
989                         if (gl_stencil || visiblevolumes)
990                         {
991                                 if (!visiblevolumes)
992                                         R_Shadow_Stage_ShadowVolumes();
993                                 ent = &cl_entities[0].render;
994                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
995                                 if (r_drawentities.integer)
996                                 {
997                                         for (i = 0;i < r_refdef.numentities;i++)
998                                         {
999                                                 ent = r_refdef.entities[i];
1000                                                 if (ent != rd->ent)
1001                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
1002                                         }
1003                                 }
1004                         }
1005
1006                         if (!visiblevolumes)
1007                         {
1008                                 if (gl_stencil)
1009                                         R_Shadow_Stage_LightWithShadows();
1010                                 else
1011                                         R_Shadow_Stage_LightWithoutShadows();
1012
1013                                 // calculate world to filter matrix
1014                                 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
1015                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
1016                                 // calculate world to attenuationxyz/xy matrix
1017                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
1018                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
1019                                 // calculate world to attenuationz matrix
1020                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
1021                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
1022                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
1023                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
1024                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
1025
1026                                 ent = &cl_entities[0].render;
1027                                 if (ent->model && ent->model->DrawLight)
1028                                 {
1029                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
1030                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
1031                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
1032                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
1033                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
1034                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
1035                                 }
1036                                 if (r_drawentities.integer)
1037                                 {
1038                                         for (i = 0;i < r_refdef.numentities;i++)
1039                                         {
1040                                                 ent = r_refdef.entities[i];
1041                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
1042                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
1043                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
1044                                                 {
1045                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
1046                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
1047                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
1048                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
1049                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
1050                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
1051                                                 }
1052                                         }
1053                                 }
1054                         }
1055                 }
1056         }
1057
1058         if (!visiblevolumes)
1059                 R_Shadow_Stage_End();
1060         qglEnable(GL_CULL_FACE);
1061         qglDisable(GL_SCISSOR_TEST);
1062 }
1063
1064 static void R_SetFrustum (void)
1065 {
1066         // LordHavoc: note to all quake engine coders, the special case for 90
1067         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
1068         // disabled as well.
1069
1070         // rotate VPN right by FOV_X/2 degrees
1071         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
1072         frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
1073         PlaneClassify(&frustum[0]);
1074
1075         // rotate VPN left by FOV_X/2 degrees
1076         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
1077         frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
1078         PlaneClassify(&frustum[1]);
1079
1080         // rotate VPN up by FOV_X/2 degrees
1081         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
1082         frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
1083         PlaneClassify(&frustum[2]);
1084
1085         // rotate VPN down by FOV_X/2 degrees
1086         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
1087         frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
1088         PlaneClassify(&frustum[3]);
1089 }
1090
1091 /*
1092 ===============
1093 R_SetupFrame
1094 ===============
1095 */
1096 static void R_SetupFrame (void)
1097 {
1098 // don't allow cheats in multiplayer
1099         if (cl.maxclients > 1)
1100         {
1101                 if (r_fullbright.integer != 0)
1102                         Cvar_Set ("r_fullbright", "0");
1103                 if (r_ambient.value != 0)
1104                         Cvar_Set ("r_ambient", "0");
1105         }
1106
1107         r_framecount++;
1108
1109 // build the transformation matrix for the given view angles
1110         VectorCopy (r_refdef.vieworg, r_origin);
1111
1112         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
1113
1114         R_AnimateLight ();
1115 }
1116
1117
1118 static void R_BlendView(void)
1119 {
1120         rmeshstate_t m;
1121         float r;
1122
1123         if (r_refdef.viewblend[3] < 0.01f)
1124                 return;
1125
1126         memset(&m, 0, sizeof(m));
1127         m.blendfunc1 = GL_SRC_ALPHA;
1128         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1129         m.depthdisable = true; // magic
1130         R_Mesh_Matrix(&r_identitymatrix);
1131         R_Mesh_State(&m);
1132
1133         R_Mesh_GetSpace(3);
1134         r = 64000;
1135         varray_vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
1136         varray_vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
1137         varray_vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
1138         varray_vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
1139         varray_vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
1140         varray_vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
1141         varray_vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
1142         varray_vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
1143         varray_vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
1144         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
1145         R_Mesh_Draw(3, 1, polygonelements);
1146 }
1147
1148 /*
1149 ================
1150 R_RenderView
1151
1152 r_refdef must be set before the first call
1153 ================
1154 */
1155 extern void R_DrawLightningBeams (void);
1156 void R_RenderView (void)
1157 {
1158         entity_render_t *world;
1159         if (!r_refdef.entities/* || !cl.worldmodel*/)
1160                 return; //Host_Error ("R_RenderView: NULL worldmodel");
1161
1162         if (r_shadow_realtime_world.integer)
1163         {
1164                 if (!gl_stencil)
1165                 {
1166                         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");
1167                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
1168                 }
1169         }
1170
1171         world = &cl_entities[0].render;
1172
1173         // FIXME: move to client
1174         R_MoveExplosions();
1175         R_TimeReport("mexplosion");
1176
1177         R_Textures_Frame();
1178         R_SetupFrame();
1179         R_SetFrustum();
1180         R_SetupFog();
1181         R_SkyStartFrame();
1182         R_BuildLightList();
1183         R_TimeReport("setup");
1184
1185         R_WorldVisibility(world);
1186         R_TimeReport("worldvis");
1187
1188         R_FarClip_Start(r_origin, vpn, 768.0f);
1189         R_MarkEntities();
1190         r_farclip = R_FarClip_Finish() + 256.0f;
1191         R_TimeReport("markentity");
1192
1193         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
1194         if (r_shadow_realtime_world.integer || gl_stencil)
1195                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
1196         else
1197                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
1198         GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
1199         qglDepthFunc(GL_LEQUAL);
1200
1201         R_Mesh_Start();
1202         R_MeshQueue_BeginScene();
1203
1204         R_Shadow_UpdateWorldLightSelection();
1205
1206         if (R_DrawBrushModelsSky())
1207                 R_TimeReport("bmodelsky");
1208
1209         // must occur early because it can draw sky
1210         R_DrawWorld(world);
1211         R_TimeReport("world");
1212
1213         // don't let sound skip if going slow
1214         if (!intimerefresh && !r_speeds.integer)
1215                 S_ExtraUpdate ();
1216
1217         R_DrawModels(r_shadow_realtime_world.integer);
1218         R_TimeReport("models");
1219
1220         if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
1221         {
1222                 R_DrawFakeShadows();
1223                 R_TimeReport("fakeshadow");
1224         }
1225
1226         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
1227         {
1228                 R_ShadowVolumeLighting(false);
1229                 R_TimeReport("dynlight");
1230         }
1231
1232         R_DrawLightningBeams();
1233         R_TimeReport("lightning");
1234
1235         R_DrawParticles();
1236         R_TimeReport("particles");
1237
1238         R_DrawExplosions();
1239         R_TimeReport("explosions");
1240
1241         R_MeshQueue_RenderTransparent();
1242         R_TimeReport("drawtrans");
1243
1244         R_DrawCoronas();
1245         R_TimeReport("coronas");
1246
1247         R_DrawWorldCrosshair();
1248         R_TimeReport("crosshair");
1249
1250         R_BlendView();
1251         R_TimeReport("blendview");
1252
1253         R_MeshQueue_Render();
1254         R_MeshQueue_EndScene();
1255
1256         if (r_shadow_visiblevolumes.integer)
1257         {
1258                 R_ShadowVolumeLighting(true);
1259                 R_TimeReport("shadowvolume");
1260         }
1261
1262         R_Mesh_Finish();
1263         R_TimeReport("meshfinish");
1264 }
1265
1266 /*
1267 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1268 {
1269         int i;
1270         float *v, *c, f1, f2, diff[3];
1271         rmeshstate_t m;
1272         m.blendfunc1 = GL_SRC_ALPHA;
1273         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1274         R_Mesh_Matrix(&r_identitymatrix);
1275         R_Mesh_State(&m);
1276
1277         R_Mesh_GetSpace(8);
1278         varray_vertex[ 0] = mins[0];varray_vertex[ 1] = mins[1];varray_vertex[ 2] = mins[2];
1279         varray_vertex[ 4] = maxs[0];varray_vertex[ 5] = mins[1];varray_vertex[ 6] = mins[2];
1280         varray_vertex[ 8] = mins[0];varray_vertex[ 9] = maxs[1];varray_vertex[10] = mins[2];
1281         varray_vertex[12] = maxs[0];varray_vertex[13] = maxs[1];varray_vertex[14] = mins[2];
1282         varray_vertex[16] = mins[0];varray_vertex[17] = mins[1];varray_vertex[18] = maxs[2];
1283         varray_vertex[20] = maxs[0];varray_vertex[21] = mins[1];varray_vertex[22] = maxs[2];
1284         varray_vertex[24] = mins[0];varray_vertex[25] = maxs[1];varray_vertex[26] = maxs[2];
1285         varray_vertex[28] = maxs[0];varray_vertex[29] = maxs[1];varray_vertex[30] = maxs[2];
1286         R_FillColors(varray_color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1287         if (fogenabled)
1288         {
1289                 for (i = 0, v = varray_vertex, c = varray_color;i < 8;i++, v += 4, c += 4)
1290                 {
1291                         VectorSubtract(v, r_origin, diff);
1292                         f2 = exp(fogdensity/DotProduct(diff, diff));
1293                         f1 = 1 - f2;
1294                         f2 *= r_colorscale;
1295                         c[0] = c[0] * f1 + fogcolor[0] * f2;
1296                         c[1] = c[1] * f1 + fogcolor[1] * f2;
1297                         c[2] = c[2] * f1 + fogcolor[2] * f2;
1298                 }
1299         }
1300         GL_UseColorArray();
1301         R_Mesh_Draw(8, 12);
1302 }
1303 */
1304
1305 int nomodelelements[24] =
1306 {
1307         5, 2, 0,
1308         5, 1, 2,
1309         5, 0, 3,
1310         5, 3, 1,
1311         0, 2, 4,
1312         2, 1, 4,
1313         3, 0, 4,
1314         1, 3, 4
1315 };
1316
1317 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1318 {
1319         const entity_render_t *ent = calldata1;
1320         int i;
1321         float f1, f2, *c, diff[3];
1322         rmeshstate_t m;
1323         memset(&m, 0, sizeof(m));
1324         if (ent->flags & EF_ADDITIVE)
1325         {
1326                 m.blendfunc1 = GL_SRC_ALPHA;
1327                 m.blendfunc2 = GL_ONE;
1328         }
1329         else if (ent->alpha < 1)
1330         {
1331                 m.blendfunc1 = GL_SRC_ALPHA;
1332                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1333         }
1334         else
1335         {
1336                 m.blendfunc1 = GL_ONE;
1337                 m.blendfunc2 = GL_ZERO;
1338         }
1339         R_Mesh_Matrix(&ent->matrix);
1340         R_Mesh_State(&m);
1341
1342         GL_UseColorArray();
1343         R_Mesh_GetSpace(6);
1344         varray_vertex3f[ 0] = -16;varray_vertex3f[ 1] =   0;varray_vertex3f[ 2] =   0;
1345         varray_vertex3f[ 3] =  16;varray_vertex3f[ 4] =   0;varray_vertex3f[ 5] =   0;
1346         varray_vertex3f[ 6] =   0;varray_vertex3f[ 7] = -16;varray_vertex3f[ 8] =   0;
1347         varray_vertex3f[ 9] =   0;varray_vertex3f[10] =  16;varray_vertex3f[11] =   0;
1348         varray_vertex3f[12] =   0;varray_vertex3f[13] =   0;varray_vertex3f[14] = -16;
1349         varray_vertex3f[15] =   0;varray_vertex3f[16] =   0;varray_vertex3f[17] =  16;
1350         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;
1351         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;
1352         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;
1353         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;
1354         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;
1355         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;
1356         if (fogenabled)
1357         {
1358                 VectorSubtract(ent->origin, r_origin, diff);
1359                 f2 = exp(fogdensity/DotProduct(diff, diff));
1360                 f1 = 1 - f2;
1361                 for (i = 0, c = varray_color4f;i < 6;i++, c += 4)
1362                 {
1363                         c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
1364                         c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
1365                         c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
1366                 }
1367         }
1368         else
1369         {
1370                 for (i = 0, c = varray_color4f;i < 6;i++, c += 4)
1371                 {
1372                         c[0] *= r_colorscale;
1373                         c[1] *= r_colorscale;
1374                         c[2] *= r_colorscale;
1375                 }
1376         }
1377         R_Mesh_Draw(6, 8, nomodelelements);
1378 }
1379
1380 void R_DrawNoModel(entity_render_t *ent)
1381 {
1382         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1383                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1384         //else
1385         //      R_DrawNoModelCallback(ent, 0);
1386 }
1387
1388 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1389 {
1390         vec3_t right1, right2, diff, normal;
1391
1392         VectorSubtract (org2, org1, normal);
1393         VectorNormalizeFast (normal);
1394
1395         // calculate 'right' vector for start
1396         VectorSubtract (r_origin, org1, diff);
1397         VectorNormalizeFast (diff);
1398         CrossProduct (normal, diff, right1);
1399
1400         // calculate 'right' vector for end
1401         VectorSubtract (r_origin, org2, diff);
1402         VectorNormalizeFast (diff);
1403         CrossProduct (normal, diff, right2);
1404
1405         vert[ 0] = org1[0] + width * right1[0];
1406         vert[ 1] = org1[1] + width * right1[1];
1407         vert[ 2] = org1[2] + width * right1[2];
1408         vert[ 3] = org1[0] - width * right1[0];
1409         vert[ 4] = org1[1] - width * right1[1];
1410         vert[ 5] = org1[2] - width * right1[2];
1411         vert[ 6] = org2[0] - width * right2[0];
1412         vert[ 7] = org2[1] - width * right2[1];
1413         vert[ 8] = org2[2] - width * right2[2];
1414         vert[ 9] = org2[0] + width * right2[0];
1415         vert[10] = org2[1] + width * right2[1];
1416         vert[11] = org2[2] + width * right2[2];
1417 }
1418
1419 void R_DrawSpriteMesh(const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2)
1420 {
1421         R_Mesh_GetSpace(4);
1422         varray_texcoord2f[0][0] = 1;varray_texcoord2f[0][1] = 1;
1423         varray_texcoord2f[0][2] = 1;varray_texcoord2f[0][3] = 0;
1424         varray_texcoord2f[0][4] = 0;varray_texcoord2f[0][5] = 0;
1425         varray_texcoord2f[0][6] = 0;varray_texcoord2f[0][7] = 1;
1426         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1427         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1428         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1429         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1430         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1431         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1432         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1433         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1434         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1435         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1436         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1437         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1438         R_Mesh_Draw(4, 2, polygonelements);
1439 }
1440