]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
A couple of minor simplifications in the screenshot / video code
[divverent/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #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
630         // GL is weird because it's bottom to top, r_view_y is top to bottom
631         qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
632         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
633         GL_ScissorTest(true);
634         R_ClearScreen();
635         R_TimeReport("setup");
636
637         qglDepthFunc(GL_LEQUAL);
638         qglPolygonOffset(0, 0);
639         qglEnable(GL_POLYGON_OFFSET_FILL);
640
641         R_RenderScene();
642
643         qglPolygonOffset(0, 0);
644         qglDisable(GL_POLYGON_OFFSET_FILL);
645
646         R_BlendView();
647         R_TimeReport("blendview");
648         
649         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
650         GL_ScissorTest(false);
651 }
652
653 extern void R_DrawLightningBeams (void);
654 void R_RenderScene(void)
655 {
656         entity_render_t *world;
657         
658         // don't let sound skip if going slow
659         if (!intimerefresh && !r_speeds.integer)
660                 S_ExtraUpdate ();
661
662         r_framecount++;
663
664         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
665
666         R_SetFrustum();
667
668         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
669         if (gl_stencil && (r_shadow_realtime_world.integer || (r_shadow_realtime_dlight.integer && r_shadow_realtime_dlight_shadows.integer)))
670                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
671         else
672                 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
673
674         GL_SetupView_Orientation_FromEntity(&r_view_matrix);
675
676         R_SkyStartFrame();
677
678         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
679                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
680         world = &cl_entities[0].render;
681         R_WorldVisibility(world);
682         R_TimeReport("worldvis");
683
684         R_MarkEntities();
685         R_TimeReport("markentity");
686
687         R_MeshQueue_BeginScene();
688
689         R_Shadow_UpdateWorldLightSelection();
690
691         // don't let sound skip if going slow
692         if (!intimerefresh && !r_speeds.integer)
693                 S_ExtraUpdate ();
694
695         GL_ShowTrisColor(0.025, 0.025, 0, 1);
696         if (world->model && world->model->DrawSky)
697         {
698                 world->model->DrawSky(world);
699                 R_TimeReport("worldsky");
700         }
701
702         if (R_DrawBrushModelsSky())
703                 R_TimeReport("bmodelsky");
704
705         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
706         if (world->model && world->model->Draw)
707         {
708                 world->model->Draw(world);
709                 R_TimeReport("world");
710         }
711
712         // don't let sound skip if going slow
713         if (!intimerefresh && !r_speeds.integer)
714                 S_ExtraUpdate ();
715
716         GL_ShowTrisColor(0, 0.015, 0, 1);
717
718         R_DrawModels();
719         R_TimeReport("models");
720
721         // don't let sound skip if going slow
722         if (!intimerefresh && !r_speeds.integer)
723                 S_ExtraUpdate ();
724
725         GL_ShowTrisColor(0, 0, 0.033, 1);
726         R_ShadowVolumeLighting(false);
727         R_TimeReport("rtlights");
728
729         // don't let sound skip if going slow
730         if (!intimerefresh && !r_speeds.integer)
731                 S_ExtraUpdate ();
732
733         GL_ShowTrisColor(0.1, 0, 0, 1);
734
735         R_DrawLightningBeams();
736         R_TimeReport("lightning");
737
738         R_DrawParticles();
739         R_TimeReport("particles");
740
741         R_DrawExplosions();
742         R_TimeReport("explosions");
743
744         R_MeshQueue_RenderTransparent();
745         R_TimeReport("drawtrans");
746
747         R_DrawCoronas();
748         R_TimeReport("coronas");
749
750         R_DrawWorldCrosshair();
751         R_TimeReport("crosshair");
752
753         R_MeshQueue_Render();
754         R_MeshQueue_EndScene();
755
756         if (r_shadow_visiblevolumes.integer && !r_showtrispass)
757         {
758                 R_ShadowVolumeLighting(true);
759                 R_TimeReport("shadowvolume");
760         }
761
762         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
763
764         // don't let sound skip if going slow
765         if (!intimerefresh && !r_speeds.integer)
766                 S_ExtraUpdate ();
767 }
768
769 /*
770 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
771 {
772         int i;
773         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
774         rmeshstate_t m;
775         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
776         GL_DepthMask(false);
777         GL_DepthTest(true);
778         R_Mesh_Matrix(&r_identitymatrix);
779
780         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
781         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
782         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
783         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
784         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
785         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
786         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
787         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
788         R_FillColors(color, 8, cr, cg, cb, ca);
789         if (fogenabled)
790         {
791                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
792                 {
793                         VectorSubtract(v, r_vieworigin, diff);
794                         f2 = exp(fogdensity/DotProduct(diff, diff));
795                         f1 = 1 - f2;
796                         c[0] = c[0] * f1 + fogcolor[0] * f2;
797                         c[1] = c[1] * f1 + fogcolor[1] * f2;
798                         c[2] = c[2] * f1 + fogcolor[2] * f2;
799                 }
800         }
801         memset(&m, 0, sizeof(m));
802         m.pointer_vertex = vertex3f;
803         m.pointer_color = color;
804         R_Mesh_State(&m);
805         R_Mesh_Draw(8, 12);
806 }
807 */
808
809 int nomodelelements[24] =
810 {
811         5, 2, 0,
812         5, 1, 2,
813         5, 0, 3,
814         5, 3, 1,
815         0, 2, 4,
816         2, 1, 4,
817         3, 0, 4,
818         1, 3, 4
819 };
820
821 float nomodelvertex3f[6*3] =
822 {
823         -16,   0,   0,
824          16,   0,   0,
825           0, -16,   0,
826           0,  16,   0,
827           0,   0, -16,
828           0,   0,  16
829 };
830
831 float nomodelcolor4f[6*4] =
832 {
833         0.0f, 0.0f, 0.5f, 1.0f,
834         0.0f, 0.0f, 0.5f, 1.0f,
835         0.0f, 0.5f, 0.0f, 1.0f,
836         0.0f, 0.5f, 0.0f, 1.0f,
837         0.5f, 0.0f, 0.0f, 1.0f,
838         0.5f, 0.0f, 0.0f, 1.0f
839 };
840
841 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
842 {
843         const entity_render_t *ent = calldata1;
844         int i;
845         float f1, f2, *c, diff[3];
846         float color4f[6*4];
847         rmeshstate_t m;
848         R_Mesh_Matrix(&ent->matrix);
849
850         memset(&m, 0, sizeof(m));
851         m.pointer_vertex = nomodelvertex3f;
852
853         if (ent->flags & EF_ADDITIVE)
854         {
855                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
856                 GL_DepthMask(false);
857         }
858         else if (ent->alpha < 1)
859         {
860                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
861                 GL_DepthMask(false);
862         }
863         else
864         {
865                 GL_BlendFunc(GL_ONE, GL_ZERO);
866                 GL_DepthMask(true);
867         }
868         GL_DepthTest(true);
869         if (fogenabled)
870         {
871                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
872                 m.pointer_color = color4f;
873                 VectorSubtract(ent->origin, r_vieworigin, diff);
874                 f2 = exp(fogdensity/DotProduct(diff, diff));
875                 f1 = 1 - f2;
876                 for (i = 0, c = color4f;i < 6;i++, c += 4)
877                 {
878                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
879                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
880                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
881                         c[3] *= ent->alpha;
882                 }
883         }
884         else if (ent->alpha != 1)
885         {
886                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
887                 m.pointer_color = color4f;
888                 for (i = 0, c = color4f;i < 6;i++, c += 4)
889                         c[3] *= ent->alpha;
890         }
891         else
892                 m.pointer_color = nomodelcolor4f;
893         R_Mesh_State(&m);
894         R_Mesh_Draw(6, 8, nomodelelements);
895 }
896
897 void R_DrawNoModel(entity_render_t *ent)
898 {
899         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
900                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
901         //else
902         //      R_DrawNoModelCallback(ent, 0);
903 }
904
905 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
906 {
907         vec3_t right1, right2, diff, normal;
908
909         VectorSubtract (org2, org1, normal);
910         VectorNormalizeFast (normal);
911
912         // calculate 'right' vector for start
913         VectorSubtract (r_vieworigin, org1, diff);
914         VectorNormalizeFast (diff);
915         CrossProduct (normal, diff, right1);
916
917         // calculate 'right' vector for end
918         VectorSubtract (r_vieworigin, org2, diff);
919         VectorNormalizeFast (diff);
920         CrossProduct (normal, diff, right2);
921
922         vert[ 0] = org1[0] + width * right1[0];
923         vert[ 1] = org1[1] + width * right1[1];
924         vert[ 2] = org1[2] + width * right1[2];
925         vert[ 3] = org1[0] - width * right1[0];
926         vert[ 4] = org1[1] - width * right1[1];
927         vert[ 5] = org1[2] - width * right1[2];
928         vert[ 6] = org2[0] - width * right2[0];
929         vert[ 7] = org2[1] - width * right2[1];
930         vert[ 8] = org2[2] - width * right2[2];
931         vert[ 9] = org2[0] + width * right2[0];
932         vert[10] = org2[1] + width * right2[1];
933         vert[11] = org2[2] + width * right2[2];
934 }
935
936 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
937
938 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)
939 {
940         float diff[3];
941         rmeshstate_t m;
942
943         if (fogenabled)
944         {
945                 VectorSubtract(origin, r_vieworigin, diff);
946                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
947         }
948
949         R_Mesh_Matrix(&r_identitymatrix);
950         GL_BlendFunc(blendfunc1, blendfunc2);
951         GL_DepthMask(false);
952         GL_DepthTest(!depthdisable);
953
954         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
955         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
956         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
957         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
958         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
959         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
960         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
961         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
962         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
963         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
964         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
965         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
966
967         memset(&m, 0, sizeof(m));
968         m.tex[0] = R_GetTexture(texture);
969         m.pointer_texcoord[0] = spritetexcoord2f;
970         m.pointer_vertex = varray_vertex3f;
971         R_Mesh_State(&m);
972         GL_Color(cr, cg, cb, ca);
973         R_Mesh_Draw(4, 2, polygonelements);
974 }
975