added back r_speeds2, with masses of information (6 lines high), and made it print...
[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 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_realframetime;
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_realframetime;
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 = qmalloc(glwidth*glheight*3);
619         glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer); 
620         Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
621
622         qfree(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 extern cvar_t r_speeds2;
776
777 void GL_BrightenScreen()
778 {
779         float f;
780         if (!r_render.value)
781                 return;
782         glDisable(GL_TEXTURE_2D);
783         glEnable(GL_BLEND);
784         f = brightness.value = bound(1.0f, brightness.value, 5.0f);
785         if (f >= 1.01f)
786         {
787                 glBlendFunc (GL_DST_COLOR, GL_ONE);
788                 glBegin (GL_TRIANGLES);
789                 while (f >= 1.01f)
790                 {
791                         if (f >= 2)
792                                 glColor3f (1, 1, 1);
793                         else
794                                 glColor3f (f-1, f-1, f-1);
795                         glVertex2f (-5000, -5000);
796                         glVertex2f (10000, -5000);
797                         glVertex2f (-5000, 10000);
798                         f *= 0.5;
799                 }
800                 glEnd ();
801         }
802         glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
803         contrast.value = bound(0.2, contrast.value, 1.0);
804         if (contrast.value < 0.99f)
805         {
806                 glBegin (GL_TRIANGLES);
807                 glColor4f (1, 1, 1, 1-contrast.value);
808                 glVertex2f (-5000, -5000);
809                 glVertex2f (10000, -5000);
810                 glVertex2f (-5000, 10000);
811                 glEnd ();
812         }
813
814         glEnable (GL_CULL_FACE);
815         glEnable (GL_DEPTH_TEST);
816         glDisable(GL_BLEND);
817         glEnable(GL_TEXTURE_2D);
818 }
819
820 /*
821 ==================
822 SCR_UpdateScreen
823
824 This is called every frame, and can also be called explicitly to flush
825 text to the screen.
826
827 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
828 ==================
829 */
830 extern cvar_t gl_vertexarrays;
831 extern qboolean gl_arrays;
832 void GL_Finish();
833 void SCR_UpdateScreen (void)
834 {
835         double  time1 = 0, time2;
836
837         if (r_speeds.value)
838                 time1 = Sys_FloatTime ();
839
840         if (!gl_arrays)
841                 gl_vertexarrays.value = 0;
842
843         scr_copytop = 0;
844         scr_copyeverything = 0;
845
846         if (scr_disabled_for_loading)
847         {
848                 if (realtime - scr_disabled_time > 60)
849                 {
850                         scr_disabled_for_loading = false;
851                         Con_Printf ("load failed.\n");
852                 }
853                 else
854                         return;
855         }
856
857         if (!scr_initialized || !con_initialized)
858                 return;                         // not initialized yet
859
860
861         GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
862         
863         //
864         // determine size of refresh window
865         //
866         if (oldfov != scr_fov.value)
867         {
868                 oldfov = scr_fov.value;
869                 vid.recalc_refdef = true;
870         }
871
872         if (oldscreensize != scr_viewsize.value)
873         {
874                 oldscreensize = scr_viewsize.value;
875                 vid.recalc_refdef = true;
876         }
877
878         if (vid.recalc_refdef)
879                 SCR_CalcRefdef ();
880
881         if (r_render.value)
882         {
883                 glClearColor(0,0,0,0);
884                 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
885         }
886
887 //
888 // do 3D refresh drawing, and then update the screen
889 //
890         SCR_SetUpToDrawConsole ();
891
892         V_RenderView ();
893
894         GL_Set2D ();
895
896         if (scr_drawdialog)
897         {
898                 Sbar_Draw ();
899 //              Draw_FadeScreen ();
900                 SCR_DrawNotifyString ();
901                 scr_copyeverything = true;
902         }
903         else if (scr_drawloading)
904         {
905                 SCR_DrawLoading ();
906                 Sbar_Draw ();
907         }
908         else if (cl.intermission == 1 && key_dest == key_game)
909         {
910                 Sbar_IntermissionOverlay ();
911         }
912         else if (cl.intermission == 2 && key_dest == key_game)
913         {
914                 Sbar_FinaleOverlay ();
915                 SCR_CheckDrawCenterString ();
916         }
917         else
918         {
919                 if (crosshair.value)
920                         DrawCrosshair(crosshair.value - 1);
921                 
922                 SCR_DrawRam ();
923                 SCR_DrawNet ();
924                 SCR_DrawTurtle ();
925                 SCR_DrawPause ();
926                 SCR_CheckDrawCenterString ();
927                 Sbar_Draw ();
928                 SHOWLMP_drawall();
929                 SCR_DrawConsole ();     
930                 M_Draw ();
931         }
932
933         if (showfps.value)
934         {
935                 static double currtime;
936                 double newtime;
937                 char temp[32];
938                 int calc;
939                 newtime = Sys_FloatTime();
940                 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
941                 sprintf(temp, "%4i fps", calc);
942                 currtime = newtime;
943                 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
944         }
945
946         if (r_speeds2.value)
947         {
948                 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];
949                 Draw_String(0, vid.height - sb_lines - 48, r_speeds2_string1, 80);
950                 Draw_String(0, vid.height - sb_lines - 40, r_speeds2_string2, 80);
951                 Draw_String(0, vid.height - sb_lines - 32, r_speeds2_string3, 80);
952                 Draw_String(0, vid.height - sb_lines - 24, r_speeds2_string4, 80);
953                 Draw_String(0, vid.height - sb_lines - 16, r_speeds2_string5, 80);
954                 Draw_String(0, vid.height - sb_lines -  8, r_speeds2_string6, 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 seperated
972 void GL_Finish()
973 {
974         if (!r_render.value)
975                 return;
976         glFinish ();
977 }
978