]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
added support for GAME_GOODVSBAD2
[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_DPrintf("\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                 R_Mesh_State_Texture(&m);
821
822                 GL_BlendFunc(GL_ONE, GL_ONE);
823                 GL_DepthMask(false);
824                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
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_world.integer || 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                 qglEnable(GL_CULL_FACE);
1060         else
1061                 R_Shadow_Stage_End();
1062         qglDisable(GL_SCISSOR_TEST);
1063 }
1064
1065 static void R_SetFrustum (void)
1066 {
1067         // LordHavoc: note to all quake engine coders, the special case for 90
1068         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
1069         // disabled as well.
1070
1071         // rotate VPN right by FOV_X/2 degrees
1072         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
1073         frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
1074         PlaneClassify(&frustum[0]);
1075
1076         // rotate VPN left by FOV_X/2 degrees
1077         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
1078         frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
1079         PlaneClassify(&frustum[1]);
1080
1081         // rotate VPN up by FOV_X/2 degrees
1082         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
1083         frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
1084         PlaneClassify(&frustum[2]);
1085
1086         // rotate VPN down by FOV_X/2 degrees
1087         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
1088         frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
1089         PlaneClassify(&frustum[3]);
1090 }
1091
1092 /*
1093 ===============
1094 R_SetupFrame
1095 ===============
1096 */
1097 static void R_SetupFrame (void)
1098 {
1099 // don't allow cheats in multiplayer
1100         if (cl.maxclients > 1)
1101         {
1102                 if (r_fullbright.integer != 0)
1103                         Cvar_Set ("r_fullbright", "0");
1104                 if (r_ambient.value != 0)
1105                         Cvar_Set ("r_ambient", "0");
1106         }
1107
1108         r_framecount++;
1109
1110 // build the transformation matrix for the given view angles
1111         VectorCopy (r_refdef.vieworg, r_origin);
1112
1113         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
1114
1115         R_AnimateLight ();
1116 }
1117
1118
1119 static void R_BlendView(void)
1120 {
1121         rmeshstate_t m;
1122         float r;
1123         float vertex3f[3*3];
1124
1125         if (r_refdef.viewblend[3] < 0.01f)
1126                 return;
1127
1128         R_Mesh_Matrix(&r_identitymatrix);
1129
1130         memset(&m, 0, sizeof(m));
1131         R_Mesh_State_Texture(&m);
1132
1133         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1134         GL_DepthMask(true);
1135         GL_DepthTest(false); // magic
1136         GL_VertexPointer(vertex3f);
1137         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
1138         r = 64000;
1139         vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
1140         vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
1141         vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
1142         vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
1143         vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
1144         vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
1145         vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
1146         vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
1147         vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
1148         R_Mesh_Draw(3, 1, polygonelements);
1149 }
1150
1151 /*
1152 ================
1153 R_RenderView
1154
1155 r_refdef must be set before the first call
1156 ================
1157 */
1158 extern void R_DrawLightningBeams (void);
1159 void R_RenderView (void)
1160 {
1161         entity_render_t *world;
1162         if (!r_refdef.entities/* || !cl.worldmodel*/)
1163                 return; //Host_Error ("R_RenderView: NULL worldmodel");
1164
1165         if (r_shadow_realtime_world.integer)
1166         {
1167                 if (!gl_stencil)
1168                 {
1169                         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");
1170                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
1171                 }
1172         }
1173
1174         world = &cl_entities[0].render;
1175
1176         // FIXME: move to client
1177         R_MoveExplosions();
1178         R_TimeReport("mexplosion");
1179
1180         R_Textures_Frame();
1181         R_SetupFrame();
1182         R_SetFrustum();
1183         R_SetupFog();
1184         R_SkyStartFrame();
1185         R_BuildLightList();
1186         R_TimeReport("setup");
1187
1188         R_WorldVisibility(world);
1189         R_TimeReport("worldvis");
1190
1191         R_FarClip_Start(r_origin, vpn, 768.0f);
1192         R_MarkEntities();
1193         r_farclip = R_FarClip_Finish() + 256.0f;
1194         R_TimeReport("markentity");
1195
1196         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
1197         if (r_shadow_realtime_world.integer || gl_stencil)
1198                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
1199         else
1200                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
1201         GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
1202         qglDepthFunc(GL_LEQUAL);
1203
1204         R_Mesh_Start();
1205         R_MeshQueue_BeginScene();
1206
1207         R_Shadow_UpdateWorldLightSelection();
1208
1209         if (R_DrawBrushModelsSky())
1210                 R_TimeReport("bmodelsky");
1211
1212         // must occur early because it can draw sky
1213         R_DrawWorld(world);
1214         R_TimeReport("world");
1215
1216         // don't let sound skip if going slow
1217         if (!intimerefresh && !r_speeds.integer)
1218                 S_ExtraUpdate ();
1219
1220         R_DrawModels(r_shadow_realtime_world.integer);
1221         R_TimeReport("models");
1222
1223         if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
1224         {
1225                 R_DrawFakeShadows();
1226                 R_TimeReport("fakeshadow");
1227         }
1228
1229         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
1230         {
1231                 R_ShadowVolumeLighting(false);
1232                 R_TimeReport("dynlight");
1233         }
1234
1235         R_DrawLightningBeams();
1236         R_TimeReport("lightning");
1237
1238         R_DrawParticles();
1239         R_TimeReport("particles");
1240
1241         R_DrawExplosions();
1242         R_TimeReport("explosions");
1243
1244         R_MeshQueue_RenderTransparent();
1245         R_TimeReport("drawtrans");
1246
1247         R_DrawCoronas();
1248         R_TimeReport("coronas");
1249
1250         R_DrawWorldCrosshair();
1251         R_TimeReport("crosshair");
1252
1253         R_BlendView();
1254         R_TimeReport("blendview");
1255
1256         R_MeshQueue_Render();
1257         R_MeshQueue_EndScene();
1258
1259         if (r_shadow_visiblevolumes.integer)
1260         {
1261                 R_ShadowVolumeLighting(true);
1262                 R_TimeReport("shadowvolume");
1263         }
1264
1265         R_Mesh_Finish();
1266         R_TimeReport("meshfinish");
1267 }
1268
1269 /*
1270 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1271 {
1272         int i;
1273         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1274         rmeshstate_t m;
1275         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1276         GL_DepthMask(false);
1277         GL_DepthTest(true);
1278         R_Mesh_Matrix(&r_identitymatrix);
1279
1280         memset(&m, 0, sizeof(m));
1281         R_Mesh_State_Texture(&m);
1282
1283         R_Mesh_GetSpace(8);
1284         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1285         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1286         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1287         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1288         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1289         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1290         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1291         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1292         GL_ColorPointer(color);
1293         R_FillColors(color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1294         if (fogenabled)
1295         {
1296                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1297                 {
1298                         VectorSubtract(v, r_origin, diff);
1299                         f2 = exp(fogdensity/DotProduct(diff, diff));
1300                         f1 = 1 - f2;
1301                         f2 *= r_colorscale;
1302                         c[0] = c[0] * f1 + fogcolor[0] * f2;
1303                         c[1] = c[1] * f1 + fogcolor[1] * f2;
1304                         c[2] = c[2] * f1 + fogcolor[2] * f2;
1305                 }
1306         }
1307         R_Mesh_Draw(8, 12);
1308 }
1309 */
1310
1311 int nomodelelements[24] =
1312 {
1313         5, 2, 0,
1314         5, 1, 2,
1315         5, 0, 3,
1316         5, 3, 1,
1317         0, 2, 4,
1318         2, 1, 4,
1319         3, 0, 4,
1320         1, 3, 4
1321 };
1322
1323 float nomodelvertex3f[6*3] =
1324 {
1325         -16,   0,   0,
1326          16,   0,   0,
1327           0, -16,   0,
1328           0,  16,   0,
1329           0,   0, -16,
1330           0,   0,  16
1331 };
1332
1333 float nomodelcolor4f[6*4] =
1334 {
1335         0.0f, 0.0f, 0.5f, 1.0f,
1336         0.0f, 0.0f, 0.5f, 1.0f,
1337         0.0f, 0.5f, 0.0f, 1.0f,
1338         0.0f, 0.5f, 0.0f, 1.0f,
1339         0.5f, 0.0f, 0.0f, 1.0f,
1340         0.5f, 0.0f, 0.0f, 1.0f
1341 };
1342
1343 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1344 {
1345         const entity_render_t *ent = calldata1;
1346         int i;
1347         float f1, f2, *c, diff[3];
1348         float color4f[6*4];
1349         rmeshstate_t m;
1350         R_Mesh_Matrix(&ent->matrix);
1351
1352         memset(&m, 0, sizeof(m));
1353         R_Mesh_State_Texture(&m);
1354
1355         if (ent->flags & EF_ADDITIVE)
1356         {
1357                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1358                 GL_DepthMask(false);
1359         }
1360         else if (ent->alpha < 1)
1361         {
1362                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1363                 GL_DepthMask(false);
1364         }
1365         else
1366         {
1367                 GL_BlendFunc(GL_ONE, GL_ZERO);
1368                 GL_DepthMask(true);
1369         }
1370         GL_DepthTest(true);
1371         GL_VertexPointer(nomodelvertex3f);
1372         if (fogenabled)
1373         {
1374                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1375                 GL_ColorPointer(color4f);
1376                 VectorSubtract(ent->origin, r_origin, diff);
1377                 f2 = exp(fogdensity/DotProduct(diff, diff));
1378                 f1 = 1 - f2;
1379                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1380                 {
1381                         c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
1382                         c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
1383                         c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
1384                         c[3] *= ent->alpha;
1385                 }
1386         }
1387         else if (r_colorscale != 1 || ent->alpha != 1)
1388         {
1389                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1390                 GL_ColorPointer(color4f);
1391                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1392                 {
1393                         c[0] *= r_colorscale;
1394                         c[1] *= r_colorscale;
1395                         c[2] *= r_colorscale;
1396                         c[3] *= ent->alpha;
1397                 }
1398         }
1399         else
1400                 GL_ColorPointer(nomodelcolor4f);
1401         R_Mesh_Draw(6, 8, nomodelelements);
1402 }
1403
1404 void R_DrawNoModel(entity_render_t *ent)
1405 {
1406         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1407                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1408         //else
1409         //      R_DrawNoModelCallback(ent, 0);
1410 }
1411
1412 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1413 {
1414         vec3_t right1, right2, diff, normal;
1415
1416         VectorSubtract (org2, org1, normal);
1417         VectorNormalizeFast (normal);
1418
1419         // calculate 'right' vector for start
1420         VectorSubtract (r_origin, org1, diff);
1421         VectorNormalizeFast (diff);
1422         CrossProduct (normal, diff, right1);
1423
1424         // calculate 'right' vector for end
1425         VectorSubtract (r_origin, org2, diff);
1426         VectorNormalizeFast (diff);
1427         CrossProduct (normal, diff, right2);
1428
1429         vert[ 0] = org1[0] + width * right1[0];
1430         vert[ 1] = org1[1] + width * right1[1];
1431         vert[ 2] = org1[2] + width * right1[2];
1432         vert[ 3] = org1[0] - width * right1[0];
1433         vert[ 4] = org1[1] - width * right1[1];
1434         vert[ 5] = org1[2] - width * right1[2];
1435         vert[ 6] = org2[0] - width * right2[0];
1436         vert[ 7] = org2[1] - width * right2[1];
1437         vert[ 8] = org2[2] - width * right2[2];
1438         vert[ 9] = org2[0] + width * right2[0];
1439         vert[10] = org2[1] + width * right2[1];
1440         vert[11] = org2[2] + width * right2[2];
1441 }
1442
1443 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1444
1445 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
1446 {
1447         float diff[3];
1448         rmeshstate_t m;
1449
1450         if (fogenabled)
1451         {
1452                 VectorSubtract(origin, r_origin, diff);
1453                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1454         }
1455
1456         R_Mesh_Matrix(&r_identitymatrix);
1457         GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1458         GL_VertexPointer(varray_vertex3f);
1459         GL_BlendFunc(blendfunc1, blendfunc2);
1460         GL_DepthMask(false);
1461         GL_DepthTest(!depthdisable);
1462
1463         memset(&m, 0, sizeof(m));
1464         m.tex[0] = R_GetTexture(texture);
1465         m.pointer_texcoord[0] = spritetexcoord2f;
1466         R_Mesh_State_Texture(&m);
1467
1468         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1469         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1470         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1471         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1472         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1473         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1474         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1475         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1476         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1477         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1478         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1479         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1480         R_Mesh_Draw(4, 2, polygonelements);
1481 }
1482