1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: screen.cpp 4343 2010-12-16 20:25:03Z dj_jl $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "gamedefs.h"
29 #include "cl_local.h"
30 #include "drawer.h"
31 #include "ui.h"
32 
33 // MACROS ------------------------------------------------------------------
34 
35 // TYPES -------------------------------------------------------------------
36 
37 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
38 
39 void CalcFadetable16(byte *pal);
40 
41 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
42 
43 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
44 
45 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
46 
47 extern int				screenblocks;
48 
49 // PUBLIC DATA DEFINITIONS -------------------------------------------------
50 
51 int		ScreenWidth = 0;
52 int		ScreenHeight = 0;
53 int		ScreenBPP = 0;
54 
55 int		PixelBytes;
56 
57 int		VirtualWidth = 640;
58 int		VirtualHeight = 480;
59 
60 float	fScaleX;
61 float	fScaleY;
62 float	fScaleXI;
63 float	fScaleYI;
64 
65 int		usegamma = 0;
66 
67 bool	graphics_started = false;
68 
69 // Table of RGB values in current gamma corection level
70 byte 	gammatable[5][256] =
71 {
72 	{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
73 	17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
74 	33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
75 	49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
76 	65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
77 	81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,
78 	97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,
79 	113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
80 	128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
81 	144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
82 	160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
83 	176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
84 	192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
85 	208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
86 	224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
87 	240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255},
88 
89 	{2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31,
90 	32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55,
91 	56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77,
92 	78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
93 	99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
94 	115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129,
95 	130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
96 	146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160,
97 	161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175,
98 	175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189,
99 	190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204,
100 	205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218,
101 	219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232,
102 	233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246,
103 	247,248,249,250,251,252,252,253,254,255},
104 
105 	{4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42,
106 	43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69,
107 	70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93,
108 	94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,
109 	113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
110 	129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144,
111 	144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159,
112 	160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173,
113 	174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188,
114 	188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201,
115 	202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215,
116 	216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228,
117 	229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241,
118 	242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254,
119 	255},
120 
121 	{8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55,
122 	57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85,
123 	86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107,
124 	108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
125 	125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
126 	141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,
127 	155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169,
128 	169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182,
129 	183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195,
130 	195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207,
131 	207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219,
132 	219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230,
133 	231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241,
134 	242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252,
135 	253,253,254,254,255},
136 
137 	{16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76,
138 	78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106,
139 	107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,
140 	125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
141 	142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155,
142 	156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169,
143 	169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181,
144 	182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193,
145 	193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203,
146 	204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214,
147 	214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224,
148 	224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233,
149 	234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242,
150 	243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,
151 	251,252,252,253,254,254,255,255}
152 };
153 
154 // PRIVATE DATA DEFINITIONS ------------------------------------------------
155 
156 static bool		setresolutionneeded = false;
157 static int		setwidth;
158 static int		setheight;
159 static int		setbpp;
160 
161 static VCvarF	menu_darkening("menu_darkening", "0.5", CVAR_Archive);
162 static VCvarI	draw_pause("draw_pause", "1");
163 
164 static VCvarI	screen_width("screen_width", "0", CVAR_Archive);
165 static VCvarI	screen_height("screen_height", "0", CVAR_Archive);
166 static VCvarI	screen_bpp("screen_bpp", "0", CVAR_Archive);
167 static VCvarI	screen_windowed("screen_windowed", "0", CVAR_Archive);
168 static VCvarI	brightness("brightness", "0", CVAR_Archive);
169 
170 static VCvarI	draw_fps("draw_fps", "0", CVAR_Archive);
171 static double	fps_start = 0.0;
172 static double	ms = 0.0;
173 static int		fps_frames = 0;
174 static int		show_fps = 0;
175 
176 static VCvarI	draw_cycles("draw_cycles", "0", CVAR_Archive);
177 
178 // CODE --------------------------------------------------------------------
179 
180 //**************************************************************************
181 //
182 //	Screenshots
183 //
184 //**************************************************************************
185 
186 static VCvarS screenshot_type("screenshot_type", "png", CVAR_Archive);
187 
188 void WriteTGA(char* filename, void* data, int width, int height, int bpp,
189 	bool bot2top);
190 void WritePCX(char* filename, void* data, int width, int height, int bpp,
191 	bool bot2top);
192 void WritePNG(const VStr& FileName, const void* Data, int Width, int Height,
193 	int Bpp, bool Bot2top);
194 void WriteJPG(const VStr& FileName, const void* Data, int Width, int Height,
195 	int Bpp, bool Bot2top);
196 
197 //==========================================================================
198 //
199 //  ScreenShot_f
200 //
201 //==========================================================================
202 
COMMAND(ScreenShot)203 COMMAND(ScreenShot)
204 {
205 	guard(COMMAND ScreenShot);
206 	int		i;
207 	int		bpp;
208 	bool	bot2top;
209 	void	*data;
210 	char	filename[128];
211 
212 	if (strlen(screenshot_type) > 8)
213 	{
214 		GCon->Log("Screenshot extension too long");
215 		return;
216 	}
217 
218 	//	Find a file name to save it to
219 	VStr BaseDir = (fl_savedir.IsNotEmpty() ? fl_savedir : fl_basedir) + "/" + fl_gamedir;
220 	for (i = 0; i <= 9999; i++)
221 	{
222 		sprintf(filename, "shot%04d.%s", i, (const char*)screenshot_type);
223 		if (!Sys_FileExists(BaseDir + "/" + (const char*)filename))
224 			break;	//	File doesn't exist
225 	}
226 	if (i == 10000)
227 	{
228 		GCon->Log("Couldn't create a screenshot file");
229 		return;
230 	}
231 
232 	// save the pcx file
233 	data = Drawer->ReadScreen(&bpp, &bot2top);
234 	if (data)
235 	{
236 		if (!VStr::ICmp(screenshot_type, "pcx"))
237 		{
238 			WritePCX(filename, data, ScreenWidth, ScreenHeight, bpp, bot2top);
239 		}
240 		else if (!VStr::ICmp(screenshot_type, "tga"))
241 		{
242 			WriteTGA(filename, data, ScreenWidth, ScreenHeight, bpp, bot2top);
243 		}
244 		else if (!VStr::ICmp(screenshot_type, "png"))
245 		{
246 			WritePNG(filename, data, ScreenWidth, ScreenHeight, bpp, bot2top);
247 		}
248 		else if (!VStr::ICmp(screenshot_type, "jpg"))
249 		{
250 			WriteJPG(filename, data, ScreenWidth, ScreenHeight, bpp, bot2top);
251 		}
252 		else
253 		{
254 			GCon->Log("Bad screenshot type");
255 			GCon->Log("Supported formats are pcx, tga, png and jpg");
256 		}
257 		Z_Free(data);
258 	}
259 	else
260 	{
261 		GCon->Log("Not enough memory to take a screenshot");
262 	}
263 	unguard;
264 }
265 
266 //**************************************************************************
267 //
268 //	Misc drawing stuff
269 //
270 //**************************************************************************
271 
272 //==========================================================================
273 //
274 //	DrawFPS
275 //
276 //==========================================================================
277 
DrawFPS()278 static void DrawFPS()
279 {
280 	guard(DrawFPS);
281 	double		time;
282 
283 	if (draw_fps)
284 	{
285 		time = Sys_Time();
286 		fps_frames++;
287 
288 		if (time - fps_start > 1.0)
289 		{
290 			show_fps = (int)(fps_frames / (time - fps_start));
291 			if (draw_fps == 2)
292 			{
293 				ms = 1000.0 / fps_frames / (time - fps_start);
294 			}
295 			fps_start = time;
296 			fps_frames = 0;
297 		}
298 
299 		T_SetFont(SmallFont);
300 		T_SetAlign(hright, vtop);
301 		T_DrawText(VirtualWidth - 2, 0, va("%d fps", show_fps), CR_UNTRANSLATED);
302 		if (draw_fps == 2)
303 		{
304 			T_DrawText(VirtualWidth - 2, 12, va("%.2f ms ", ms), CR_UNTRANSLATED);
305 		}
306 	}
307 	unguard;
308 }
309 
310 //==========================================================================
311 //
312 //	DrawCycles
313 //
314 //==========================================================================
315 
DrawCycles()316 static void DrawCycles()
317 {
318 	guard(DrawCycles);
319 	if (draw_cycles)
320 	{
321 		T_SetFont(ConFont);
322 		T_SetAlign(hright, vtop);
323 		for (int i = 0; i < 16; i++)
324 		{
325 			T_DrawText(VirtualWidth - 2, 32 + i * 8, va("%d %10u", i,
326 				host_cycles[i]), CR_UNTRANSLATED);
327 			host_cycles[i] = 0;
328 		}
329 	}
330 	unguard;
331 }
332 
333 //**************************************************************************
334 //
335 //	Resolution change
336 //
337 //**************************************************************************
338 
339 //==========================================================================
340 //
341 //	ChangeResolution
342 //
343 //==========================================================================
344 
ChangeResolution(int InWidth,int InHeight,int InBpp)345 static void ChangeResolution(int InWidth, int InHeight, int InBpp)
346 {
347 	guard(ChangeResolution);
348 	int width = InWidth;
349 	int height = InHeight;
350 	int bpp = InBpp;
351 	bool win = false;
352 	if (bpp != 8 && bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32)
353 	{
354 		GCon->Log("Invalid bpp, using 8");
355 		bpp = 8;
356 	}
357 	if (screen_windowed > 0)
358 	{
359 		win = true;
360 	}
361 
362 	// Changing resolution
363 	if (!Drawer->SetResolution(width, height, bpp, win))
364 	{
365 		GCon->Logf("Failed to set resolution %dx%dx%d", width, height, bpp);
366 		if (ScreenWidth)
367 		{
368 			if (!Drawer->SetResolution(ScreenWidth, ScreenHeight, ScreenBPP,
369 				win))
370 				Sys_Error("ChangeResolution: failed to restore resolution");
371 			else
372 				GCon->Log("Restoring previous resolution");
373 		}
374 		else
375 		{
376 			if (!Drawer->SetResolution(0, 0, 0, win))
377 				Sys_Error("ChangeResolution: Failed to set default resolution");
378 			else
379 				GCon->Log("Setting default resolution");
380 		}
381 	}
382 	GCon->Logf("%dx%dx%d.", ScreenWidth, ScreenHeight, ScreenBPP);
383 
384 	screen_width = ScreenWidth;
385 	screen_height = ScreenHeight;
386 	screen_bpp = ScreenBPP;
387 
388 	PixelBytes = (ScreenBPP + 7) / 8;
389 
390 	fScaleX = (float)ScreenWidth / (float)VirtualWidth;
391 	fScaleY = (float)ScreenHeight / (float)VirtualHeight;
392 	fScaleXI = (float)VirtualWidth / (float)ScreenWidth;
393 	fScaleYI = (float)VirtualHeight / (float)ScreenHeight;
394 	unguard;
395 }
396 
397 //==========================================================================
398 //
399 //  CheckResolutionChange
400 //
401 //==========================================================================
402 
CheckResolutionChange()403 static void CheckResolutionChange()
404 {
405 	guard(CheckResolutionChange);
406 	bool		res_changed = false;
407 
408 	if (brightness != usegamma)
409 	{
410 		usegamma = brightness;
411 		if (usegamma < 0)
412 		{
413 			usegamma = 0;
414 			brightness = usegamma;
415 		}
416 		if (usegamma > 4)
417 		{
418 			usegamma = 4;
419 			brightness = usegamma;
420 		}
421 	}
422 	if (setresolutionneeded)
423 	{
424 		ChangeResolution(setwidth, setheight, setbpp);
425 		setresolutionneeded = false;
426 		res_changed = true;
427 	}
428 	else if (!screen_width || screen_width != ScreenWidth ||
429 		screen_height != ScreenHeight || screen_bpp != ScreenBPP)
430 	{
431 		ChangeResolution(screen_width, screen_height, screen_bpp);
432 		res_changed = true;
433 	}
434 
435 	if (res_changed)
436 	{
437 		Drawer->InitResolution();
438 		//	Recalculate view size and other data
439 		R_SetViewSize(screenblocks);
440 	}
441 	graphics_started = true;
442 	unguard;
443 }
444 
445 //==========================================================================
446 //
447 //  SetResolution_f
448 //
449 //==========================================================================
450 
COMMAND(SetResolution)451 COMMAND(SetResolution)
452 {
453 	if (Args.Num() == 3)
454 	{
455 		setwidth = superatoi(*Args[1]);
456 		setheight = superatoi(*Args[2]);
457 		setbpp = ScreenBPP;
458 		setresolutionneeded = true;
459 	}
460 	else if (Args.Num() == 4)
461 	{
462 		setwidth = superatoi(*Args[1]);
463 		setheight = superatoi(*Args[2]);
464 		setbpp = superatoi(*Args[3]);
465 		setresolutionneeded = true;
466 	}
467 	else
468 	{
469 		GCon->Log("SetResolution <width> <height> [<bpp>]:change resolution");
470 	}
471 }
472 
473 //==========================================================================
474 //
475 //	COMMAND vid_restart
476 //
477 //==========================================================================
478 
COMMAND(vid_restart)479 COMMAND(vid_restart)
480 {
481 	setwidth = ScreenWidth;
482 	setheight = ScreenHeight;
483 	setbpp = ScreenBPP;
484 	setresolutionneeded = true;
485 }
486 
487 //**************************************************************************
488 //
489 //	General (public) stuff
490 //
491 //**************************************************************************
492 
493 //==========================================================================
494 //
495 //  SCR_Init
496 //
497 //==========================================================================
498 
SCR_Init()499 void SCR_Init()
500 {
501 }
502 
503 //==========================================================================
504 //
505 //  SCR_Update
506 //
507 //==========================================================================
508 
SCR_Update()509 void SCR_Update()
510 {
511 	guard(SCR_Update);
512 	CheckResolutionChange();
513 
514 	Drawer->StartUpdate();
515 
516 	// do buffered drawing
517 	if (cl && cls.signon && cl->MO)
518 	{
519 		switch (GClGame->intermission)
520 		{
521 		case 0:
522 			if (automapactive)
523 			{
524 				AM_Drawer();
525 			}
526 			else
527 			{
528 				R_RenderPlayerView();
529 			}
530 			if (GGameInfo->NetMode != NM_TitleMap)
531 			{
532 				CT_Drawer();
533 				SB_Drawer();
534 			}
535 			break;
536 		}
537 	}
538 
539 	//	Draw user interface.
540 	GRoot->DrawWidgets();
541 
542 	// Menu drawing
543 	MN_Drawer();
544 
545 	// Console drawing
546 	C_Drawer();
547 
548 	DrawFPS();
549 
550 	DrawCycles();
551 
552 	Drawer->Update();              // page flip or blit buffer
553 	unguard;
554 }
555 
556 //==========================================================================
557 //
558 // Draw_TeleportIcon
559 //
560 //==========================================================================
561 
Draw_TeleportIcon()562 void Draw_TeleportIcon()
563 {
564 	guard(Draw_TeleportIcon);
565 	if (W_CheckNumForName(NAME_teleicon) >= 0)
566 	{
567 		Drawer->BeginDirectUpdate();
568 		R_DrawPic(260, 68, GTextureManager.AddPatch(NAME_teleicon,
569 			TEXTYPE_Pic));
570 		Drawer->EndDirectUpdate();
571 	}
572 	unguard;
573 }
574 
575 //==========================================================================
576 //
577 // Draw_SaveIcon
578 //
579 //==========================================================================
580 
Draw_SaveIcon()581 void Draw_SaveIcon()
582 {
583 	guard(Draw_SaveIcon);
584 	if (W_CheckNumForName(NAME_saveicon) >= 0)
585 	{
586 		Drawer->BeginDirectUpdate();
587 		R_DrawPic(260, 68, GTextureManager.AddPatch(NAME_saveicon,
588 			TEXTYPE_Pic));
589 		Drawer->EndDirectUpdate();
590 	}
591 	unguard;
592 }
593 
594 //==========================================================================
595 //
596 // Draw_LoadIcon
597 //
598 //==========================================================================
599 
Draw_LoadIcon()600 void Draw_LoadIcon()
601 {
602 	guard(Draw_LoadIcon);
603 	if (W_CheckNumForName(NAME_loadicon) >= 0)
604 	{
605 		Drawer->BeginDirectUpdate();
606 		R_DrawPic(260, 68, GTextureManager.AddPatch(NAME_loadicon,
607 			TEXTYPE_Pic));
608 		Drawer->EndDirectUpdate();
609 	}
610 	unguard;
611 }
612 
613 //==========================================================================
614 //
615 //	SCR_SetVirtualScreen
616 //
617 //==========================================================================
618 
SCR_SetVirtualScreen(int Width,int Height)619 void SCR_SetVirtualScreen(int Width, int Height)
620 {
621 	guard(SCR_SetVirtualScreen);
622 	VirtualWidth = Width;
623 	VirtualHeight = Height;
624 	fScaleX = (float)ScreenWidth / (float)VirtualWidth;
625 	fScaleY = (float)ScreenHeight / (float)VirtualHeight;
626 	fScaleXI = (float)VirtualWidth / (float)ScreenWidth;
627 	fScaleYI = (float)VirtualHeight / (float)ScreenHeight;
628 	unguard;
629 }
630