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