added support for GL_ARB_texture_env_combine, currently only used on wall rendering...
[xonotic/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 = {CVAR_SAVE, "viewsize","100"};
80 cvar_t  scr_fov = {CVAR_SAVE, "fov","90"};      // 10 - 170
81 cvar_t  scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
82 cvar_t  scr_centertime = {0, "scr_centertime","2"};
83 cvar_t  scr_showram = {CVAR_SAVE, "showram","1"};
84 cvar_t  scr_showturtle = {CVAR_SAVE, "showturtle","0"};
85 cvar_t  scr_showpause = {CVAR_SAVE, "showpause","1"};
86 cvar_t  scr_printspeed = {0, "scr_printspeed","8"};
87 cvar_t  showfps = {CVAR_SAVE, "showfps", "0"};
88 cvar_t  r_render = {0, "r_render", "1"};
89 cvar_t  r_brightness = {CVAR_SAVE, "r_brightness", "1"}; // LordHavoc: a method of operating system independent color correction
90 cvar_t  r_contrast = {CVAR_SAVE, "r_contrast", "1"}; // 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 int                     lightscalebit;
102 float           lightscale;
103
104 qboolean        scr_disabled_for_loading;
105 //qboolean      scr_drawloading;
106 //float         scr_disabled_time;
107
108 void SCR_ScreenShot_f (void);
109
110 /*
111 ===============================================================================
112
113 CENTER PRINTING
114
115 ===============================================================================
116 */
117
118 char            scr_centerstring[1024];
119 float           scr_centertime_start;   // for slow victory printing
120 float           scr_centertime_off;
121 int                     scr_center_lines;
122 int                     scr_erase_lines;
123 int                     scr_erase_center;
124
125 /*
126 ==============
127 SCR_CenterPrint
128
129 Called for important messages that should stay in the center of the screen
130 for a few moments
131 ==============
132 */
133 void SCR_CenterPrint (char *str)
134 {
135         strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
136         scr_centertime_off = scr_centertime.value;
137         scr_centertime_start = cl.time;
138
139 // count the number of lines for centering
140         scr_center_lines = 1;
141         while (*str)
142         {
143                 if (*str == '\n')
144                         scr_center_lines++;
145                 str++;
146         }
147 }
148
149
150 void SCR_DrawCenterString (void)
151 {
152         char    *start;
153         int             l;
154         int             x, y;
155         int             remaining;
156
157 // the finale prints the characters one at a time
158         if (cl.intermission)
159                 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
160         else
161                 remaining = 9999;
162
163         scr_erase_center = 0;
164         start = scr_centerstring;
165
166         if (scr_center_lines <= 4)
167                 y = vid.height*0.35;
168         else
169                 y = 48;
170
171         do      
172         {
173         // scan the width of the line
174                 for (l=0 ; l<40 ; l++)
175                         if (start[l] == '\n' || !start[l])
176                                 break;
177                 x = (vid.width - l*8)/2;
178                 // LordHavoc: speedup
179                 if (l > 0)
180                 {
181                         if (remaining < l)
182                                 l = remaining;
183                         Draw_String(x, y, start, l);
184                         remaining -= l;
185                         if (remaining <= 0)
186                                 return;
187                 }
188                 /*
189                 for (j=0 ; j<l ; j++, x+=8)
190                 {
191                         Draw_Character (x, y, start[j]);        
192                         if (!remaining--)
193                                 return;
194                 }
195                 */
196                         
197                 y += 8;
198
199                 while (*start && *start != '\n')
200                         start++;
201
202                 if (!*start)
203                         break;
204                 start++;                // skip the \n
205         } while (1);
206 }
207
208 void SCR_CheckDrawCenterString (void)
209 {
210         if (scr_center_lines > scr_erase_lines)
211                 scr_erase_lines = scr_center_lines;
212
213         scr_centertime_off -= host_frametime;
214
215         if (scr_centertime_off <= 0 && !cl.intermission)
216                 return;
217         if (key_dest != key_game)
218                 return;
219
220         SCR_DrawCenterString ();
221 }
222
223 //=============================================================================
224
225 /*
226 ====================
227 CalcFov
228 ====================
229 */
230 float CalcFov (float fov_x, float width, float height)
231 {
232         float   a;
233         float   x;
234
235         if (fov_x < 1 || fov_x > 179)
236                 Sys_Error ("Bad fov: %f", fov_x);
237
238         x = width/tan(fov_x/360*M_PI);
239
240         a = atan (height/x);
241
242         a = a*360/M_PI;
243
244         return a;
245 }
246
247 /*
248 =================
249 SCR_CalcRefdef
250
251 Must be called whenever vid changes
252 Internal use only
253 =================
254 */
255 static void SCR_CalcRefdef (void)
256 {
257         float           size;
258         int             h;
259         qboolean                full = false;
260
261
262         vid.recalc_refdef = 0;
263
264 //========================================
265         
266 // bound viewsize
267         if (scr_viewsize.value < 30)
268                 Cvar_Set ("viewsize","30");
269         if (scr_viewsize.value > 120)
270                 Cvar_Set ("viewsize","120");
271
272 // bound field of view
273         if (scr_fov.value < 10)
274                 Cvar_Set ("fov","10");
275         if (scr_fov.value > 170)
276                 Cvar_Set ("fov","170");
277
278 // intermission is always full screen
279         if (cl.intermission)
280         {
281                 full = true;
282                 size = 1;
283                 sb_lines = 0;
284         }
285         else
286         {
287                 if (scr_viewsize.value >= 120)
288                         sb_lines = 0;           // no status bar at all
289                 else if (scr_viewsize.value >= 110)
290                         sb_lines = 24;          // no inventory
291                 else
292                         sb_lines = 24+16+8;
293
294                 if (scr_viewsize.value >= 100.0)
295                 {
296                         full = true;
297                         size = 1.0f;
298                 }
299                 else
300                         size = scr_viewsize.value * (1.0f / 100.0f);
301         }
302
303         // LordHavoc: always fullscreen 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(void)
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(void)
366 {
367 }
368
369 void gl_screen_newmap(void)
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 void GL_BrightenScreen(void)
712 {
713         float f;
714
715         if (r_brightness.value < 0.1f)
716                 Cvar_SetValue("r_brightness", 0.1f);
717         if (r_brightness.value > 5.0f)
718                 Cvar_SetValue("r_brightness", 5.0f);
719
720         if (r_contrast.value < 0.2f)
721                 Cvar_SetValue("r_contrast", 0.2f);
722         if (r_contrast.value > 1.0f)
723                 Cvar_SetValue("r_contrast", 1.0f);
724
725         if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
726                 return;
727
728         if (!r_render.value)
729                 return;
730
731         glDisable(GL_TEXTURE_2D);
732         glEnable(GL_BLEND);
733         f = r_brightness.value;
734         // only apply lighthalf using software color correction if hardware is not available (speed reasons)
735         if (lighthalf && !hardwaregammasupported)
736                 f *= 2;
737         if (f >= 1.01f)
738         {
739                 glBlendFunc (GL_DST_COLOR, GL_ONE);
740                 glBegin (GL_TRIANGLES);
741                 while (f >= 1.01f)
742                 {
743                         if (f >= 2)
744                                 glColor3f (1, 1, 1);
745                         else
746                                 glColor3f (f-1, f-1, f-1);
747                         glVertex2f (-5000, -5000);
748                         glVertex2f (10000, -5000);
749                         glVertex2f (-5000, 10000);
750                         f *= 0.5;
751                 }
752                 glEnd ();
753         }
754         if (r_contrast.value <= 0.99f)
755         {
756                 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
757                 if (lighthalf && hardwaregammasupported)
758                         glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
759                 else
760                         glColor4f (1, 1, 1, 1 - r_contrast.value);
761                 glBegin (GL_TRIANGLES);
762                 glVertex2f (-5000, -5000);
763                 glVertex2f (10000, -5000);
764                 glVertex2f (-5000, 10000);
765                 glEnd ();
766         }
767         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
768
769         glEnable (GL_CULL_FACE);
770         glEnable (GL_DEPTH_TEST);
771         glDisable(GL_BLEND);
772         glEnable(GL_TEXTURE_2D);
773 }
774
775 /*
776 ==================
777 SCR_UpdateScreen
778
779 This is called every frame, and can also be called explicitly to flush
780 text to the screen.
781
782 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
783 ==================
784 */
785 void GL_Finish(void);
786 void R_Clip_DisplayBuffer(void);
787 void SCR_UpdateScreen (void)
788 {
789         double  time1 = 0, time2;
790
791         if (r_speeds.value)
792                 time1 = Sys_DoubleTime ();
793
794         VID_UpdateGamma(false);
795
796         if (scr_disabled_for_loading)
797         {
798                 /*
799                 if (realtime - scr_disabled_time > 60)
800                 {
801                         scr_disabled_for_loading = false;
802                         Con_Printf ("load failed.\n");
803                 }
804                 else
805                 */
806                         return;
807         }
808
809         if (!scr_initialized || !con_initialized)
810                 return;                         // not initialized yet
811
812
813         GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
814
815         if (gl_combine.value && !gl_combine_extension)
816                 Cvar_SetValue("gl_combine", false);
817
818         lighthalf = gl_lightmode.value;
819
820         lightscalebit = 0;
821         if (lighthalf)
822                 lightscalebit += 1;
823
824         if (gl_combine.value)
825                 lightscalebit += 2;
826
827         lightscale = 1.0f / (float) (1 << lightscalebit);
828
829         //
830         // determine size of refresh window
831         //
832         if (oldfov != scr_fov.value)
833         {
834                 oldfov = scr_fov.value;
835                 vid.recalc_refdef = true;
836         }
837
838         if (oldscreensize != scr_viewsize.value)
839         {
840                 oldscreensize = scr_viewsize.value;
841                 vid.recalc_refdef = true;
842         }
843
844         if (vid.recalc_refdef)
845                 SCR_CalcRefdef();
846
847         if (r_render.value)
848         {
849                 glClearColor(0,0,0,0);
850                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
851         }
852
853 //
854 // do 3D refresh drawing, and then update the screen
855 //
856         SCR_SetUpToDrawConsole();
857
858         V_RenderView();
859
860         GL_Set2D();
861
862         R_Clip_DisplayBuffer();
863
864         SCR_DrawRam();
865         SCR_DrawNet();
866         SCR_DrawTurtle();
867         SCR_DrawPause();
868         SCR_CheckDrawCenterString();
869         Sbar_Draw();
870         SHOWLMP_drawall();
871
872         if (crosshair.value)
873                 DrawCrosshair(crosshair.value - 1);
874
875         if (cl.intermission == 1)
876                 Sbar_IntermissionOverlay();
877         else if (cl.intermission == 2)
878                 Sbar_FinaleOverlay();
879
880         SCR_DrawConsole();
881         M_Draw();
882
883         ui_draw();
884
885 //      if (scr_drawloading)
886 //              SCR_DrawLoading();
887
888         if (showfps.value)
889         {
890                 static double currtime;
891                 double newtime;
892                 char temp[32];
893                 int calc;
894                 newtime = Sys_DoubleTime();
895                 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
896                 sprintf(temp, "%4i fps", calc);
897                 currtime = newtime;
898                 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
899         }
900
901         // LordHavoc: only print info if renderer is being used
902         if (r_speeds2.value && !con_forcedup)
903         {
904                 int i, j, lines, y;
905                 lines = 1;
906                 for (i = 0;r_speeds2_string[i];i++)
907                         if (r_speeds2_string[i] == '\n')
908                                 lines++;
909                 y = vid.height - sb_lines - lines * 8 - 8;
910                 i = j = 0;
911                 while (r_speeds2_string[i])
912                 {
913                         j = i;
914                         while (r_speeds2_string[i] && r_speeds2_string[i] != '\n')
915                                 i++;
916                         if (i - j > 0)
917                                 Draw_String(0, y, r_speeds2_string + j, i - j);
918                         if (r_speeds2_string[i] == '\n')
919                                 i++;
920                         y += 8;
921                 }
922         }
923
924         V_UpdateBlends();
925
926         GL_BrightenScreen();
927
928         GL_Finish();
929
930         if (r_speeds.value)
931         {
932                 time2 = Sys_DoubleTime ();
933                 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);
934         }
935         GL_EndRendering ();
936 }
937
938 // for profiling, this is separated
939 void GL_Finish(void)
940 {
941         if (!r_render.value)
942                 return;
943         glFinish ();
944 }
945