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