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