2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // screen.c -- master for refresh, status bar, console, chat, notify, etc
25 // only the refresh window will be updated unless these variables are flagged
27 int scr_copyeverything
;
29 float scr_con_current
;
30 float scr_conlines
; // lines of console to display
32 float oldscreensize
, oldfov
;
33 cvar_t scr_viewsize
= {"viewsize","100", true};
34 cvar_t scr_fov
= {"fov","90"}; // 10 - 170
35 cvar_t scr_conspeed
= {"scr_conspeed","300"};
36 cvar_t scr_centertime
= {"scr_centertime","2"};
37 cvar_t scr_showram
= {"showram","1"};
38 cvar_t scr_showturtle
= {"showturtle","0"};
39 cvar_t scr_showpause
= {"showpause","1"};
40 cvar_t scr_printspeed
= {"scr_printspeed","8"};
42 qboolean scr_initialized
; // ready to draw
53 viddef_t vid
; // global video state
58 qboolean scr_disabled_for_loading
;
59 qboolean scr_drawloading
;
60 float scr_disabled_time
;
61 qboolean scr_skipupdate
;
63 qboolean block_drawing
;
65 void SCR_ScreenShot_f (void);
68 ===============================================================================
72 ===============================================================================
75 char scr_centerstring
[1024];
76 float scr_centertime_start
; // for slow victory printing
77 float scr_centertime_off
;
86 Called for important messages that should stay in the center of the screen
90 void SCR_CenterPrint (char *str
)
92 strncpy (scr_centerstring
, str
, sizeof(scr_centerstring
)-1);
93 scr_centertime_off
= scr_centertime
.value
;
94 scr_centertime_start
= cl
.time
;
96 // count the number of lines for centering
106 void SCR_EraseCenterString (void)
110 if (scr_erase_center
++ > vid
.numpages
)
116 if (scr_center_lines
<= 4)
122 Draw_TileClear (0, y
,vid
.width
, 8*scr_erase_lines
);
125 void SCR_DrawCenterString (void)
133 // the finale prints the characters one at a time
135 remaining
= scr_printspeed
.value
* (cl
.time
- scr_centertime_start
);
139 scr_erase_center
= 0;
140 start
= scr_centerstring
;
142 if (scr_center_lines
<= 4)
149 // scan the width of the line
150 for (l
=0 ; l
<40 ; l
++)
151 if (start
[l
] == '\n' || !start
[l
])
153 x
= (vid
.width
- l
*8)/2;
154 for (j
=0 ; j
<l
; j
++, x
+=8)
156 Draw_Character (x
, y
, start
[j
]);
163 while (*start
&& *start
!= '\n')
168 start
++; // skip the \n
172 void SCR_CheckDrawCenterString (void)
175 if (scr_center_lines
> scr_erase_lines
)
176 scr_erase_lines
= scr_center_lines
;
178 scr_centertime_off
-= host_frametime
;
180 if (scr_centertime_off
<= 0 && !cl
.intermission
)
182 if (key_dest
!= key_game
)
185 SCR_DrawCenterString ();
188 //=============================================================================
195 float CalcFov (float fov_x
, float width
, float height
)
200 if (fov_x
< 1 || fov_x
> 179)
201 Sys_Error ("Bad fov: %f", fov_x
);
203 x
= width
/tan(fov_x
/360*M_PI
);
216 Must be called whenever vid changes
220 static void SCR_CalcRefdef (void)
225 scr_fullupdate
= 0; // force a background redraw
226 vid
.recalc_refdef
= 0;
228 // force the status bar to redraw
231 //========================================
234 if (scr_viewsize
.value
< 30)
235 Cvar_Set ("viewsize","30");
236 if (scr_viewsize
.value
> 120)
237 Cvar_Set ("viewsize","120");
239 // bound field of view
240 if (scr_fov
.value
< 10)
241 Cvar_Set ("fov","10");
242 if (scr_fov
.value
> 170)
243 Cvar_Set ("fov","170");
245 r_refdef
.fov_x
= scr_fov
.value
;
246 r_refdef
.fov_y
= CalcFov (r_refdef
.fov_x
, r_refdef
.vrect
.width
, r_refdef
.vrect
.height
);
248 // intermission is always full screen
252 size
= scr_viewsize
.value
;
255 sb_lines
= 0; // no status bar at all
256 else if (size
>= 110)
257 sb_lines
= 24; // no inventory
261 // these calculations mirror those in R_Init() for r_refdef, but take no
262 // account of water warping
265 vrect
.width
= vid
.width
;
266 vrect
.height
= vid
.height
;
268 R_SetVrect (&vrect
, &scr_vrect
, sb_lines
);
270 // guard against going from one mode to another that's less than half the
271 // vertical resolution
272 if (scr_con_current
> vid
.height
)
273 scr_con_current
= vid
.height
;
275 // notify the refresh of the change
276 R_ViewChanged (&vrect
, sb_lines
, vid
.aspect
);
287 void SCR_SizeUp_f (void)
289 Cvar_SetValue ("viewsize",scr_viewsize
.value
+10);
290 vid
.recalc_refdef
= 1;
301 void SCR_SizeDown_f (void)
303 Cvar_SetValue ("viewsize",scr_viewsize
.value
-10);
304 vid
.recalc_refdef
= 1;
307 //============================================================================
316 Cvar_RegisterVariable (&scr_fov
);
317 Cvar_RegisterVariable (&scr_viewsize
);
318 Cvar_RegisterVariable (&scr_conspeed
);
319 Cvar_RegisterVariable (&scr_showram
);
320 Cvar_RegisterVariable (&scr_showturtle
);
321 Cvar_RegisterVariable (&scr_showpause
);
322 Cvar_RegisterVariable (&scr_centertime
);
323 Cvar_RegisterVariable (&scr_printspeed
);
326 // register our commands
328 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f
);
329 Cmd_AddCommand ("sizeup",SCR_SizeUp_f
);
330 Cmd_AddCommand ("sizedown",SCR_SizeDown_f
);
332 scr_ram
= Draw_PicFromWad ("ram");
333 scr_net
= Draw_PicFromWad ("net");
334 scr_turtle
= Draw_PicFromWad ("turtle");
336 scr_initialized
= true;
346 void SCR_DrawRam (void)
348 if (!scr_showram
.value
)
354 Draw_Pic (scr_vrect
.x
+32, scr_vrect
.y
, scr_ram
);
362 void SCR_DrawTurtle (void)
366 if (!scr_showturtle
.value
)
369 if (host_frametime
< 0.1)
379 Draw_Pic (scr_vrect
.x
, scr_vrect
.y
, scr_turtle
);
387 void SCR_DrawNet (void)
389 if (realtime
- cl
.last_received_message
< 0.3)
391 if (cls
.demoplayback
)
394 Draw_Pic (scr_vrect
.x
+64, scr_vrect
.y
, scr_net
);
402 void SCR_DrawPause (void)
406 if (!scr_showpause
.value
) // turn off for screenshots
412 pic
= Draw_CachePic ("gfx/pause.lmp");
413 Draw_Pic ( (vid
.width
- pic
->width
)/2,
414 (vid
.height
- 48 - pic
->height
)/2, pic
);
424 void SCR_DrawLoading (void)
428 if (!scr_drawloading
)
431 pic
= Draw_CachePic ("gfx/loading.lmp");
432 Draw_Pic ( (vid
.width
- pic
->width
)/2,
433 (vid
.height
- 48 - pic
->height
)/2, pic
);
438 //=============================================================================
443 SCR_SetUpToDrawConsole
446 void SCR_SetUpToDrawConsole (void)
451 return; // never a console with loading plaque
453 // decide on the height of the console
454 con_forcedup
= !cl
.worldmodel
|| cls
.signon
!= SIGNONS
;
458 scr_conlines
= vid
.height
; // full screen
459 scr_con_current
= scr_conlines
;
461 else if (key_dest
== key_console
)
462 scr_conlines
= vid
.height
/2; // half screen
464 scr_conlines
= 0; // none visible
466 if (scr_conlines
< scr_con_current
)
468 scr_con_current
-= scr_conspeed
.value
*host_frametime
;
469 if (scr_conlines
> scr_con_current
)
470 scr_con_current
= scr_conlines
;
473 else if (scr_conlines
> scr_con_current
)
475 scr_con_current
+= scr_conspeed
.value
*host_frametime
;
476 if (scr_conlines
< scr_con_current
)
477 scr_con_current
= scr_conlines
;
480 if (clearconsole
++ < vid
.numpages
)
483 Draw_TileClear (0,(int)scr_con_current
,vid
.width
, vid
.height
- (int)scr_con_current
);
486 else if (clearnotify
++ < vid
.numpages
)
489 Draw_TileClear (0,0,vid
.width
, con_notifylines
);
500 void SCR_DrawConsole (void)
504 scr_copyeverything
= 1;
505 Con_DrawConsole (scr_con_current
, true);
510 if (key_dest
== key_game
|| key_dest
== key_message
)
511 Con_DrawNotify (); // only draw notify in game
517 ==============================================================================
521 ==============================================================================
531 unsigned short xmin
,ymin
,xmax
,ymax
;
532 unsigned short hres
,vres
;
533 unsigned char palette
[48];
536 unsigned short bytes_per_line
;
537 unsigned short palette_type
;
539 unsigned char data
; // unbounded
547 void WritePCXfile (char *filename
, byte
*data
, int width
, int height
,
548 int rowbytes
, byte
*palette
)
554 pcx
= Hunk_TempAlloc (width
*height
*2+1000);
557 Con_Printf("SCR_ScreenShot_f: not enough memory\n");
561 pcx
->manufacturer
= 0x0a; // PCX id
562 pcx
->version
= 5; // 256 color
563 pcx
->encoding
= 1; // uncompressed
564 pcx
->bits_per_pixel
= 8; // 256 color
567 pcx
->xmax
= LittleShort((short)(width
-1));
568 pcx
->ymax
= LittleShort((short)(height
-1));
569 pcx
->hres
= LittleShort((short)width
);
570 pcx
->vres
= LittleShort((short)height
);
571 Q_memset (pcx
->palette
,0,sizeof(pcx
->palette
));
572 pcx
->color_planes
= 1; // chunky image
573 pcx
->bytes_per_line
= LittleShort((short)width
);
574 pcx
->palette_type
= LittleShort(2); // not a grey scale
575 Q_memset (pcx
->filler
,0,sizeof(pcx
->filler
));
580 for (i
=0 ; i
<height
; i
++)
582 for (j
=0 ; j
<width
; j
++)
584 if ( (*data
& 0xc0) != 0xc0)
593 data
+= rowbytes
- width
;
597 *pack
++ = 0x0c; // palette ID byte
598 for (i
=0 ; i
<768 ; i
++)
599 *pack
++ = *palette
++;
602 length
= pack
- (byte
*)pcx
;
603 COM_WriteFile (filename
, pcx
, length
);
613 void SCR_ScreenShot_f (void)
617 char checkname
[MAX_OSPATH
];
620 // find a file name to save it to
622 strcpy(pcxname
,"quake00.pcx");
624 for (i
=0 ; i
<=99 ; i
++)
626 pcxname
[5] = i
/10 + '0';
627 pcxname
[6] = i
%10 + '0';
628 sprintf (checkname
, "%s/%s", com_gamedir
, pcxname
);
629 if (Sys_FileTime(checkname
) == -1)
630 break; // file doesn't exist
634 Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n");
641 D_EnableBackBufferAccess (); // enable direct drawing of console to back
644 WritePCXfile (pcxname
, vid
.buffer
, vid
.width
, vid
.height
, vid
.rowbytes
,
647 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
648 // for linear writes all the time
650 Con_Printf ("Wrote %s\n", pcxname
);
654 //=============================================================================
659 SCR_BeginLoadingPlaque
663 void SCR_BeginLoadingPlaque (void)
665 S_StopAllSounds (true);
667 if (cls
.state
!= ca_connected
)
669 if (cls
.signon
!= SIGNONS
)
672 // redraw with no console and the loading plaque
674 scr_centertime_off
= 0;
677 scr_drawloading
= true;
681 scr_drawloading
= false;
683 scr_disabled_for_loading
= true;
684 scr_disabled_time
= realtime
;
694 void SCR_EndLoadingPlaque (void)
696 scr_disabled_for_loading
= false;
701 //=============================================================================
703 char *scr_notifystring
;
704 qboolean scr_drawdialog
;
706 void SCR_DrawNotifyString (void)
713 start
= scr_notifystring
;
719 // scan the width of the line
720 for (l
=0 ; l
<40 ; l
++)
721 if (start
[l
] == '\n' || !start
[l
])
723 x
= (vid
.width
- l
*8)/2;
724 for (j
=0 ; j
<l
; j
++, x
+=8)
725 Draw_Character (x
, y
, start
[j
]);
729 while (*start
&& *start
!= '\n')
734 start
++; // skip the \n
742 Displays a text string in the center of the screen and waits for a Y or N
746 int SCR_ModalMessage (char *text
)
748 if (cls
.state
== ca_dedicated
)
751 scr_notifystring
= text
;
753 // draw a fresh screen
755 scr_drawdialog
= true;
757 scr_drawdialog
= false;
759 S_ClearBuffer (); // so dma doesn't loop current sound
763 key_count
= -1; // wait for a key down and up
764 Sys_SendKeyEvents ();
765 } while (key_lastpress
!= 'y' && key_lastpress
!= 'n' && key_lastpress
!= K_ESCAPE
);
770 return key_lastpress
== 'y';
774 //=============================================================================
780 Brings the console down and fades the palettes back to normal
783 void SCR_BringDownConsole (void)
787 scr_centertime_off
= 0;
789 for (i
=0 ; i
<20 && scr_conlines
!= scr_con_current
; i
++)
792 cl
.cshifts
[0].percent
= 0; // no area contents palette on next frame
793 VID_SetPalette (host_basepal
);
801 This is called every frame, and can also be called explicitly to flush
804 WARNING: be very careful calling this from elsewhere, because the refresh
805 needs almost the entire 256k of stack space!
808 void SCR_UpdateScreen (void)
810 static float oldscr_viewsize
;
811 static float oldlcd_x
;
814 if (scr_skipupdate
|| block_drawing
)
818 scr_copyeverything
= 0;
820 if (scr_disabled_for_loading
)
822 if (realtime
- scr_disabled_time
> 60)
824 scr_disabled_for_loading
= false;
825 Con_Printf ("load failed.\n");
831 if (cls
.state
== ca_dedicated
)
832 return; // stdout only
834 if (!scr_initialized
|| !con_initialized
)
835 return; // not initialized yet
837 if (scr_viewsize
.value
!= oldscr_viewsize
)
839 oldscr_viewsize
= scr_viewsize
.value
;
840 vid
.recalc_refdef
= 1;
844 // check for vid changes
846 if (oldfov
!= scr_fov
.value
)
848 oldfov
= scr_fov
.value
;
849 vid
.recalc_refdef
= true;
852 if (oldlcd_x
!= lcd_x
.value
)
854 oldlcd_x
= lcd_x
.value
;
855 vid
.recalc_refdef
= true;
858 if (oldscreensize
!= scr_viewsize
.value
)
860 oldscreensize
= scr_viewsize
.value
;
861 vid
.recalc_refdef
= true;
864 if (vid
.recalc_refdef
)
866 // something changed, so reorder the screen
871 // do 3D refresh drawing, and then update the screen
873 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
875 if (scr_fullupdate
++ < vid
.numpages
)
876 { // clear the entire screen
877 scr_copyeverything
= 1;
878 Draw_TileClear (0,0,vid
.width
,vid
.height
);
885 SCR_SetUpToDrawConsole ();
886 SCR_EraseCenterString ();
888 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
889 // for linear writes all the time
897 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
903 SCR_DrawNotifyString ();
904 scr_copyeverything
= true;
906 else if (scr_drawloading
)
911 else if (cl
.intermission
== 1 && key_dest
== key_game
)
913 Sbar_IntermissionOverlay ();
915 else if (cl
.intermission
== 2 && key_dest
== key_game
)
917 Sbar_FinaleOverlay ();
918 SCR_CheckDrawCenterString ();
920 else if (cl
.intermission
== 3 && key_dest
== key_game
)
922 SCR_CheckDrawCenterString ();
930 SCR_CheckDrawCenterString ();
936 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
937 // for linear writes all the time
940 D_UpdateRects (pconupdate
);
946 // update one of three areas
949 if (scr_copyeverything
)
953 vrect
.width
= vid
.width
;
954 vrect
.height
= vid
.height
;
959 else if (scr_copytop
)
963 vrect
.width
= vid
.width
;
964 vrect
.height
= vid
.height
- sb_lines
;
971 vrect
.x
= scr_vrect
.x
;
972 vrect
.y
= scr_vrect
.y
;
973 vrect
.width
= scr_vrect
.width
;
974 vrect
.height
= scr_vrect
.height
;
984 SCR_UpdateWholeScreen
987 void SCR_UpdateWholeScreen (void)