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