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