]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
dlights using light_lev now need the PFLAG_FULLDYNAMIC flag set to operate, otherwise...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24
25 // used for dlight push checking and other things
26 int r_framecount;
27
28 // used for visibility checking
29 qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
30
31 mplane_t frustum[4];
32
33 matrix4x4_t r_identitymatrix;
34
35 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
36
37 // true during envmap command capture
38 qboolean envmap;
39
40 float r_farclip;
41
42 // view origin
43 vec3_t r_vieworigin;
44 vec3_t r_viewforward;
45 vec3_t r_viewleft;
46 vec3_t r_viewright;
47 vec3_t r_viewup;
48 int r_view_x;
49 int r_view_y;
50 int r_view_width;
51 int r_view_height;
52 float r_view_fov_x;
53 float r_view_fov_y;
54 matrix4x4_t r_view_matrix;
55
56 //
57 // screen size info
58 //
59 refdef_t r_refdef;
60
61 // 8.8 fraction of base light value
62 unsigned short d_lightstylevalue[256];
63
64 cvar_t r_drawentities = {0, "r_drawentities","1"};
65 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
66 cvar_t r_speeds = {0, "r_speeds","0"};
67 cvar_t r_fullbright = {0, "r_fullbright","0"};
68 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
69 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
70 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
71 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
72
73 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
74 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
75 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
76 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
77 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
78 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
79 cvar_t gl_fogend = {0, "gl_fogend","0"};
80
81 cvar_t r_textureunits = {0, "r_textureunits", "32"};
82
83 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
84 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
85 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
86 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
87
88
89 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
90 {
91         int i;
92         for (i = 0;i < verts;i++)
93         {
94                 out[0] = in[0] * r;
95                 out[1] = in[1] * g;
96                 out[2] = in[2] * b;
97                 out[3] = in[3];
98                 in += 4;
99                 out += 4;
100         }
101 }
102
103 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
104 {
105         int i;
106         for (i = 0;i < verts;i++)
107         {
108                 out[0] = r;
109                 out[1] = g;
110                 out[2] = b;
111                 out[3] = a;
112                 out += 4;
113         }
114 }
115
116 /*
117 ====================
118 R_TimeRefresh_f
119
120 For program optimization
121 ====================
122 */
123 qboolean intimerefresh = 0;
124 static void R_TimeRefresh_f (void)
125 {
126         int i;
127         float timestart, timedelta, oldangles[3];
128
129         intimerefresh = 1;
130         VectorCopy(cl.viewangles, oldangles);
131         VectorClear(cl.viewangles);
132
133         timestart = Sys_DoubleTime();
134         for (i = 0;i < 128;i++)
135         {
136                 Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], 0, i / 128.0 * 360.0, 0, 1);
137                 CL_UpdateScreen();
138         }
139         timedelta = Sys_DoubleTime() - timestart;
140
141         VectorCopy(oldangles, cl.viewangles);
142         intimerefresh = 0;
143         Con_Printf ("%f seconds (%f fps)\n", timedelta, 128/timedelta);
144 }
145
146 vec3_t fogcolor;
147 vec_t fogdensity;
148 float fog_density, fog_red, fog_green, fog_blue;
149 qboolean fogenabled;
150 qboolean oldgl_fogenable;
151 void R_UpdateFog(void)
152 {
153         if (gamemode == GAME_NEHAHRA)
154         {
155                 if (gl_fogenable.integer)
156                 {
157                         oldgl_fogenable = true;
158                         fog_density = gl_fogdensity.value;
159                         fog_red = gl_fogred.value;
160                         fog_green = gl_foggreen.value;
161                         fog_blue = gl_fogblue.value;
162                 }
163                 else if (oldgl_fogenable)
164                 {
165                         oldgl_fogenable = false;
166                         fog_density = 0;
167                         fog_red = 0;
168                         fog_green = 0;
169                         fog_blue = 0;
170                 }
171         }
172         if (fog_density)
173         {
174                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
175                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
176                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
177         }
178         if (fog_density)
179         {
180                 fogenabled = true;
181                 fogdensity = -4000.0f / (fog_density * fog_density);
182                 // fog color was already set
183         }
184         else
185                 fogenabled = false;
186 }
187
188 // FIXME: move this to client?
189 void FOG_clear(void)
190 {
191         if (gamemode == GAME_NEHAHRA)
192         {
193                 Cvar_Set("gl_fogenable", "0");
194                 Cvar_Set("gl_fogdensity", "0.2");
195                 Cvar_Set("gl_fogred", "0.3");
196                 Cvar_Set("gl_foggreen", "0.3");
197                 Cvar_Set("gl_fogblue", "0.3");
198         }
199         fog_density = fog_red = fog_green = fog_blue = 0.0f;
200 }
201
202 // FIXME: move this to client?
203 void FOG_registercvars(void)
204 {
205         if (gamemode == GAME_NEHAHRA)
206         {
207                 Cvar_RegisterVariable (&gl_fogenable);
208                 Cvar_RegisterVariable (&gl_fogdensity);
209                 Cvar_RegisterVariable (&gl_fogred);
210                 Cvar_RegisterVariable (&gl_foggreen);
211                 Cvar_RegisterVariable (&gl_fogblue);
212                 Cvar_RegisterVariable (&gl_fogstart);
213                 Cvar_RegisterVariable (&gl_fogend);
214         }
215 }
216
217 void gl_main_start(void)
218 {
219 }
220
221 void gl_main_shutdown(void)
222 {
223 }
224
225 extern void CL_ParseEntityLump(char *entitystring);
226 void gl_main_newmap(void)
227 {
228         int l;
229         char *entities, entname[MAX_QPATH];
230         r_framecount = 1;
231         if (cl.worldmodel)
232         {
233                 strcpy(entname, cl.worldmodel->name);
234                 l = strlen(entname) - 4;
235                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
236                 {
237                         strcpy(entname + l, ".ent");
238                         if ((entities = FS_LoadFile(entname, true)))
239                         {
240                                 CL_ParseEntityLump(entities);
241                                 Mem_Free(entities);
242                                 return;
243                         }
244                 }
245                 if (cl.worldmodel->brush.entities)
246                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
247         }
248 }
249
250 void GL_Main_Init(void)
251 {
252         Matrix4x4_CreateIdentity(&r_identitymatrix);
253 // FIXME: move this to client?
254         FOG_registercvars();
255         Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
256         Cvar_RegisterVariable(&r_drawentities);
257         Cvar_RegisterVariable(&r_drawviewmodel);
258         Cvar_RegisterVariable(&r_speeds);
259         Cvar_RegisterVariable(&r_fullbrights);
260         Cvar_RegisterVariable(&r_wateralpha);
261         Cvar_RegisterVariable(&r_dynamic);
262         Cvar_RegisterVariable(&r_fullbright);
263         Cvar_RegisterVariable(&r_textureunits);
264         Cvar_RegisterVariable(&r_lerpsprites);
265         Cvar_RegisterVariable(&r_lerpmodels);
266         Cvar_RegisterVariable(&r_waterscroll);
267         Cvar_RegisterVariable(&r_watershader);
268         Cvar_RegisterVariable(&r_drawcollisionbrushes);
269         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
270                 Cvar_SetValue("r_fullbrights", 0);
271         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
272 }
273
274 static vec3_t r_farclip_origin;
275 static vec3_t r_farclip_direction;
276 static vec_t r_farclip_directiondist;
277 static vec_t r_farclip_meshfarclip;
278 static int r_farclip_directionbit0;
279 static int r_farclip_directionbit1;
280 static int r_farclip_directionbit2;
281
282 // enlarge farclip to accomodate box
283 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
284 {
285         float d;
286         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
287           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
288           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
289         if (r_farclip_meshfarclip < d)
290                 r_farclip_meshfarclip = d;
291 }
292
293 // return farclip value
294 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
295 {
296         int i;
297
298         VectorCopy(origin, r_farclip_origin);
299         VectorCopy(direction, r_farclip_direction);
300         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
301         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
302         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
303         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
304         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
305
306         if (cl.worldmodel)
307                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
308         for (i = 0;i < r_refdef.numentities;i++)
309                 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
310         
311         return r_farclip_meshfarclip - r_farclip_directiondist;
312 }
313
314 extern void R_Textures_Init(void);
315 extern void Mod_RenderInit(void);
316 extern void GL_Draw_Init(void);
317 extern void GL_Main_Init(void);
318 extern void R_Shadow_Init(void);
319 extern void GL_Models_Init(void);
320 extern void R_Sky_Init(void);
321 extern void GL_Surf_Init(void);
322 extern void R_Crosshairs_Init(void);
323 extern void R_Light_Init(void);
324 extern void R_Particles_Init(void);
325 extern void R_Explosion_Init(void);
326 extern void ui_init(void);
327 extern void gl_backend_init(void);
328 extern void Sbar_Init(void);
329 extern void R_LightningBeams_Init(void);
330
331 void Render_Init(void)
332 {
333         R_Textures_Init();
334         Mod_RenderInit();
335         gl_backend_init();
336         R_MeshQueue_Init();
337         GL_Draw_Init();
338         GL_Main_Init();
339         R_Shadow_Init();
340         GL_Models_Init();
341         R_Sky_Init();
342         GL_Surf_Init();
343         R_Crosshairs_Init();
344         R_Light_Init();
345         R_Particles_Init();
346         R_Explosion_Init();
347         //ui_init();
348         UI_Init();
349         Sbar_Init();
350         R_LightningBeams_Init();
351 }
352
353 /*
354 ===============
355 GL_Init
356 ===============
357 */
358 extern char *ENGINE_EXTENSIONS;
359 void GL_Init (void)
360 {
361         VID_CheckExtensions();
362
363         // LordHavoc: report supported extensions
364         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
365 }
366
367 int R_CullBox(const vec3_t mins, const vec3_t maxs)
368 {
369         int i;
370         mplane_t *p;
371         for (i = 0;i < 4;i++)
372         {
373                 p = frustum + i;
374                 switch(p->signbits)
375                 {
376                 default:
377                 case 0:
378                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
379                                 return true;
380                         break;
381                 case 1:
382                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
383                                 return true;
384                         break;
385                 case 2:
386                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
387                                 return true;
388                         break;
389                 case 3:
390                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
391                                 return true;
392                         break;
393                 case 4:
394                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
395                                 return true;
396                         break;
397                 case 5:
398                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
399                                 return true;
400                         break;
401                 case 6:
402                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
403                                 return true;
404                         break;
405                 case 7:
406                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
407                                 return true;
408                         break;
409                 }
410         }
411         return false;
412 }
413
414 //==================================================================================
415
416 static void R_MarkEntities (void)
417 {
418         int i;
419         entity_render_t *ent;
420
421         ent = &cl_entities[0].render;
422         Matrix4x4_CreateIdentity(&ent->matrix);
423         Matrix4x4_CreateIdentity(&ent->inversematrix);
424
425         if (!r_drawentities.integer)
426                 return;
427
428         for (i = 0;i < r_refdef.numentities;i++)
429         {
430                 ent = r_refdef.entities[i];
431                 Mod_CheckLoaded(ent->model);
432                 // some of the renderer still relies on origin...
433                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
434                 // some of the renderer still relies on scale...
435                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
436                 R_LerpAnimation(ent);
437                 R_UpdateEntLights(ent);
438                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
439                  && !VIS_CullBox(ent->mins, ent->maxs)
440                  && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
441                         ent->visframe = r_framecount;
442         }
443 }
444
445 // only used if skyrendermasked, and normally returns false
446 int R_DrawBrushModelsSky (void)
447 {
448         int i, sky;
449         entity_render_t *ent;
450
451         if (!r_drawentities.integer)
452                 return false;
453
454         sky = false;
455         for (i = 0;i < r_refdef.numentities;i++)
456         {
457                 ent = r_refdef.entities[i];
458                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
459                 {
460                         ent->model->DrawSky(ent);
461                         sky = true;
462                 }
463         }
464         return sky;
465 }
466
467 /*
468 =============
469 R_DrawViewModel
470 =============
471 */
472 /*
473 void R_DrawViewModel (void)
474 {
475         entity_render_t *ent;
476
477         // FIXME: move these checks to client
478         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
479                 return;
480
481         ent = &cl.viewent.render;
482         Mod_CheckLoaded(ent->model);
483         R_LerpAnimation(ent);
484         Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
485         Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
486         R_UpdateEntLights(ent);
487         ent->model->Draw(ent);
488 }
489 */
490
491 void R_DrawNoModel(entity_render_t *ent);
492 void R_DrawModels(void)
493 {
494         int i;
495         entity_render_t *ent;
496
497         if (!r_drawentities.integer)
498                 return;
499
500         for (i = 0;i < r_refdef.numentities;i++)
501         {
502                 ent = r_refdef.entities[i];
503                 if (ent->visframe == r_framecount)
504                 {
505                         if (ent->model && ent->model->Draw != NULL)
506                                 ent->model->Draw(ent);
507                         else
508                                 R_DrawNoModel(ent);
509                 }
510         }
511 }
512
513 static void R_SetFrustum(void)
514 {
515         // break apart the view matrix into vectors for various purposes
516         Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
517         VectorNegate(r_viewleft, r_viewright);
518
519         // LordHavoc: note to all quake engine coders, the special case for 90
520         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
521         // disabled as well.
522
523         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
524         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
525         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
526         PlaneClassify(&frustum[0]);
527
528         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
529         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
530         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
531         PlaneClassify(&frustum[1]);
532
533         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
534         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
535         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
536         PlaneClassify(&frustum[2]);
537
538         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
539         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
540         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
541         PlaneClassify(&frustum[3]);
542 }
543
544 static void R_BlendView(void)
545 {
546         rmeshstate_t m;
547         float r;
548         float vertex3f[3*3];
549
550         if (r_refdef.viewblend[3] < 0.01f)
551                 return;
552
553         R_Mesh_Matrix(&r_identitymatrix);
554
555         memset(&m, 0, sizeof(m));
556         R_Mesh_State_Texture(&m);
557
558         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
559         GL_DepthMask(true);
560         GL_DepthTest(false); // magic
561         GL_VertexPointer(vertex3f);
562         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
563         r = 64;
564         vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
565         vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
566         vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
567         vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
568         vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
569         vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
570         vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
571         vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
572         vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
573         R_Mesh_Draw(3, 1, polygonelements);
574 }
575
576 void R_UpdateWorld(void)
577 {
578         if (!r_refdef.entities/* || !cl.worldmodel*/)
579                 return; //Host_Error ("R_RenderView: NULL worldmodel");
580
581         if (r_shadow_realtime_world.integer && !gl_stencil)
582         {
583                 Con_Printf("Realtime world lighting requires 32bit color; turning off r_shadow_realtime_world, please type vid_bitsperpixel 32;vid_restart and try again\n");
584                 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
585         }
586
587         // don't allow cheats in multiplayer
588         if (!cl.islocalgame)
589         {
590                 if (r_fullbright.integer != 0)
591                         Cvar_Set ("r_fullbright", "0");
592                 if (r_ambient.value != 0)
593                         Cvar_Set ("r_ambient", "0");
594         }
595
596         R_Textures_Frame();
597         R_UpdateFog();
598         R_UpdateLights();
599 }
600
601 void R_RenderScene(void);
602
603 /*
604 ================
605 R_RenderView
606 ================
607 */
608 void R_RenderView(void)
609 {
610         if (!r_refdef.entities/* || !cl.worldmodel*/)
611                 return; //Host_Error ("R_RenderView: NULL worldmodel");
612         
613         r_view_width = bound(0, r_refdef.width, vid.realwidth);
614         r_view_height = bound(0, r_refdef.height, vid.realheight);
615         r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
616         r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
617         r_view_fov_x = bound(1, r_refdef.fov_x, 170);
618         r_view_fov_y = bound(1, r_refdef.fov_y, 170);
619         r_view_matrix = r_refdef.viewentitymatrix;
620
621         // GL is weird because it's bottom to top, r_view_y is top to bottom
622         qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
623         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
624         GL_ScissorTest(true);
625         R_ClearScreen();
626
627         R_Mesh_Start();
628         R_TimeReport("setup");
629
630         qglDepthFunc(GL_LEQUAL);
631         qglPolygonOffset(0, 0);
632         qglEnable(GL_POLYGON_OFFSET_FILL);
633
634         R_RenderScene();
635
636         qglPolygonOffset(0, 0);
637         qglDisable(GL_POLYGON_OFFSET_FILL);
638
639         R_BlendView();
640         R_TimeReport("blendview");
641         
642         R_Mesh_Finish();
643         R_TimeReport("meshfinish");
644
645         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
646         GL_ScissorTest(false);
647 }
648
649 extern void R_DrawLightningBeams (void);
650 void R_RenderScene(void)
651 {
652         entity_render_t *world;
653
654         // don't let sound skip if going slow
655         if (!intimerefresh && !r_speeds.integer)
656                 S_ExtraUpdate ();
657
658         r_framecount++;
659
660         R_SetFrustum();
661
662         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
663         if (gl_stencil && ((r_shadow_realtime_world.integer && r_shadow_worldshadows.integer) || ((r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && r_shadow_dlightshadows.integer)))
664                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
665         else
666                 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
667
668         GL_SetupView_Orientation_FromEntity(&r_view_matrix);
669
670         R_SkyStartFrame();
671
672         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
673                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
674         world = &cl_entities[0].render;
675         R_WorldVisibility(world);
676         R_TimeReport("worldvis");
677
678         R_MarkEntities();
679         R_TimeReport("markentity");
680
681         R_MeshQueue_BeginScene();
682
683         R_Shadow_UpdateWorldLightSelection();
684
685         // don't let sound skip if going slow
686         if (!intimerefresh && !r_speeds.integer)
687                 S_ExtraUpdate ();
688
689         if (R_DrawBrushModelsSky())
690                 R_TimeReport("bmodelsky");
691
692         // must occur early because it can draw sky
693         R_DrawWorld(world);
694         R_TimeReport("world");
695
696         // don't let sound skip if going slow
697         if (!intimerefresh && !r_speeds.integer)
698                 S_ExtraUpdate ();
699
700         R_DrawModels();
701         R_TimeReport("models");
702
703         // don't let sound skip if going slow
704         if (!intimerefresh && !r_speeds.integer)
705                 S_ExtraUpdate ();
706
707         R_ShadowVolumeLighting(false);
708         R_TimeReport("rtlights");
709
710         // don't let sound skip if going slow
711         if (!intimerefresh && !r_speeds.integer)
712                 S_ExtraUpdate ();
713
714         R_DrawLightningBeams();
715         R_TimeReport("lightning");
716
717         R_DrawParticles();
718         R_TimeReport("particles");
719
720         R_DrawExplosions();
721         R_TimeReport("explosions");
722
723         R_MeshQueue_RenderTransparent();
724         R_TimeReport("drawtrans");
725
726         R_DrawCoronas();
727         R_TimeReport("coronas");
728
729         R_DrawWorldCrosshair();
730         R_TimeReport("crosshair");
731
732         R_MeshQueue_Render();
733         R_MeshQueue_EndScene();
734
735         if (r_shadow_visiblevolumes.integer)
736         {
737                 R_ShadowVolumeLighting(true);
738                 R_TimeReport("shadowvolume");
739         }
740
741         // don't let sound skip if going slow
742         if (!intimerefresh && !r_speeds.integer)
743                 S_ExtraUpdate ();
744 }
745
746 /*
747 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
748 {
749         int i;
750         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
751         rmeshstate_t m;
752         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
753         GL_DepthMask(false);
754         GL_DepthTest(true);
755         R_Mesh_Matrix(&r_identitymatrix);
756
757         memset(&m, 0, sizeof(m));
758         R_Mesh_State_Texture(&m);
759
760         R_Mesh_GetSpace(8);
761         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
762         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
763         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
764         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
765         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
766         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
767         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
768         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
769         GL_ColorPointer(color);
770         R_FillColors(color, 8, cr, cg, cb, ca);
771         if (fogenabled)
772         {
773                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
774                 {
775                         VectorSubtract(v, r_vieworigin, diff);
776                         f2 = exp(fogdensity/DotProduct(diff, diff));
777                         f1 = 1 - f2;
778                         c[0] = c[0] * f1 + fogcolor[0] * f2;
779                         c[1] = c[1] * f1 + fogcolor[1] * f2;
780                         c[2] = c[2] * f1 + fogcolor[2] * f2;
781                 }
782         }
783         R_Mesh_Draw(8, 12);
784 }
785 */
786
787 int nomodelelements[24] =
788 {
789         5, 2, 0,
790         5, 1, 2,
791         5, 0, 3,
792         5, 3, 1,
793         0, 2, 4,
794         2, 1, 4,
795         3, 0, 4,
796         1, 3, 4
797 };
798
799 float nomodelvertex3f[6*3] =
800 {
801         -16,   0,   0,
802          16,   0,   0,
803           0, -16,   0,
804           0,  16,   0,
805           0,   0, -16,
806           0,   0,  16
807 };
808
809 float nomodelcolor4f[6*4] =
810 {
811         0.0f, 0.0f, 0.5f, 1.0f,
812         0.0f, 0.0f, 0.5f, 1.0f,
813         0.0f, 0.5f, 0.0f, 1.0f,
814         0.0f, 0.5f, 0.0f, 1.0f,
815         0.5f, 0.0f, 0.0f, 1.0f,
816         0.5f, 0.0f, 0.0f, 1.0f
817 };
818
819 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
820 {
821         const entity_render_t *ent = calldata1;
822         int i;
823         float f1, f2, *c, diff[3];
824         float color4f[6*4];
825         rmeshstate_t m;
826         R_Mesh_Matrix(&ent->matrix);
827
828         memset(&m, 0, sizeof(m));
829         R_Mesh_State_Texture(&m);
830
831         if (ent->flags & EF_ADDITIVE)
832         {
833                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
834                 GL_DepthMask(false);
835         }
836         else if (ent->alpha < 1)
837         {
838                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
839                 GL_DepthMask(false);
840         }
841         else
842         {
843                 GL_BlendFunc(GL_ONE, GL_ZERO);
844                 GL_DepthMask(true);
845         }
846         GL_DepthTest(true);
847         GL_VertexPointer(nomodelvertex3f);
848         if (fogenabled)
849         {
850                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
851                 GL_ColorPointer(color4f);
852                 VectorSubtract(ent->origin, r_vieworigin, diff);
853                 f2 = exp(fogdensity/DotProduct(diff, diff));
854                 f1 = 1 - f2;
855                 for (i = 0, c = color4f;i < 6;i++, c += 4)
856                 {
857                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
858                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
859                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
860                         c[3] *= ent->alpha;
861                 }
862         }
863         else if (ent->alpha != 1)
864         {
865                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
866                 GL_ColorPointer(color4f);
867                 for (i = 0, c = color4f;i < 6;i++, c += 4)
868                         c[3] *= ent->alpha;
869         }
870         else
871                 GL_ColorPointer(nomodelcolor4f);
872         R_Mesh_Draw(6, 8, nomodelelements);
873 }
874
875 void R_DrawNoModel(entity_render_t *ent)
876 {
877         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
878                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
879         //else
880         //      R_DrawNoModelCallback(ent, 0);
881 }
882
883 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
884 {
885         vec3_t right1, right2, diff, normal;
886
887         VectorSubtract (org2, org1, normal);
888         VectorNormalizeFast (normal);
889
890         // calculate 'right' vector for start
891         VectorSubtract (r_vieworigin, org1, diff);
892         VectorNormalizeFast (diff);
893         CrossProduct (normal, diff, right1);
894
895         // calculate 'right' vector for end
896         VectorSubtract (r_vieworigin, org2, diff);
897         VectorNormalizeFast (diff);
898         CrossProduct (normal, diff, right2);
899
900         vert[ 0] = org1[0] + width * right1[0];
901         vert[ 1] = org1[1] + width * right1[1];
902         vert[ 2] = org1[2] + width * right1[2];
903         vert[ 3] = org1[0] - width * right1[0];
904         vert[ 4] = org1[1] - width * right1[1];
905         vert[ 5] = org1[2] - width * right1[2];
906         vert[ 6] = org2[0] - width * right2[0];
907         vert[ 7] = org2[1] - width * right2[1];
908         vert[ 8] = org2[2] - width * right2[2];
909         vert[ 9] = org2[0] + width * right2[0];
910         vert[10] = org2[1] + width * right2[1];
911         vert[11] = org2[2] + width * right2[2];
912 }
913
914 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
915
916 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
917 {
918         float diff[3];
919         rmeshstate_t m;
920
921         if (fogenabled)
922         {
923                 VectorSubtract(origin, r_vieworigin, diff);
924                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
925         }
926
927         R_Mesh_Matrix(&r_identitymatrix);
928         GL_Color(cr, cg, cb, ca);
929         GL_VertexPointer(varray_vertex3f);
930         GL_BlendFunc(blendfunc1, blendfunc2);
931         GL_DepthMask(false);
932         GL_DepthTest(!depthdisable);
933
934         memset(&m, 0, sizeof(m));
935         m.tex[0] = R_GetTexture(texture);
936         m.pointer_texcoord[0] = spritetexcoord2f;
937         R_Mesh_State_Texture(&m);
938
939         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
940         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
941         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
942         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
943         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
944         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
945         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
946         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
947         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
948         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
949         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
950         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
951         R_Mesh_Draw(4, 2, polygonelements);
952 }
953