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