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