]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
greatly improved chances of an entity being visible (in traceline test), checks neare...
[divverent/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23
24 //static qboolean       r_cache_thrash;         // compatability
25
26 entity_render_t *currentrenderentity;
27
28 int                     r_framecount;           // used for dlight push checking
29
30 mplane_t        frustum[4];
31
32 int                     c_brush_polys, c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
33
34 qboolean        envmap;                         // true during envmap command capture
35
36 // LordHavoc: moved all code related to particles into r_part.c
37 //int                   particletexture;        // little dot for particles
38 //int                   playertextures;         // up to 16 color translated skins
39
40 //
41 // view origin
42 //
43 vec3_t  vup;
44 vec3_t  vpn;
45 vec3_t  vright;
46 vec3_t  r_origin;
47
48 //float r_world_matrix[16];
49 //float r_base_world_matrix[16];
50
51 //
52 // screen size info
53 //
54 refdef_t        r_refdef;
55
56 mleaf_t         *r_viewleaf, *r_oldviewleaf;
57
58 unsigned short  d_lightstylevalue[256]; // 8.8 fraction of base light value
59
60 //cvar_t        r_norefresh = {0, "r_norefresh","0"};
61 cvar_t  r_drawentities = {0, "r_drawentities","1"};
62 cvar_t  r_drawviewmodel = {0, "r_drawviewmodel","1"};
63 cvar_t  r_speeds = {0, "r_speeds","0"};
64 cvar_t  r_fullbright = {0, "r_fullbright","0"};
65 //cvar_t        r_lightmap = {0, "r_lightmap","0"};
66 cvar_t  r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
67 cvar_t  r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
68 cvar_t  r_waterripple = {CVAR_SAVE, "r_waterripple","0"};
69 cvar_t  r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
70
71 //cvar_t        r_dynamicbothsides = {CVAR_SAVE, "r_dynamicbothsides", "1"}; // LordHavoc: can disable dynamic lighting of backfaces, but quake maps are weird so it doesn't always work right...
72
73 cvar_t  gl_fogenable = {0, "gl_fogenable", "0"};
74 cvar_t  gl_fogdensity = {0, "gl_fogdensity", "0.25"};
75 cvar_t  gl_fogred = {0, "gl_fogred","0.3"};
76 cvar_t  gl_foggreen = {0, "gl_foggreen","0.3"};
77 cvar_t  gl_fogblue = {0, "gl_fogblue","0.3"};
78 cvar_t  gl_fogstart = {0, "gl_fogstart", "0"};
79 cvar_t  gl_fogend = {0, "gl_fogend","0"};
80
81 cvar_t  r_ser = {CVAR_SAVE, "r_ser", "1"};
82 //cvar_t        gl_viewmodeldepthhack = {0, "gl_viewmodeldepthhack", "1"};
83
84 cvar_t r_multitexture = {0, "r_multitexture", "1"};
85
86 /*
87 ====================
88 R_TimeRefresh_f
89
90 For program optimization
91 ====================
92 */
93 qboolean intimerefresh = 0;
94 static void R_TimeRefresh_f (void)
95 {
96         int                     i;
97         float           start, stop, time;
98
99         intimerefresh = 1;
100         start = Sys_DoubleTime ();
101         glDrawBuffer (GL_FRONT);
102         for (i = 0;i < 128;i++)
103         {
104                 r_refdef.viewangles[0] = 0;
105                 r_refdef.viewangles[1] = i/128.0*360.0;
106                 r_refdef.viewangles[2] = 0;
107                 R_RenderView();
108         }
109         glDrawBuffer  (GL_BACK);
110
111         stop = Sys_DoubleTime ();
112         intimerefresh = 0;
113         time = stop-start;
114         Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
115 }
116
117 extern cvar_t r_drawportals;
118
119 int R_VisibleCullBox (vec3_t mins, vec3_t maxs)
120 {
121         int sides;
122         mnode_t *nodestack[8192], *node;
123         int stack = 0;
124
125         if (R_CullBox(mins, maxs))
126                 return true;
127
128         node = cl.worldmodel->nodes;
129 loc0:
130         if (node->contents < 0)
131         {
132                 if (((mleaf_t *)node)->visframe == r_framecount)
133                         return false;
134                 if (!stack)
135                         return true;
136                 node = nodestack[--stack];
137                 goto loc0;
138         }
139
140         sides = BOX_ON_PLANE_SIDE(mins, maxs, node->plane);
141
142 // recurse down the contacted sides
143         if (sides & 1)
144         {
145                 if (sides & 2) // 3
146                 {
147                         // put second child on the stack for later examination
148                         nodestack[stack++] = node->children[1];
149                         node = node->children[0];
150                         goto loc0;
151                 }
152                 else // 1
153                 {
154                         node = node->children[0];
155                         goto loc0;
156                 }
157         }
158         // 2
159         node = node->children[1];
160         goto loc0;
161 }
162
163 vec3_t fogcolor;
164 vec_t fogdensity;
165 float fog_density, fog_red, fog_green, fog_blue;
166 qboolean fogenabled;
167 qboolean oldgl_fogenable;
168 void R_SetupFog(void)
169 {
170         if (gamemode == GAME_NEHAHRA)
171         {
172                 if (gl_fogenable.integer)
173                 {
174                         oldgl_fogenable = true;
175                         fog_density = gl_fogdensity.value;
176                         fog_red = gl_fogred.value;
177                         fog_green = gl_foggreen.value;
178                         fog_blue = gl_fogblue.value;
179                 }
180                 else if (oldgl_fogenable)
181                 {
182                         oldgl_fogenable = false;
183                         fog_density = 0;
184                         fog_red = 0;
185                         fog_green = 0;
186                         fog_blue = 0;
187                 }
188         }
189         if (fog_density)
190         {
191                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
192                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
193                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
194         }
195         if (fog_density)
196         {
197                 fogenabled = true;
198                 fogdensity = -4000.0f / (fog_density * fog_density);
199                 // fog color was already set
200         }
201         else
202                 fogenabled = false;
203 }
204
205 // FIXME: move this to client?
206 void FOG_clear(void)
207 {
208         if (gamemode == GAME_NEHAHRA)
209         {
210                 Cvar_Set("gl_fogenable", "0");
211                 Cvar_Set("gl_fogdensity", "0.2");
212                 Cvar_Set("gl_fogred", "0.3");
213                 Cvar_Set("gl_foggreen", "0.3");
214                 Cvar_Set("gl_fogblue", "0.3");
215         }
216         fog_density = fog_red = fog_green = fog_blue = 0.0f;
217 }
218
219 // FIXME: move this to client?
220 void FOG_registercvars(void)
221 {
222         if (gamemode == GAME_NEHAHRA)
223         {
224                 Cvar_RegisterVariable (&gl_fogenable);
225                 Cvar_RegisterVariable (&gl_fogdensity);
226                 Cvar_RegisterVariable (&gl_fogred);
227                 Cvar_RegisterVariable (&gl_foggreen);
228                 Cvar_RegisterVariable (&gl_fogblue);
229                 Cvar_RegisterVariable (&gl_fogstart);
230                 Cvar_RegisterVariable (&gl_fogend);
231         }
232 }
233
234 void gl_main_start(void)
235 {
236 }
237
238 void gl_main_shutdown(void)
239 {
240 }
241
242 void gl_main_newmap(void)
243 {
244         r_framecount = 1;
245 }
246
247 void GL_Main_Init(void)
248 {
249 // FIXME: move this to client?
250         FOG_registercvars();
251         Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
252         Cvar_RegisterVariable (&r_drawentities);
253         Cvar_RegisterVariable (&r_drawviewmodel);
254         Cvar_RegisterVariable (&r_speeds);
255 //      Cvar_RegisterVariable (&r_dynamicwater);
256 //      Cvar_RegisterVariable (&r_dynamicbothsides);
257         Cvar_RegisterVariable (&r_fullbrights);
258         Cvar_RegisterVariable (&r_wateralpha);
259         Cvar_RegisterVariable (&r_dynamic);
260         Cvar_RegisterVariable (&r_waterripple);
261         Cvar_RegisterVariable (&r_fullbright);
262         Cvar_RegisterVariable (&r_ser);
263 //      Cvar_RegisterVariable (&gl_viewmodeldepthhack);
264         Cvar_RegisterVariable (&r_multitexture);
265         if (gamemode == GAME_NEHAHRA)
266                 Cvar_SetValue("r_fullbrights", 0);
267         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
268 }
269
270 /*
271 ===============
272 R_NewMap
273 ===============
274 */
275 void CL_ParseEntityLump(char *entitystring);
276 void R_NewMap (void)
277 {
278         int             i;
279
280         for (i=0 ; i<256 ; i++)
281                 d_lightstylevalue[i] = 264;             // normal light value
282
283         r_viewleaf = NULL;
284         if (cl.worldmodel->entities)
285                 CL_ParseEntityLump(cl.worldmodel->entities);
286         R_Modules_NewMap();
287 }
288
289 extern void R_Textures_Init(void);
290 extern void Mod_RenderInit(void);
291 extern void GL_Draw_Init(void);
292 extern void GL_Main_Init(void);
293 extern void GL_Models_Init(void);
294 extern void R_Sky_Init(void);
295 extern void GL_Surf_Init(void);
296 extern void R_Crosshairs_Init(void);
297 extern void R_Light_Init(void);
298 extern void R_Particles_Init(void);
299 extern void R_Explosion_Init(void);
300 extern void R_Clip_Init(void);
301 extern void ui_init(void);
302 extern void gl_backend_init(void);
303
304 void Render_Init(void)
305 {
306         R_Modules_Shutdown();
307         R_Textures_Init();
308         Mod_RenderInit();
309         gl_backend_init();
310         R_Clip_Init();
311         GL_Draw_Init();
312         GL_Main_Init();
313         GL_Models_Init();
314         R_Sky_Init();
315         GL_Surf_Init();
316         R_Crosshairs_Init();
317         R_Light_Init();
318         R_Particles_Init();
319         R_Explosion_Init();
320         ui_init();
321         R_Modules_Start();
322 }
323
324 /*
325 ===============
326 GL_Init
327 ===============
328 */
329 extern char *ENGINE_EXTENSIONS;
330 void GL_Init (void)
331 {
332         gl_vendor = glGetString (GL_VENDOR);
333         Con_Printf ("GL_VENDOR: %s\n", gl_vendor);
334         gl_renderer = glGetString (GL_RENDERER);
335         Con_Printf ("GL_RENDERER: %s\n", gl_renderer);
336
337         gl_version = glGetString (GL_VERSION);
338         Con_Printf ("GL_VERSION: %s\n", gl_version);
339         gl_extensions = glGetString (GL_EXTENSIONS);
340         Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions);
341
342 //      Con_Printf ("%s %s\n", gl_renderer, gl_version);
343
344         VID_CheckExtensions();
345
346         // LordHavoc: report supported extensions
347         Con_Printf ("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
348
349         glCullFace(GL_FRONT);
350         glEnable(GL_TEXTURE_2D);
351
352 //      glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
353 }
354
355
356 //==================================================================================
357
358 void R_Entity_Callback(void *data, void *junk)
359 {
360         ((entity_render_t *)data)->visframe = r_framecount;
361 }
362
363 static void R_MarkEntities (void)
364 {
365         int             i;
366         vec3_t  v;
367
368         if (!r_drawentities.integer)
369                 return;
370
371         for (i = 0;i < r_refdef.numentities;i++)
372         {
373                 currentrenderentity = r_refdef.entities[i];
374                 Mod_CheckLoaded(currentrenderentity->model);
375
376                 // move view-relative models to where they should be
377                 if (currentrenderentity->flags & RENDER_VIEWMODEL)
378                 {
379                         // remove flag so it will not be repeated incase RelinkEntities is not called again for a while
380                         currentrenderentity->flags -= RENDER_VIEWMODEL;
381                         // transform origin
382                         VectorCopy(currentrenderentity->origin, v);
383                         currentrenderentity->origin[0] = v[0] * vpn[0] + v[1] * vright[0] + v[2] * vup[0] + r_origin[0];
384                         currentrenderentity->origin[1] = v[0] * vpn[1] + v[1] * vright[1] + v[2] * vup[1] + r_origin[1];
385                         currentrenderentity->origin[2] = v[0] * vpn[2] + v[1] * vright[2] + v[2] * vup[2] + r_origin[2];
386                         // adjust angles
387                         VectorAdd(currentrenderentity->angles, r_refdef.viewangles, currentrenderentity->angles);
388                 }
389
390                 if (currentrenderentity->angles[0] || currentrenderentity->angles[2])
391                 {
392                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->rotatedmins, currentrenderentity->mins);
393                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->rotatedmaxs, currentrenderentity->maxs);
394                 }
395                 else if (currentrenderentity->angles[1])
396                 {
397                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->yawmins, currentrenderentity->mins);
398                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->yawmaxs, currentrenderentity->maxs);
399                 }
400                 else
401                 {
402                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->normalmins, currentrenderentity->mins);
403                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->normalmaxs, currentrenderentity->maxs);
404                 }
405                 if (R_VisibleCullBox(currentrenderentity->mins, currentrenderentity->maxs))
406                         continue;
407
408                 R_LerpAnimation(currentrenderentity);
409                 if (r_ser.integer)
410                         currentrenderentity->model->SERAddEntity();
411                 else
412                         currentrenderentity->visframe = r_framecount;
413         }
414 }
415
416 // only used if skyrendermasked, and normally returns false
417 int R_DrawBModelSky (void)
418 {
419         int             i, sky = false;
420
421         if (!r_drawentities.integer)
422                 return false;
423
424         for (i = 0;i < r_refdef.numentities;i++)
425         {
426                 currentrenderentity = r_refdef.entities[i];
427                 if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->DrawSky)
428                 {
429                         currentrenderentity->model->DrawSky();
430                         sky = true;
431                 }
432         }
433         return sky;
434 }
435
436 void R_DrawModels (void)
437 {
438         int             i;
439
440         if (!r_drawentities.integer)
441                 return;
442
443         for (i = 0;i < r_refdef.numentities;i++)
444         {
445                 currentrenderentity = r_refdef.entities[i];
446                 if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->Draw)
447                         currentrenderentity->model->Draw();
448         }
449 }
450
451 /*
452 =============
453 R_DrawViewModel
454 =============
455 */
456 void R_DrawViewModel (void)
457 {
458         // FIXME: move these checks to client
459         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
460                 return;
461
462         currentrenderentity = &cl.viewent.render;
463         Mod_CheckLoaded(currentrenderentity->model);
464
465         R_LerpAnimation(currentrenderentity);
466
467         // hack the depth range to prevent view model from poking into walls
468 //      if (gl_viewmodeldepthhack.integer)
469 //      {
470 //              R_Mesh_Render();
471 //              glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
472 //      }
473         currentrenderentity->model->Draw();
474 //      if (gl_viewmodeldepthhack.integer)
475 //      {
476 //              R_Mesh_Render();
477 //              glDepthRange (gldepthmin, gldepthmax);
478 //      }
479 }
480
481 static void R_SetFrustum (void)
482 {
483         int             i;
484
485         // LordHavoc: note to all quake engine coders, the special case for 90
486         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
487         // disabled as well.
488         // rotate VPN right by FOV_X/2 degrees
489         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
490         // rotate VPN left by FOV_X/2 degrees
491         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
492         // rotate VPN up by FOV_X/2 degrees
493         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
494         // rotate VPN down by FOV_X/2 degrees
495         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
496
497
498         for (i=0 ; i<4 ; i++)
499         {
500                 frustum[i].type = PLANE_ANYZ;
501                 frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
502                 PlaneClassify(&frustum[i]);
503         }
504 }
505
506 /*
507 ===============
508 R_SetupFrame
509 ===============
510 */
511 static void R_SetupFrame (void)
512 {
513 // don't allow cheats in multiplayer
514         if (cl.maxclients > 1)
515         {
516                 if (r_fullbright.integer != 0)
517                         Cvar_Set ("r_fullbright", "0");
518                 if (r_ambient.value != 0)
519                         Cvar_Set ("r_ambient", "0");
520         }
521         if (r_multitexture.integer && gl_textureunits < 2)
522                 Cvar_SetValue("r_multitexture", 0);
523
524         r_framecount++;
525
526 // build the transformation matrix for the given view angles
527         VectorCopy (r_refdef.vieworg, r_origin);
528
529         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
530
531 // current viewleaf
532         r_oldviewleaf = r_viewleaf;
533         r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
534
535 //      r_cache_thrash = false;
536
537         R_AnimateLight ();
538 }
539
540
541 static int blendviewpolyindex[3] = {0, 1, 2};
542
543 static void R_BlendView(void)
544 {
545         rmeshinfo_t m;
546         float tvxyz[3][4], r;
547
548         if (!r_render.integer)
549                 return;
550
551         if (r_refdef.viewblend[3] < 0.01f)
552                 return;
553
554         memset(&m, 0, sizeof(m));
555         m.transparent = false;
556         m.blendfunc1 = GL_SRC_ALPHA;
557         m.blendfunc2 = GL_ONE;
558         m.depthdisable = true; // magic
559         m.numtriangles = 1;
560         m.numverts = 3;
561         m.index = blendviewpolyindex;
562         m.vertex = &tvxyz[0][0];
563         m.vertexstep = sizeof(float[4]);
564         m.cr = r_refdef.viewblend[0];
565         m.cg = r_refdef.viewblend[1];
566         m.cb = r_refdef.viewblend[2];
567         m.ca = r_refdef.viewblend[3];
568         r = 64000;
569         tvxyz[0][0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
570         tvxyz[0][1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
571         tvxyz[0][2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
572         r *= 3;
573         tvxyz[1][0] = tvxyz[0][0] + vup[0] * r;
574         tvxyz[1][1] = tvxyz[0][1] + vup[1] * r;
575         tvxyz[1][2] = tvxyz[0][2] + vup[2] * r;
576         tvxyz[2][0] = tvxyz[0][0] + vright[0] * r;
577         tvxyz[2][1] = tvxyz[0][1] + vright[1] * r;
578         tvxyz[2][2] = tvxyz[0][2] + vright[2] * r;
579         R_Mesh_Draw(&m);
580
581         /*
582         glMatrixMode(GL_PROJECTION);
583         glLoadIdentity ();
584         glOrtho  (0, 1, 1, 0, -99999, 99999);
585         glMatrixMode(GL_MODELVIEW);
586         glLoadIdentity ();
587         glDisable (GL_DEPTH_TEST);
588         glDisable (GL_CULL_FACE);
589         glDisable(GL_TEXTURE_2D);
590         glEnable(GL_BLEND);
591         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
592         glBegin (GL_TRIANGLES);
593         glColor4f (r_refdef.viewblend[0] * overbrightscale, r_refdef.viewblend[1] * overbrightscale, r_refdef.viewblend[2] * overbrightscale, r_refdef.viewblend[3]);
594         glVertex2f (-5, -5);
595         glVertex2f (10, -5);
596         glVertex2f (-5, 10);
597         glEnd ();
598
599         glEnable (GL_CULL_FACE);
600         glEnable (GL_DEPTH_TEST);
601         glDisable(GL_BLEND);
602         glEnable(GL_TEXTURE_2D);
603         */
604 }
605
606 /*
607 ================
608 R_RenderView
609
610 r_refdef must be set before the first call
611 ================
612 */
613 void R_RenderView (void)
614 {
615         if (!cl.worldmodel)
616                 return; //Host_Error ("R_RenderView: NULL worldmodel");
617
618         // FIXME: move to client
619         R_MoveExplosions();
620         R_TimeReport("mexplosion");
621
622         R_SetupFrame();
623         R_SetFrustum();
624         R_SetupFog();
625         R_SkyStartFrame();
626         if (r_ser.integer)
627                 R_Clip_StartFrame();
628         R_BuildLightList();
629
630         R_Mesh_Start();
631
632         R_TimeReport("setup");
633
634         R_DrawWorld();
635         R_TimeReport("worldnode");
636
637         R_MarkEntities();
638         R_TimeReport("markentity");
639
640         if (r_ser.integer)
641         {
642                 R_Clip_EndFrame();
643                 R_TimeReport("hiddensurf");
644         }
645
646         R_MarkWorldLights();
647         R_TimeReport("marklights");
648
649         if (skyrendermasked)
650         {
651                 if (R_DrawBModelSky())
652                         R_TimeReport("bmodelsky");
653         }
654         else
655         {
656                 R_DrawViewModel();
657                 R_TimeReport("viewmodel");
658         }
659
660         R_SetupForWorldRendering();
661         R_PrepareSurfaces();
662         R_TimeReport("surfprep");
663
664         R_DrawSurfaces(SHADERSTAGE_SKY);
665         R_DrawSurfaces(SHADERSTAGE_NORMAL);
666         R_DrawSurfaces(SHADERSTAGE_FOG);
667         R_TimeReport("surfdraw");
668
669         if (r_drawportals.integer)
670         {
671                 R_DrawPortals();
672                 R_TimeReport("portals");
673         }
674
675         // don't let sound skip if going slow
676         if (!intimerefresh && !r_speeds.integer)
677                 S_ExtraUpdate ();
678
679         if (skyrendermasked)
680         {
681                 R_DrawViewModel();
682                 R_TimeReport("viewmodel");
683         }
684
685         R_DrawModels();
686         R_TimeReport("models");
687
688         R_DrawParticles();
689         R_TimeReport("particles");
690
691         R_DrawExplosions();
692         R_TimeReport("explosions");
693
694         // draw transparent meshs
695         R_Mesh_AddTransparent();
696         R_TimeReport("addtrans");
697
698         R_DrawCoronas();
699         R_TimeReport("coronas");
700
701         R_BlendView();
702         R_TimeReport("blendview");
703
704         // render any queued meshs
705         R_Mesh_Finish();
706         R_TimeReport("meshfinish");
707
708         //Mem_CheckSentinelsGlobal();
709         //R_TimeReport("memtest");
710 }