]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_screen.c
9b2a7b22c2da6c43b087fb3c4ff667f06e2bde24
[divverent/darkplaces.git] / gl_screen.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
21 // screen.c -- master for refresh, status bar, console, chat, notify, etc
22
23 #include "quakedef.h"
24
25 /*
26
27 background clear
28 rendering
29 turtle/net/ram icons
30 sbar
31 centerprint / slow centerprint
32 notify lines
33 intermission / finale overlay
34 loading plaque
35 console
36 menu
37
38 required background clears
39 required update regions
40
41
42 syncronous draw mode or async
43 One off screen buffer, with updates either copied or xblited
44 Need to double buffer?
45
46
47 async draw will require the refresh area to be cleared, because it will be
48 xblited, but sync draw can just ignore it.
49
50 sync
51 draw
52
53 CenterPrint ()
54 SlowPrint ()
55 Screen_Update ();
56 Con_Printf ();
57
58 net 
59 turn off messages option
60
61 the refresh is always rendered, unless the console is full screen
62
63
64 console is:
65         notify lines
66         half
67         full
68         
69
70 */
71
72
73 int             glx, gly, glwidth, glheight;
74
75 float   scr_con_current;
76 float   scr_conlines;           // lines of console to display
77
78 float   oldscreensize, oldfov;
79 cvar_t  scr_viewsize = {"viewsize","100", true};
80 cvar_t  scr_fov = {"fov","90"}; // 10 - 170
81 cvar_t  scr_conspeed = {"scr_conspeed","300"};
82 cvar_t  scr_centertime = {"scr_centertime","2"};
83 cvar_t  scr_showram = {"showram","1"};
84 cvar_t  scr_showturtle = {"showturtle","0"};
85 cvar_t  scr_showpause = {"showpause","1"};
86 cvar_t  scr_printspeed = {"scr_printspeed","8"};
87 cvar_t  showfps = {"showfps", "0", true};
88 cvar_t  r_render = {"r_render", "1"};
89 cvar_t  r_brightness = {"r_brightness", "1", true}; // LordHavoc: a method of operating system independent color correction
90 cvar_t  r_contrast = {"r_contrast", "1", true}; // LordHavoc: a method of operating system independent color correction
91
92 qboolean        scr_initialized;                // ready to draw
93
94 qpic_t          *scr_ram;
95 qpic_t          *scr_net;
96 qpic_t          *scr_turtle;
97
98 int                     clearconsole;
99 int                     clearnotify;
100
101 qboolean        scr_disabled_for_loading;
102 //qboolean      scr_drawloading;
103 //float         scr_disabled_time;
104
105 void SCR_ScreenShot_f (void);
106
107 /*
108 ===============================================================================
109
110 CENTER PRINTING
111
112 ===============================================================================
113 */
114
115 char            scr_centerstring[1024];
116 float           scr_centertime_start;   // for slow victory printing
117 float           scr_centertime_off;
118 int                     scr_center_lines;
119 int                     scr_erase_lines;
120 int                     scr_erase_center;
121
122 /*
123 ==============
124 SCR_CenterPrint
125
126 Called for important messages that should stay in the center of the screen
127 for a few moments
128 ==============
129 */
130 void SCR_CenterPrint (char *str)
131 {
132         strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
133         scr_centertime_off = scr_centertime.value;
134         scr_centertime_start = cl.time;
135
136 // count the number of lines for centering
137         scr_center_lines = 1;
138         while (*str)
139         {
140                 if (*str == '\n')
141                         scr_center_lines++;
142                 str++;
143         }
144 }
145
146
147 void SCR_DrawCenterString (void)
148 {
149         char    *start;
150         int             l;
151         int             x, y;
152         int             remaining;
153
154 // the finale prints the characters one at a time
155         if (cl.intermission)
156                 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
157         else
158                 remaining = 9999;
159
160         scr_erase_center = 0;
161         start = scr_centerstring;
162
163         if (scr_center_lines <= 4)
164                 y = vid.height*0.35;
165         else
166                 y = 48;
167
168         do      
169         {
170         // scan the width of the line
171                 for (l=0 ; l<40 ; l++)
172                         if (start[l] == '\n' || !start[l])
173                                 break;
174                 x = (vid.width - l*8)/2;
175                 // LordHavoc: speedup
176                 if (l > 0)
177                 {
178                         if (remaining < l)
179                                 l = remaining;
180                         Draw_String(x, y, start, l);
181                         remaining -= l;
182                         if (remaining <= 0)
183                                 return;
184                 }
185                 /*
186                 for (j=0 ; j<l ; j++, x+=8)
187                 {
188                         Draw_Character (x, y, start[j]);        
189                         if (!remaining--)
190                                 return;
191                 }
192                 */
193                         
194                 y += 8;
195
196                 while (*start && *start != '\n')
197                         start++;
198
199                 if (!*start)
200                         break;
201                 start++;                // skip the \n
202         } while (1);
203 }
204
205 void SCR_CheckDrawCenterString (void)
206 {
207         if (scr_center_lines > scr_erase_lines)
208                 scr_erase_lines = scr_center_lines;
209
210         scr_centertime_off -= host_frametime;
211         
212         if (scr_centertime_off <= 0 && !cl.intermission)
213                 return;
214         if (key_dest != key_game)
215                 return;
216
217         SCR_DrawCenterString ();
218 }
219
220 //=============================================================================
221
222 /*
223 ====================
224 CalcFov
225 ====================
226 */
227 float CalcFov (float fov_x, float width, float height)
228 {
229         float   a;
230         float   x;
231
232         if (fov_x < 1 || fov_x > 179)
233                 Sys_Error ("Bad fov: %f", fov_x);
234
235         x = width/tan(fov_x/360*M_PI);
236
237         a = atan (height/x);
238
239         a = a*360/M_PI;
240
241         return a;
242 }
243
244 /*
245 =================
246 SCR_CalcRefdef
247
248 Must be called whenever vid changes
249 Internal use only
250 =================
251 */
252 static void SCR_CalcRefdef (void)
253 {
254         float           size;
255         int             h;
256         qboolean                full = false;
257
258
259         vid.recalc_refdef = 0;
260
261 //========================================
262         
263 // bound viewsize
264         if (scr_viewsize.value < 30)
265                 Cvar_Set ("viewsize","30");
266         if (scr_viewsize.value > 120)
267                 Cvar_Set ("viewsize","120");
268
269 // bound field of view
270         if (scr_fov.value < 10)
271                 Cvar_Set ("fov","10");
272         if (scr_fov.value > 170)
273                 Cvar_Set ("fov","170");
274
275 // intermission is always full screen   
276         if (cl.intermission)
277                 size = 120;
278         else
279                 size = scr_viewsize.value;
280
281         if (size >= 120)
282                 sb_lines = 0;           // no status bar at all
283         else if (size >= 110)
284                 sb_lines = 24;          // no inventory
285         else
286                 sb_lines = 24+16+8;
287
288         if (scr_viewsize.value >= 100.0)
289         {
290                 full = true;
291                 size = 100.0;
292         }
293         else
294                 size = scr_viewsize.value;
295         if (cl.intermission)
296         {
297                 full = true;
298                 size = 100;
299                 sb_lines = 0;
300         }
301         size /= 100.0;
302
303         // LordHavoc: always fullyscreen rendering
304         h = vid.height/* - sb_lines*/;
305
306         r_refdef.vrect.width = vid.width * size;
307         if (r_refdef.vrect.width < 96)
308         {
309                 size = 96.0 / r_refdef.vrect.width;
310                 r_refdef.vrect.width = 96;      // min for icons
311         }
312
313         r_refdef.vrect.height = vid.height * size;
314         //if (r_refdef.vrect.height > vid.height - sb_lines)
315         //      r_refdef.vrect.height = vid.height - sb_lines;
316         if (r_refdef.vrect.height > (int) vid.height)
317                         r_refdef.vrect.height = vid.height;
318         r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
319         if (full)
320                 r_refdef.vrect.y = 0;
321         else 
322                 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
323
324         r_refdef.fov_x = scr_fov.value;
325         r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
326 }
327
328
329 /*
330 =================
331 SCR_SizeUp_f
332
333 Keybinding command
334 =================
335 */
336 void SCR_SizeUp_f (void)
337 {
338         Cvar_SetValue ("viewsize",scr_viewsize.value+10);
339         vid.recalc_refdef = 1;
340 }
341
342
343 /*
344 =================
345 SCR_SizeDown_f
346
347 Keybinding command
348 =================
349 */
350 void SCR_SizeDown_f (void)
351 {
352         Cvar_SetValue ("viewsize",scr_viewsize.value-10);
353         vid.recalc_refdef = 1;
354 }
355
356 //============================================================================
357
358 void gl_screen_start()
359 {
360         scr_ram = Draw_PicFromWad ("ram");
361         scr_net = Draw_PicFromWad ("net");
362         scr_turtle = Draw_PicFromWad ("turtle");
363 }
364
365 void gl_screen_shutdown()
366 {
367 }
368
369 void gl_screen_newmap()
370 {
371 }
372
373 /*
374 ==================
375 SCR_Init
376 ==================
377 */
378 void GL_Screen_Init (void)
379 {
380
381         Cvar_RegisterVariable (&scr_fov);
382         Cvar_RegisterVariable (&scr_viewsize);
383         Cvar_RegisterVariable (&scr_conspeed);
384         Cvar_RegisterVariable (&scr_showram);
385         Cvar_RegisterVariable (&scr_showturtle);
386         Cvar_RegisterVariable (&scr_showpause);
387         Cvar_RegisterVariable (&scr_centertime);
388         Cvar_RegisterVariable (&scr_printspeed);
389         Cvar_RegisterVariable (&showfps);
390         Cvar_RegisterVariable (&r_render);
391         Cvar_RegisterVariable (&r_brightness);
392         Cvar_RegisterVariable (&r_contrast);
393 #ifdef NORENDER
394         r_render.value = 0;
395 #endif
396
397 //
398 // register our commands
399 //
400         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
401         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
402         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
403
404         scr_initialized = true;
405
406         R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
407 }
408
409
410
411 /*
412 ==============
413 SCR_DrawRam
414 ==============
415 */
416 void SCR_DrawRam (void)
417 {
418         if (!scr_showram.value)
419                 return;
420
421         if (!r_cache_thrash)
422                 return;
423
424         Draw_Pic (32, 0, scr_ram);
425 }
426
427 /*
428 ==============
429 SCR_DrawTurtle
430 ==============
431 */
432 void SCR_DrawTurtle (void)
433 {
434         static int      count;
435         
436         if (!scr_showturtle.value)
437                 return;
438
439         if (cl.frametime < 0.1)
440         {
441                 count = 0;
442                 return;
443         }
444
445         count++;
446         if (count < 3)
447                 return;
448
449         Draw_Pic (0, 0, scr_turtle);
450 }
451
452 /*
453 ==============
454 SCR_DrawNet
455 ==============
456 */
457 void SCR_DrawNet (void)
458 {
459         if (realtime - cl.last_received_message < 0.3)
460                 return;
461         if (cls.demoplayback)
462                 return;
463
464         Draw_Pic (64, 0, scr_net);
465 }
466
467 /*
468 ==============
469 DrawPause
470 ==============
471 */
472 void SCR_DrawPause (void)
473 {
474         qpic_t  *pic;
475
476         if (!scr_showpause.value)               // turn off for screenshots
477                 return;
478
479         if (!cl.paused)
480                 return;
481
482         pic = Draw_CachePic ("gfx/pause.lmp");
483         Draw_Pic ( (vid.width - pic->width)/2, 
484                 (vid.height - 48 - pic->height)/2, pic);
485 }
486
487
488
489 /*
490 ==============
491 SCR_DrawLoading
492 ==============
493 */
494 /*
495 void SCR_DrawLoading (void)
496 {
497         qpic_t  *pic;
498
499         if (!scr_drawloading)
500                 return;
501                 
502         pic = Draw_CachePic ("gfx/loading.lmp");
503         Draw_Pic ( (vid.width - pic->width)/2, 
504                 (vid.height - 48 - pic->height)/2, pic);
505 }
506 */
507
508
509
510 //=============================================================================
511
512
513 /*
514 ==================
515 SCR_SetUpToDrawConsole
516 ==================
517 */
518 void SCR_SetUpToDrawConsole (void)
519 {
520         Con_CheckResize ();
521         
522         //if (scr_drawloading)
523         //      return;         // never a console with loading plaque
524
525 // decide on the height of the console
526         con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
527
528         if (con_forcedup)
529         {
530                 scr_conlines = vid.height;              // full screen
531                 scr_con_current = scr_conlines;
532         }
533         else if (key_dest == key_console)
534                 scr_conlines = vid.height/2;    // half screen
535         else
536                 scr_conlines = 0;                               // none visible
537         
538         if (scr_conlines < scr_con_current)
539         {
540                 scr_con_current -= scr_conspeed.value*host_realframetime;
541                 if (scr_conlines > scr_con_current)
542                         scr_con_current = scr_conlines;
543
544         }
545         else if (scr_conlines > scr_con_current)
546         {
547                 scr_con_current += scr_conspeed.value*host_realframetime;
548                 if (scr_conlines < scr_con_current)
549                         scr_con_current = scr_conlines;
550         }
551 }
552         
553 /*
554 ==================
555 SCR_DrawConsole
556 ==================
557 */
558 void SCR_DrawConsole (void)
559 {
560         if (scr_con_current)
561         {
562                 Con_DrawConsole (scr_con_current, true);
563                 clearconsole = 0;
564         }
565         else
566         {
567                 if (key_dest == key_game || key_dest == key_message)
568                         Con_DrawNotify ();      // only draw notify in game
569         }
570 }
571
572
573 /* 
574 ============================================================================== 
575  
576                                                 SCREEN SHOTS 
577  
578 ============================================================================== 
579 */ 
580
581 /*
582 ================== 
583 SCR_ScreenShot_f
584 ================== 
585 */
586 void SCR_ScreenShot_f (void) 
587 {
588         byte            *buffer;
589         char            filename[80]; 
590         char            checkname[MAX_OSPATH];
591         int                     i;
592 // 
593 // find a file name to save it to 
594 // 
595         strcpy(filename,"dp0000.tga");
596                 
597         for (i=0 ; i<=9999 ; i++) 
598         { 
599                 filename[2] = (i/1000)%10 + '0'; 
600                 filename[3] = (i/ 100)%10 + '0'; 
601                 filename[4] = (i/  10)%10 + '0'; 
602                 filename[5] = (i/   1)%10 + '0'; 
603                 sprintf (checkname, "%s/%s", com_gamedir, filename);
604                 if (Sys_FileTime(checkname) == -1)
605                         break;  // file doesn't exist
606         } 
607         if (i==10000)
608         {
609                 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); 
610                 return;
611         }
612
613         buffer = qmalloc(glwidth*glheight*3);
614         glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer); 
615         Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
616
617         qfree(buffer);
618         Con_Printf ("Wrote %s\n", filename);
619 }
620
621
622 //=============================================================================
623
624
625 /*
626 ===============
627 SCR_BeginLoadingPlaque
628
629 ================
630 */
631 /*
632 void SCR_BeginLoadingPlaque (void)
633 {
634         S_StopAllSounds (true);
635
636 //      if (cls.state != ca_connected)
637 //              return;
638 //      if (cls.signon != SIGNONS)
639 //              return;
640         
641 // redraw with no console and the loading plaque
642 //      Con_ClearNotify ();
643 //      scr_centertime_off = 0;
644 //      scr_con_current = 0;
645
646         scr_drawloading = true;
647         SCR_UpdateScreen ();
648
649 //      scr_disabled_for_loading = true;
650 //      scr_disabled_time = realtime;
651 }
652 */
653
654 /*
655 ===============
656 SCR_EndLoadingPlaque
657
658 ================
659 */
660 /*
661 void SCR_EndLoadingPlaque (void)
662 {
663 //      scr_disabled_for_loading = false;
664         scr_drawloading = false;
665         Con_ClearNotify ();
666 }
667 */
668
669 //=============================================================================
670
671 char    *scr_notifystring;
672
673 void SCR_DrawNotifyString (void)
674 {
675         char    *start;
676         int             l;
677         int             x, y;
678
679         start = scr_notifystring;
680
681         y = vid.height*0.35;
682
683         do      
684         {
685         // scan the width of the line
686                 for (l=0 ; l<40 ; l++)
687                         if (start[l] == '\n' || !start[l])
688                                 break;
689                 x = (vid.width - l*8)/2;
690                 // LordHavoc: speedup
691 //              for (j=0 ; j<l ; j++, x+=8)
692 //                      Draw_Character (x, y, start[j]);        
693                 Draw_String (x, y, start, l);
694                         
695                 y += 8;
696
697                 while (*start && *start != '\n')
698                         start++;
699
700                 if (!*start)
701                         break;
702                 start++;                // skip the \n
703         } while (1);
704 }
705
706 //=============================================================================
707
708 void DrawCrosshair(int num);
709 void GL_Set2D (void);
710
711 extern void SHOWLMP_drawall();
712 extern cvar_t r_speeds2;
713
714 void GL_BrightenScreen()
715 {
716         float f;
717
718         if (r_brightness.value < 0.1f)
719                 Cvar_SetValue("r_brightness", 0.1f);
720         if (r_brightness.value > 5.0f)
721                 Cvar_SetValue("r_brightness", 5.0f);
722
723         if (r_contrast.value < 0.2f)
724                 Cvar_SetValue("r_contrast", 0.2f);
725         if (r_contrast.value > 1.0f)
726                 Cvar_SetValue("r_contrast", 1.0f);
727
728         if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
729                 return;
730
731         if (!r_render.value)
732                 return;
733
734         glDisable(GL_TEXTURE_2D);
735         glEnable(GL_BLEND);
736         f = r_brightness.value;
737         // only apply lighthalf using software color correction if hardware is not available (speed reasons)
738         if (lighthalf && !hardwaregammasupported)
739                 f *= 2;
740         if (f >= 1.01f)
741         {
742                 glBlendFunc (GL_DST_COLOR, GL_ONE);
743                 glBegin (GL_TRIANGLES);
744                 while (f >= 1.01f)
745                 {
746                         if (f >= 2)
747                                 glColor3f (1, 1, 1);
748                         else
749                                 glColor3f (f-1, f-1, f-1);
750                         glVertex2f (-5000, -5000);
751                         glVertex2f (10000, -5000);
752                         glVertex2f (-5000, 10000);
753                         f *= 0.5;
754                 }
755                 glEnd ();
756         }
757         if (r_contrast.value <= 0.99f)
758         {
759                 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
760                 if (lighthalf && hardwaregammasupported)
761                         glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
762                 else
763                         glColor4f (1, 1, 1, 1 - r_contrast.value);
764                 glBegin (GL_TRIANGLES);
765                 glVertex2f (-5000, -5000);
766                 glVertex2f (10000, -5000);
767                 glVertex2f (-5000, 10000);
768                 glEnd ();
769         }
770         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
771
772         glEnable (GL_CULL_FACE);
773         glEnable (GL_DEPTH_TEST);
774         glDisable(GL_BLEND);
775         glEnable(GL_TEXTURE_2D);
776 }
777
778 /*
779 ==================
780 SCR_UpdateScreen
781
782 This is called every frame, and can also be called explicitly to flush
783 text to the screen.
784
785 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
786 ==================
787 */
788 void GL_Finish();
789 void SCR_UpdateScreen (void)
790 {
791         double  time1 = 0, time2;
792
793         if (r_speeds.value)
794                 time1 = Sys_DoubleTime ();
795
796         VID_UpdateGamma(false);
797
798         if (scr_disabled_for_loading)
799         {
800                 /*
801                 if (realtime - scr_disabled_time > 60)
802                 {
803                         scr_disabled_for_loading = false;
804                         Con_Printf ("load failed.\n");
805                 }
806                 else
807                 */
808                         return;
809         }
810
811         if (!scr_initialized || !con_initialized)
812                 return;                         // not initialized yet
813
814
815         GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
816         
817         //
818         // determine size of refresh window
819         //
820         if (oldfov != scr_fov.value)
821         {
822                 oldfov = scr_fov.value;
823                 vid.recalc_refdef = true;
824         }
825
826         if (oldscreensize != scr_viewsize.value)
827         {
828                 oldscreensize = scr_viewsize.value;
829                 vid.recalc_refdef = true;
830         }
831
832         if (vid.recalc_refdef)
833                 SCR_CalcRefdef();
834
835         if (r_render.value)
836         {
837                 glClearColor(0,0,0,0);
838                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
839         }
840
841 //
842 // do 3D refresh drawing, and then update the screen
843 //
844         SCR_SetUpToDrawConsole();
845
846         V_RenderView();
847
848         GL_Set2D();
849
850         SCR_DrawRam();
851         SCR_DrawNet();
852         SCR_DrawTurtle();
853         SCR_DrawPause();
854         SCR_CheckDrawCenterString();
855         Sbar_Draw();
856         SHOWLMP_drawall();
857
858         if (crosshair.value)
859                 DrawCrosshair(crosshair.value - 1);
860
861         if (cl.intermission == 1)
862                 Sbar_IntermissionOverlay();
863         else if (cl.intermission == 2)
864                 Sbar_FinaleOverlay();
865
866         SCR_DrawConsole();      
867         M_Draw();
868
869 //      if (scr_drawloading)
870 //              SCR_DrawLoading();
871
872         if (showfps.value)
873         {
874                 static double currtime;
875                 double newtime;
876                 char temp[32];
877                 int calc;
878                 newtime = Sys_DoubleTime();
879                 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
880                 sprintf(temp, "%4i fps", calc);
881                 currtime = newtime;
882                 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
883         }
884
885         if (r_speeds2.value)
886         {
887                 extern char r_speeds2_string1[81], r_speeds2_string2[81], r_speeds2_string3[81], r_speeds2_string4[81], r_speeds2_string5[81], r_speeds2_string6[81], r_speeds2_string7[81];
888                 Draw_String(0, vid.height - sb_lines - 56, r_speeds2_string1, 80);
889                 Draw_String(0, vid.height - sb_lines - 48, r_speeds2_string2, 80);
890                 Draw_String(0, vid.height - sb_lines - 40, r_speeds2_string3, 80);
891                 Draw_String(0, vid.height - sb_lines - 32, r_speeds2_string4, 80);
892                 Draw_String(0, vid.height - sb_lines - 24, r_speeds2_string5, 80);
893                 Draw_String(0, vid.height - sb_lines - 16, r_speeds2_string6, 80);
894                 Draw_String(0, vid.height - sb_lines -  8, r_speeds2_string7, 80);
895         }
896
897         V_UpdateBlends();
898
899         GL_BrightenScreen();
900
901         GL_Finish();
902
903         if (r_speeds.value)
904         {
905                 time2 = Sys_DoubleTime ();
906                 Con_Printf ("%3i ms  %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs %4i BSPfaces %4i models %4i bmodels %4i sprites %4i particles %3i dlights\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs, c_faces, c_models, c_bmodels, c_sprites, c_particles, c_dlights);
907         }
908         GL_EndRendering ();
909 }
910
911 // for profiling, this is separated
912 void GL_Finish()
913 {
914         if (!r_render.value)
915                 return;
916         glFinish ();
917 }
918