722dfa60b403d09ed3e941db95be22d0478380c5
[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 allways 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 /*
382 ==================
383 SCR_Init
384 ==================
385 */
386 void GL_Screen_Init (void)
387 {
388
389         Cvar_RegisterVariable (&scr_fov);
390         Cvar_RegisterVariable (&scr_viewsize);
391         Cvar_RegisterVariable (&scr_conspeed);
392         Cvar_RegisterVariable (&scr_showram);
393         Cvar_RegisterVariable (&scr_showturtle);
394         Cvar_RegisterVariable (&scr_showpause);
395         Cvar_RegisterVariable (&scr_centertime);
396         Cvar_RegisterVariable (&scr_printspeed);
397         Cvar_RegisterVariable (&showfps);
398         Cvar_RegisterVariable (&r_render);
399 #ifdef NORENDER
400         r_render.value = 0;
401 #endif
402
403 //
404 // register our commands
405 //
406         Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
407         Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
408         Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
409
410         scr_initialized = true;
411
412         R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown);
413 }
414
415
416
417 /*
418 ==============
419 SCR_DrawRam
420 ==============
421 */
422 void SCR_DrawRam (void)
423 {
424         if (!scr_showram.value)
425                 return;
426
427         if (!r_cache_thrash)
428                 return;
429
430         Draw_Pic (32, 0, scr_ram);
431 }
432
433 /*
434 ==============
435 SCR_DrawTurtle
436 ==============
437 */
438 void SCR_DrawTurtle (void)
439 {
440         static int      count;
441         
442         if (!scr_showturtle.value)
443                 return;
444
445         if (host_frametime < 0.1)
446         {
447                 count = 0;
448                 return;
449         }
450
451         count++;
452         if (count < 3)
453                 return;
454
455         Draw_Pic (0, 0, scr_turtle);
456 }
457
458 /*
459 ==============
460 SCR_DrawNet
461 ==============
462 */
463 void SCR_DrawNet (void)
464 {
465         if (realtime - cl.last_received_message < 0.3)
466                 return;
467         if (cls.demoplayback)
468                 return;
469
470         Draw_Pic (64, 0, scr_net);
471 }
472
473 /*
474 ==============
475 DrawPause
476 ==============
477 */
478 void SCR_DrawPause (void)
479 {
480         qpic_t  *pic;
481
482         if (!scr_showpause.value)               // turn off for screenshots
483                 return;
484
485         if (!cl.paused)
486                 return;
487
488         pic = Draw_CachePic ("gfx/pause.lmp");
489         Draw_Pic ( (vid.width - pic->width)/2, 
490                 (vid.height - 48 - pic->height)/2, pic);
491 }
492
493
494
495 /*
496 ==============
497 SCR_DrawLoading
498 ==============
499 */
500 void SCR_DrawLoading (void)
501 {
502         qpic_t  *pic;
503
504         if (!scr_drawloading)
505                 return;
506                 
507         pic = Draw_CachePic ("gfx/loading.lmp");
508         Draw_Pic ( (vid.width - pic->width)/2, 
509                 (vid.height - 48 - pic->height)/2, pic);
510 }
511
512
513
514 //=============================================================================
515
516
517 /*
518 ==================
519 SCR_SetUpToDrawConsole
520 ==================
521 */
522 void SCR_SetUpToDrawConsole (void)
523 {
524         Con_CheckResize ();
525         
526         //if (scr_drawloading)
527         //      return;         // never a console with loading plaque
528
529 // decide on the height of the console
530         con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
531
532         if (con_forcedup)
533         {
534                 scr_conlines = vid.height;              // full screen
535                 scr_con_current = scr_conlines;
536         }
537         else if (key_dest == key_console)
538                 scr_conlines = vid.height/2;    // half screen
539         else
540                 scr_conlines = 0;                               // none visible
541         
542         if (scr_conlines < scr_con_current)
543         {
544                 scr_con_current -= scr_conspeed.value*host_frametime;
545                 if (scr_conlines > scr_con_current)
546                         scr_con_current = scr_conlines;
547
548         }
549         else if (scr_conlines > scr_con_current)
550         {
551                 scr_con_current += scr_conspeed.value*host_frametime;
552                 if (scr_conlines < scr_con_current)
553                         scr_con_current = scr_conlines;
554         }
555 }
556         
557 /*
558 ==================
559 SCR_DrawConsole
560 ==================
561 */
562 void SCR_DrawConsole (void)
563 {
564         if (scr_con_current)
565         {
566                 scr_copyeverything = 1;
567                 Con_DrawConsole (scr_con_current, true);
568                 clearconsole = 0;
569         }
570         else
571         {
572                 if (key_dest == key_game || key_dest == key_message)
573                         Con_DrawNotify ();      // only draw notify in game
574         }
575 }
576
577
578 /* 
579 ============================================================================== 
580  
581                                                 SCREEN SHOTS 
582  
583 ============================================================================== 
584 */ 
585
586 /*
587 ================== 
588 SCR_ScreenShot_f
589 ================== 
590 */
591 void SCR_ScreenShot_f (void) 
592 {
593         byte            *buffer;
594         char            filename[80]; 
595         char            checkname[MAX_OSPATH];
596         int                     i;
597 // 
598 // find a file name to save it to 
599 // 
600         strcpy(filename,"dp0000.tga");
601                 
602         for (i=0 ; i<=9999 ; i++) 
603         { 
604                 filename[2] = (i/1000)%10 + '0'; 
605                 filename[3] = (i/ 100)%10 + '0'; 
606                 filename[4] = (i/  10)%10 + '0'; 
607                 filename[5] = (i/   1)%10 + '0'; 
608                 sprintf (checkname, "%s/%s", com_gamedir, filename);
609                 if (Sys_FileTime(checkname) == -1)
610                         break;  // file doesn't exist
611         } 
612         if (i==10000)
613         {
614                 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); 
615                 return;
616         }
617
618         buffer = malloc(glwidth*glheight*3);
619         glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer); 
620         Image_WriteTGARGB(filename, glwidth, glheight, buffer);
621
622         free (buffer);
623         Con_Printf ("Wrote %s\n", filename);
624 }
625
626
627 //=============================================================================
628
629
630 /*
631 ===============
632 SCR_BeginLoadingPlaque
633
634 ================
635 */
636 void SCR_BeginLoadingPlaque (void)
637 {
638         S_StopAllSounds (true);
639
640         if (cls.state != ca_connected)
641                 return;
642         if (cls.signon != SIGNONS)
643                 return;
644         
645 // redraw with no console and the loading plaque
646         Con_ClearNotify ();
647         scr_centertime_off = 0;
648         scr_con_current = 0;
649
650         scr_drawloading = true;
651         scr_fullupdate = 0;
652         SCR_UpdateScreen ();
653         scr_drawloading = false;
654
655         scr_disabled_for_loading = true;
656         scr_disabled_time = realtime;
657         scr_fullupdate = 0;
658 }
659
660 /*
661 ===============
662 SCR_EndLoadingPlaque
663
664 ================
665 */
666 void SCR_EndLoadingPlaque (void)
667 {
668         scr_disabled_for_loading = false;
669         scr_fullupdate = 0;
670         Con_ClearNotify ();
671 }
672
673 //=============================================================================
674
675 char    *scr_notifystring;
676 qboolean        scr_drawdialog;
677
678 void SCR_DrawNotifyString (void)
679 {
680         char    *start;
681         int             l;
682         int             x, y;
683
684         start = scr_notifystring;
685
686         y = vid.height*0.35;
687
688         do      
689         {
690         // scan the width of the line
691                 for (l=0 ; l<40 ; l++)
692                         if (start[l] == '\n' || !start[l])
693                                 break;
694                 x = (vid.width - l*8)/2;
695                 // LordHavoc: speedup
696 //              for (j=0 ; j<l ; j++, x+=8)
697 //                      Draw_Character (x, y, start[j]);        
698                 Draw_String (x, y, start, l);
699                         
700                 y += 8;
701
702                 while (*start && *start != '\n')
703                         start++;
704
705                 if (!*start)
706                         break;
707                 start++;                // skip the \n
708         } while (1);
709 }
710
711 /*
712 ==================
713 SCR_ModalMessage
714
715 Displays a text string in the center of the screen and waits for a Y or N
716 keypress.  
717 ==================
718 */
719 int SCR_ModalMessage (char *text)
720 {
721         if (cls.state == ca_dedicated)
722                 return true;
723
724         scr_notifystring = text;
725  
726 // draw a fresh screen
727         scr_fullupdate = 0;
728         scr_drawdialog = true;
729         SCR_UpdateScreen ();
730         scr_drawdialog = false;
731         
732         S_ClearBuffer ();               // so dma doesn't loop current sound
733
734         do
735         {
736                 key_count = -1;         // wait for a key down and up
737                 Sys_SendKeyEvents ();
738         } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
739
740         scr_fullupdate = 0;
741         SCR_UpdateScreen ();
742
743         return key_lastpress == 'y';
744 }
745
746
747 //=============================================================================
748
749 /*
750 ===============
751 SCR_BringDownConsole
752
753 Brings the console down and fades the blends back to normal
754 ================
755 */
756 void SCR_BringDownConsole (void)
757 {
758         int             i;
759         
760         scr_centertime_off = 0;
761         
762         for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
763                 SCR_UpdateScreen ();
764
765         cl.cshifts[0].percent = 0;              // no area contents blend on next frame
766 }
767
768 void DrawCrosshair(int num);
769 void GL_Set2D (void);
770
771 extern void SHOWLMP_drawall();
772 extern cvar_t contrast;
773 extern cvar_t brightness;
774 extern cvar_t gl_lightmode;
775
776 void GL_BrightenScreen()
777 {
778         float f;
779         if (!r_render.value)
780                 return;
781         glDisable(GL_TEXTURE_2D);
782         glEnable(GL_BLEND);
783         f = brightness.value = bound(1.0f, brightness.value, 5.0f);
784         if (f >= 1.01f)
785         {
786                 glBlendFunc (GL_DST_COLOR, GL_ONE);
787                 glBegin (GL_TRIANGLES);
788                 while (f >= 1.01f)
789                 {
790                         if (f >= 2)
791                                 glColor3f (1, 1, 1);
792                         else
793                                 glColor3f (f-1, f-1, f-1);
794                         glVertex2f (-5000, -5000);
795                         glVertex2f (10000, -5000);
796                         glVertex2f (-5000, 10000);
797                         f *= 0.5;
798                 }
799                 glEnd ();
800         }
801         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
802         contrast.value = bound(0.2, contrast.value, 1.0);
803         if (contrast.value < 0.99f)
804         {
805                 glBegin (GL_TRIANGLES);
806                 glColor4f (1, 1, 1, 1-contrast.value);
807                 glVertex2f (-5000, -5000);
808                 glVertex2f (10000, -5000);
809                 glVertex2f (-5000, 10000);
810                 glEnd ();
811         }
812
813         glEnable (GL_CULL_FACE);
814         glEnable (GL_DEPTH_TEST);
815         glDisable(GL_BLEND);
816         glEnable(GL_TEXTURE_2D);
817 }
818
819 /*
820 ==================
821 SCR_UpdateScreen
822
823 This is called every frame, and can also be called explicitly to flush
824 text to the screen.
825
826 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
827 ==================
828 */
829 extern cvar_t gl_vertexarrays;
830 extern qboolean gl_arrays;
831 void GL_Finish();
832 void SCR_UpdateScreen (void)
833 {
834         double  time1 = 0, time2;
835
836         if (r_speeds.value)
837                 time1 = Sys_FloatTime ();
838
839         if (!gl_arrays)
840                 gl_vertexarrays.value = 0;
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) (100.0 / (newtime - currtime));
940                 sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
941                 currtime = newtime;
942                 Draw_String(vid.width - (12*8), 0, temp, 9999);
943         }
944
945         V_UpdateBlends ();
946
947         GL_BrightenScreen();
948
949         GL_Finish();
950
951         if (r_speeds.value)
952         {
953                 time2 = Sys_FloatTime ();
954                 Con_Printf ("%3i ms  %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs);
955         }
956         GL_EndRendering ();
957 }
958
959 // for profiling, this is seperated
960 void GL_Finish()
961 {
962         if (!r_render.value)
963                 return;
964         glFinish ();
965 }
966