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