1 #include "ContentManager.h"
2 #include "Debug.h"
3 #include "Fade_Screen.h"
4 #include "FileMan.h"
5 #include "GameInstance.h"
6 #include "HImage.h"
7 #include "Input.h"
8 #include "Local.h"
9 #include "Logger.h"
10 #include "RenderWorld.h"
11 #include "Render_Dirty.h"
12 #include "Timer.h"
13 #include "Timer_Control.h"
14 #include "Types.h"
15 #include "VObject_Blitters.h"
16 #include "VSurface.h"
17 #include "Video.h"
18 #include "UILayout.h"
19 #include "Font.h"
20 #include "Icon.h"
21 #include <algorithm>
22 #include <ctime>
23 #include <stdexcept>
24
25 #define BUFFER_READY 0x00
26 #define BUFFER_DIRTY 0x02
27
28 #define MAX_CURSOR_WIDTH 64
29 #define MAX_CURSOR_HEIGHT 64
30
31 #define MAX_DIRTY_REGIONS 128
32
33 #define VIDEO_OFF 0x00
34 #define VIDEO_ON 0x01
35 #define VIDEO_SUSPENDED 0x04
36
37 #define RED_MASK 0xF800
38 #define GREEN_MASK 0x07E0
39 #define BLUE_MASK 0x001F
40 #define ALPHA_MASK 0
41
42 #define OVERSAMPLING_SCALE 4
43
44
45 // Globals for mouse cursor
46 static UINT16 gusMouseCursorWidth;
47 static UINT16 gusMouseCursorHeight;
48 static INT16 gsMouseCursorXOffset;
49 static INT16 gsMouseCursorYOffset;
50
51 static SDL_Rect MouseBackground = { 0, 0, 0, 0 };
52
53 // Refresh thread based variables
54 static UINT32 guiFrameBufferState; // BUFFER_READY, BUFFER_DIRTY
55 static UINT32 guiVideoManagerState; // VIDEO_ON, VIDEO_OFF, VIDEO_SUSPENDED
56
57 // Dirty rectangle management variables
58 static SDL_Rect DirtyRegions[MAX_DIRTY_REGIONS];
59 static UINT32 guiDirtyRegionCount;
60 static BOOLEAN gfForceFullScreenRefresh;
61
62
63 static SDL_Rect DirtyRegionsEx[MAX_DIRTY_REGIONS];
64 static UINT32 guiDirtyRegionExCount;
65
66
67 static SDL_Surface* MouseCursor;
68 static SDL_Surface* FrameBuffer;
69 static SDL_Renderer* GameRenderer;
70 SDL_Window* g_game_window;
71
72 static SDL_Surface* ScreenBuffer;
73 static SDL_Texture* ScreenTexture;
74 static SDL_Texture* ScaledScreenTexture;
75 static Uint32 g_window_flags = 0;
76 static VideoScaleQuality ScaleQuality = VideoScaleQuality::LINEAR;
77
78 static void RecreateBackBuffer();
79 static void DeletePrimaryVideoSurfaces(void);
80
81 // returns if desktop resolution larger game resolution
IsDesktopLargeEnough()82 BOOLEAN IsDesktopLargeEnough()
83 {
84 SDL_DisplayMode dm;
85 if (SDL_GetDesktopDisplayMode(0, &dm) == 0)
86 {
87 if (dm.w < SCREEN_WIDTH || dm.h < SCREEN_HEIGHT)
88 {
89 return false;
90 }
91 }
92 return true;
93 }
94
VideoSetFullScreen(const BOOLEAN enable)95 void VideoSetFullScreen(const BOOLEAN enable)
96 {
97 if (enable)
98 {
99 g_window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
100 }
101 else
102 {
103 g_window_flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP;
104 }
105 }
106
VideoToggleFullScreen(void)107 void VideoToggleFullScreen(void)
108 {
109 if (SDL_GetWindowFlags(g_game_window) & SDL_WINDOW_FULLSCREEN_DESKTOP)
110 {
111 SDL_SetWindowFullscreen(g_game_window, 0);
112 }
113 else
114 {
115 SDL_SetWindowFullscreen(g_game_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
116 }
117 }
118
VideoSetBrightness(float brightness)119 void VideoSetBrightness(float brightness)
120 {
121 SDL_SetWindowBrightness(g_game_window, brightness);
122 }
123
124
125 static void GetRGBDistribution();
126
127
InitializeVideoManager(const VideoScaleQuality quality)128 void InitializeVideoManager(const VideoScaleQuality quality)
129 {
130 SLOGD("Initializing the video manager");
131 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
132
133 ScaleQuality = quality;
134 g_window_flags |= SDL_WINDOW_RESIZABLE;
135
136 g_game_window = SDL_CreateWindow(APPLICATION_NAME,
137 SDL_WINDOWPOS_UNDEFINED,
138 SDL_WINDOWPOS_UNDEFINED,
139 SCREEN_WIDTH, SCREEN_HEIGHT,
140 g_window_flags);
141
142 GameRenderer = SDL_CreateRenderer(g_game_window, -1, 0);
143 SDL_RenderSetLogicalSize(GameRenderer, SCREEN_WIDTH, SCREEN_HEIGHT);
144
145 SDL_Surface* windowIcon = SDL_CreateRGBSurfaceFrom(
146 (void*)gWindowIconData.pixel_data,
147 gWindowIconData.width,
148 gWindowIconData.height,
149 gWindowIconData.bytes_per_pixel*8,
150 gWindowIconData.bytes_per_pixel*gWindowIconData.width,
151 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
152 SDL_SetWindowIcon(g_game_window, windowIcon);
153 SDL_FreeSurface(windowIcon);
154
155
156 ClippingRect.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
157
158 ScreenBuffer = SDL_CreateRGBSurface(
159 0,
160 SCREEN_WIDTH,
161 SCREEN_HEIGHT,
162 PIXEL_DEPTH,
163 RED_MASK,
164 GREEN_MASK,
165 BLUE_MASK,
166 ALPHA_MASK
167 );
168
169 if (ScreenBuffer == NULL) {
170 SLOGE("SDL_CreateRGBSurface for ScreenBuffer failed: %s\n", SDL_GetError());
171 }
172
173
174 if (ScaleQuality == VideoScaleQuality::PERFECT)
175 {
176 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
177 #if SDL_VERSION_ATLEAST(2,0,5)
178 if (!IsDesktopLargeEnough())
179 {
180 // Pixel-perfect mode cannot handle scaling down, and will
181 // result in a empty black screen if the window size is
182 // smaller than logical render resolution.
183 throw std::runtime_error("Game resolution must not be larger than desktop size. "
184 "Please reduce game resolution or choose another scaling mode.");
185 }
186 SDL_SetWindowMinimumSize(g_game_window, SCREEN_WIDTH, SCREEN_HEIGHT);
187 SDL_RenderSetIntegerScale(GameRenderer, SDL_TRUE);
188 #else
189 SLOGW("Pixel-perfect scaling is not available");
190 ScaleQuality = VideoScaleQuality::NEAR_PERFECT;
191 #endif
192 }
193 else if (ScaleQuality == VideoScaleQuality::NEAR_PERFECT)
194 {
195 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
196 ScaledScreenTexture = SDL_CreateTexture(GameRenderer,
197 SDL_PIXELFORMAT_RGB565,
198 SDL_TEXTUREACCESS_TARGET,
199 SCREEN_WIDTH * OVERSAMPLING_SCALE, SCREEN_HEIGHT * OVERSAMPLING_SCALE);
200
201 if (ScaledScreenTexture == NULL)
202 {
203 SLOGE("SDL_CreateTexture for ScaledScreenTexture failed: %s\n", SDL_GetError());
204 }
205
206 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
207 }
208 else
209 {
210 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
211 }
212
213 ScreenTexture = SDL_CreateTexture(GameRenderer,
214 SDL_PIXELFORMAT_RGB565,
215 SDL_TEXTUREACCESS_STREAMING,
216 SCREEN_WIDTH, SCREEN_HEIGHT);
217
218 if (ScreenTexture == NULL) {
219 SLOGE("SDL_CreateTexture for ScreenTexture failed: %s\n", SDL_GetError());
220 }
221
222 FrameBuffer = SDL_CreateRGBSurface(
223 SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_DEPTH,
224 RED_MASK, GREEN_MASK, BLUE_MASK, ALPHA_MASK
225 );
226
227 if (FrameBuffer == NULL)
228 {
229 SLOGE("SDL_CreateRGBSurface for FrameBuffer failed: %s\n", SDL_GetError());
230 }
231
232 MouseCursor = SDL_CreateRGBSurface(
233 0, MAX_CURSOR_WIDTH, MAX_CURSOR_HEIGHT, PIXEL_DEPTH,
234 RED_MASK, GREEN_MASK, BLUE_MASK, ALPHA_MASK
235 );
236 SDL_SetColorKey(MouseCursor, SDL_TRUE, 0);
237
238 if (MouseCursor == NULL)
239 {
240 SLOGE("SDL_CreateRGBSurface for MouseCursor failed: %s\n", SDL_GetError());
241 }
242
243 SDL_ShowCursor(SDL_DISABLE);
244
245 // Initialize state variables
246 guiFrameBufferState = BUFFER_DIRTY;
247 guiVideoManagerState = VIDEO_ON;
248 guiDirtyRegionCount = 0;
249 gfForceFullScreenRefresh = TRUE;
250
251 // This function must be called to setup RGB information
252 GetRGBDistribution();
253 }
254
255
ShutdownVideoManager(void)256 void ShutdownVideoManager(void)
257 {
258 SLOGD("Shutting down the video manager");
259 /* Toggle the state of the video manager to indicate to the refresh thread
260 * that it needs to shut itself down */
261
262 guiVideoManagerState = VIDEO_OFF;
263
264 if (ScreenBuffer != NULL) {
265 SDL_FreeSurface(ScreenBuffer);
266 ScreenBuffer = NULL;
267 }
268
269 if (ScreenTexture != NULL) {
270 SDL_DestroyTexture(ScreenTexture);
271 ScreenTexture = NULL;
272 }
273
274 if (ScaledScreenTexture != NULL) {
275 SDL_DestroyTexture(ScaledScreenTexture);
276 ScaledScreenTexture = NULL;
277 }
278
279 if (GameRenderer != NULL) {
280 SDL_DestroyRenderer(GameRenderer);
281 GameRenderer = NULL;
282 }
283
284 if (g_game_window != NULL) {
285 SDL_DestroyWindow(g_game_window);
286 g_game_window = NULL;
287 }
288
289 SDL_QuitSubSystem(SDL_INIT_VIDEO);
290
291 // ATE: Release mouse cursor!
292 FreeMouseCursor();
293 }
294
295
SuspendVideoManager(void)296 void SuspendVideoManager(void)
297 {
298 guiVideoManagerState = VIDEO_SUSPENDED;
299 }
300
InvalidateRegion(INT32 iLeft,INT32 iTop,INT32 iRight,INT32 iBottom)301 void InvalidateRegion(INT32 iLeft, INT32 iTop, INT32 iRight, INT32 iBottom)
302 {
303 if (gfForceFullScreenRefresh)
304 {
305 // There's no point in going on since we are forcing a full screen refresh
306 return;
307 }
308
309 if (guiDirtyRegionCount < MAX_DIRTY_REGIONS)
310 {
311 // Well we haven't broken the MAX_DIRTY_REGIONS limit yet, so we register the new region
312
313 // DO SOME PREMIMARY CHECKS FOR VALID RECTS
314 if (iLeft < 0) iLeft = 0;
315 if (iTop < 0) iTop = 0;
316
317 if (iRight > SCREEN_WIDTH) iRight = SCREEN_WIDTH;
318 if (iBottom > SCREEN_HEIGHT) iBottom = SCREEN_HEIGHT;
319
320 if (iRight - iLeft <= 0) return;
321 if (iBottom - iTop <= 0) return;
322
323 DirtyRegions[guiDirtyRegionCount].x = iLeft;
324 DirtyRegions[guiDirtyRegionCount].y = iTop;
325 DirtyRegions[guiDirtyRegionCount].w = iRight - iLeft;
326 DirtyRegions[guiDirtyRegionCount].h = iBottom - iTop;
327 guiDirtyRegionCount++;
328 }
329 else
330 {
331 // The MAX_DIRTY_REGIONS limit has been exceeded. Therefore we arbitrarely invalidate the entire
332 // screen and force a full screen refresh
333 guiDirtyRegionExCount = 0;
334 guiDirtyRegionCount = 0;
335 gfForceFullScreenRefresh = TRUE;
336 }
337 }
338
339
340 static void AddRegionEx(INT32 iLeft, INT32 iTop, INT32 iRight, INT32 iBottom);
341
342
InvalidateRegionEx(INT32 iLeft,INT32 iTop,INT32 iRight,INT32 iBottom)343 void InvalidateRegionEx(INT32 iLeft, INT32 iTop, INT32 iRight, INT32 iBottom)
344 {
345 // Check if we are spanning the rectangle - if so slit it up!
346 if (iTop <= gsVIEWPORT_WINDOW_END_Y && iBottom > gsVIEWPORT_WINDOW_END_Y)
347 {
348 // Add new top region
349 AddRegionEx(iLeft, iTop, iRight, gsVIEWPORT_WINDOW_END_Y);
350
351 // Add new bottom region
352 AddRegionEx(iLeft, gsVIEWPORT_WINDOW_END_Y, iRight, iBottom);
353 }
354 else
355 {
356 AddRegionEx(iLeft, iTop, iRight, iBottom);
357 }
358 }
359
360
AddRegionEx(INT32 iLeft,INT32 iTop,INT32 iRight,INT32 iBottom)361 static void AddRegionEx(INT32 iLeft, INT32 iTop, INT32 iRight, INT32 iBottom)
362 {
363 if (guiDirtyRegionExCount < MAX_DIRTY_REGIONS)
364 {
365 // DO SOME PRELIMINARY CHECKS FOR VALID RECTS
366 if (iLeft < 0) iLeft = 0;
367 if (iTop < 0) iTop = 0;
368
369 if (iRight > SCREEN_WIDTH) iRight = SCREEN_WIDTH;
370 if (iBottom > SCREEN_HEIGHT) iBottom = SCREEN_HEIGHT;
371
372 if (iRight - iLeft <= 0) return;
373 if (iBottom - iTop <= 0) return;
374
375 DirtyRegionsEx[guiDirtyRegionExCount].x = iLeft;
376 DirtyRegionsEx[guiDirtyRegionExCount].y = iTop;
377 DirtyRegionsEx[guiDirtyRegionExCount].w = iRight - iLeft;
378 DirtyRegionsEx[guiDirtyRegionExCount].h = iBottom - iTop;
379 guiDirtyRegionExCount++;
380 }
381 else
382 {
383 guiDirtyRegionExCount = 0;
384 guiDirtyRegionCount = 0;
385 gfForceFullScreenRefresh = TRUE;
386 }
387 }
388
389
InvalidateScreen(void)390 void InvalidateScreen(void)
391 {
392 // W A R N I N G ---- W A R N I N G ---- W A R N I N G ---- W A R N I N G ---- W A R N I N G ----
393 //
394 // This function is intended to be called by a thread which has already locked the
395 // FRAME_BUFFER_MUTEX mutual exclusion section. Anything else will cause the application to
396 // yack
397
398 guiDirtyRegionCount = 0;
399 guiDirtyRegionExCount = 0;
400 gfForceFullScreenRefresh = TRUE;
401 guiFrameBufferState = BUFFER_DIRTY;
402 }
403
404
405 //#define SCROLL_TEST
406
ScrollJA2Background(INT16 sScrollXIncrement,INT16 sScrollYIncrement)407 static void ScrollJA2Background(INT16 sScrollXIncrement, INT16 sScrollYIncrement)
408 {
409 SDL_Surface* Frame = FrameBuffer;
410 SDL_Surface* Source = SDL_CreateRGBSurface(0, ScreenBuffer->w, ScreenBuffer->h, PIXEL_DEPTH, RED_MASK, GREEN_MASK, BLUE_MASK, ALPHA_MASK);
411 SDL_Surface* Dest = ScreenBuffer; // Back
412 SDL_Rect SrcRect;
413 SDL_Rect DstRect;
414 SDL_Rect StripRegions[2];
415 UINT16 NumStrips = 0;
416
417 const UINT16 usWidth = SCREEN_WIDTH;
418 const UINT16 usHeight = gsVIEWPORT_WINDOW_END_Y - gsVIEWPORT_WINDOW_START_Y;
419
420 SDL_BlitSurface(ScreenBuffer, NULL, Source, NULL);
421
422 if (sScrollXIncrement < 0)
423 {
424 SrcRect.x = 0;
425 SrcRect.w = usWidth + sScrollXIncrement;
426 DstRect.x = -sScrollXIncrement;
427 StripRegions[0].x = gsVIEWPORT_START_X;
428 StripRegions[0].y = gsVIEWPORT_WINDOW_START_Y;
429 StripRegions[0].w = -sScrollXIncrement;
430 StripRegions[0].h = usHeight;
431 ++NumStrips;
432 }
433 else if (sScrollXIncrement > 0)
434 {
435 SrcRect.x = sScrollXIncrement;
436 SrcRect.w = usWidth - sScrollXIncrement;
437 DstRect.x = 0;
438 StripRegions[0].x = gsVIEWPORT_END_X - sScrollXIncrement;
439 StripRegions[0].y = gsVIEWPORT_WINDOW_START_Y;
440 StripRegions[0].w = sScrollXIncrement;
441 StripRegions[0].h = usHeight;
442 ++NumStrips;
443 }
444 else
445 {
446 SrcRect.x = 0;
447 SrcRect.w = usWidth;
448 DstRect.x = 0;
449 }
450
451 if (sScrollYIncrement < 0)
452 {
453 SrcRect.y = gsVIEWPORT_WINDOW_START_Y;
454 SrcRect.h = usHeight + sScrollYIncrement;
455 DstRect.y = gsVIEWPORT_WINDOW_START_Y - sScrollYIncrement;
456 StripRegions[NumStrips].x = DstRect.x;
457 StripRegions[NumStrips].y = gsVIEWPORT_WINDOW_START_Y;
458 StripRegions[NumStrips].w = SrcRect.w;
459 StripRegions[NumStrips].h = -sScrollYIncrement;
460 ++NumStrips;
461 }
462 else if (sScrollYIncrement > 0)
463 {
464 SrcRect.y = gsVIEWPORT_WINDOW_START_Y + sScrollYIncrement;
465 SrcRect.h = usHeight - sScrollYIncrement;
466 DstRect.y = gsVIEWPORT_WINDOW_START_Y;
467 StripRegions[NumStrips].x = DstRect.x;
468 StripRegions[NumStrips].y = gsVIEWPORT_WINDOW_END_Y - sScrollYIncrement;
469 StripRegions[NumStrips].w = SrcRect.w;
470 StripRegions[NumStrips].h = sScrollYIncrement;
471 ++NumStrips;
472 }
473 else
474 {
475 SrcRect.y = gsVIEWPORT_WINDOW_START_Y;
476 SrcRect.h = usHeight;
477 DstRect.y = gsVIEWPORT_WINDOW_START_Y;
478 }
479
480 SDL_BlitSurface(Source, &SrcRect, Dest, &DstRect);
481
482 #ifdef SCROLL_TEST
483 SDL_FillRect(Dest, NULL, 0);
484 #endif
485
486 for (UINT i = 0; i < NumStrips; i++)
487 {
488 UINT x = StripRegions[i].x;
489 UINT y = StripRegions[i].y;
490 UINT w = StripRegions[i].w;
491 UINT h = StripRegions[i].h;
492 for (UINT j = y; j < y + h; ++j)
493 {
494 std::fill_n(gpZBuffer + j * SCREEN_WIDTH + x, w, 0);
495 }
496
497 RenderStaticWorldRect(x, y, x + w, y + h, TRUE);
498 SDL_BlitSurface(Frame, &StripRegions[i], Dest, &StripRegions[i]);
499 }
500
501 // RESTORE SHIFTED
502 RestoreShiftedVideoOverlays(sScrollXIncrement, sScrollYIncrement);
503
504 // SAVE NEW
505 SaveVideoOverlaysArea(BACKBUFFER);
506
507 // BLIT NEW
508 ExecuteVideoOverlaysToAlternateBuffer(BACKBUFFER);
509
510 SDL_Texture* screenTexture = SDL_CreateTextureFromSurface(GameRenderer, ScreenBuffer);
511
512 SDL_Rect r;
513 r.x = gsVIEWPORT_START_X;
514 r.y = gsVIEWPORT_WINDOW_START_Y;
515 r.w = gsVIEWPORT_END_X - gsVIEWPORT_START_X;
516 r.h = gsVIEWPORT_WINDOW_END_Y - gsVIEWPORT_WINDOW_START_Y;
517 SDL_RenderCopy(GameRenderer, screenTexture, &r, &r);
518
519 SDL_FreeSurface(Source);
520 SDL_DestroyTexture(screenTexture);
521 }
522
523
RefreshScreen(void)524 void RefreshScreen(void)
525 {
526 if (guiVideoManagerState != VIDEO_ON) return;
527
528 #if DEBUG_PRINT_FPS
529 {
530 static int32_t prevSecond = 0;
531 static int32_t fps = 0;
532
533 int32_t currentSecond = time(NULL);
534 if(currentSecond != prevSecond)
535 {
536 printf("fps: %d\n", fps);
537 fps = 0;
538 prevSecond = currentSecond;
539 }
540 else
541 {
542 fps++;
543 }
544 }
545 #endif
546
547 SDL_BlitSurface(FrameBuffer, &MouseBackground, ScreenBuffer, &MouseBackground);
548
549 const BOOLEAN scrolling = (gsScrollXIncrement != 0 || gsScrollYIncrement != 0);
550
551 if (guiFrameBufferState == BUFFER_DIRTY)
552 {
553 if (gfFadeInitialized && gfFadeInVideo)
554 {
555 gFadeFunction();
556 }
557 else
558 {
559 if (gfForceFullScreenRefresh)
560 {
561 SDL_BlitSurface(FrameBuffer, NULL, ScreenBuffer, NULL);
562 }
563 else
564 {
565 for (UINT32 i = 0; i < guiDirtyRegionCount; i++)
566 {
567 SDL_BlitSurface(FrameBuffer, &DirtyRegions[i], ScreenBuffer, &DirtyRegions[i]);
568 }
569
570 for (UINT32 i = 0; i < guiDirtyRegionExCount; i++)
571 {
572 SDL_Rect* r = &DirtyRegionsEx[i];
573 if (scrolling)
574 {
575 // Check if we are completely out of bounds
576 if (r->y <= gsVIEWPORT_WINDOW_END_Y && r->y + r->h <= gsVIEWPORT_WINDOW_END_Y)
577 {
578 continue;
579 }
580 }
581 SDL_BlitSurface(FrameBuffer, r, ScreenBuffer, r);
582 }
583 }
584 }
585 if (scrolling)
586 {
587 ScrollJA2Background(gsScrollXIncrement, gsScrollYIncrement);
588 gsScrollXIncrement = 0;
589 gsScrollYIncrement = 0;
590 }
591 gfIgnoreScrollDueToCenterAdjust = FALSE;
592 guiFrameBufferState = BUFFER_READY;
593 }
594
595 SGPPoint MousePos;
596 GetMousePos(&MousePos);
597 SDL_Rect src;
598 src.x = 0;
599 src.y = 0;
600 src.w = gusMouseCursorWidth;
601 src.h = gusMouseCursorHeight;
602 SDL_Rect dst;
603 dst.x = MousePos.iX - gsMouseCursorXOffset;
604 dst.y = MousePos.iY - gsMouseCursorYOffset;
605 SDL_BlitSurface(MouseCursor, &src, ScreenBuffer, &dst);
606 MouseBackground = dst;
607
608 SDL_UpdateTexture(ScreenTexture, NULL, ScreenBuffer->pixels, ScreenBuffer->pitch);
609
610 SDL_RenderClear(GameRenderer);
611
612 if (ScaleQuality == VideoScaleQuality::NEAR_PERFECT) {
613 SDL_SetRenderTarget(GameRenderer, ScaledScreenTexture);
614 SDL_RenderCopy(GameRenderer, ScreenTexture, nullptr, nullptr);
615
616 SDL_SetRenderTarget(GameRenderer, nullptr);
617 SDL_RenderCopy(GameRenderer, ScaledScreenTexture, nullptr, nullptr);
618 }
619 else {
620 SDL_RenderCopy(GameRenderer, ScreenTexture, NULL, NULL);
621 }
622
623 SDL_RenderPresent(GameRenderer);
624
625 gfForceFullScreenRefresh = FALSE;
626 guiDirtyRegionCount = 0;
627 guiDirtyRegionExCount = 0;
628 }
629
630
GetRGBDistribution()631 static void GetRGBDistribution()
632 {
633 SDL_PixelFormat const& f = *ScreenBuffer->format;
634
635 UINT32 const r = f.Rmask;
636 UINT32 const g = f.Gmask;
637 UINT32 const b = f.Bmask;
638
639 /* Mask the highest bit of each component. This is used for alpha blending. */
640 guiTranslucentMask = (r & r >> 1) | (g & g >> 1) | (b & b >> 1);
641
642 gusRedMask = r;
643 gusGreenMask = g;
644 gusBlueMask = b;
645
646 gusRedShift = f.Rshift - f.Rloss;
647 gusGreenShift = f.Gshift - f.Gloss;
648 gusBlueShift = f.Bshift - f.Bloss;
649 }
650
651
GetPrimaryRGBDistributionMasks(UINT32 * const RedBitMask,UINT32 * const GreenBitMask,UINT32 * const BlueBitMask)652 void GetPrimaryRGBDistributionMasks(UINT32* const RedBitMask, UINT32* const GreenBitMask, UINT32* const BlueBitMask)
653 {
654 *RedBitMask = gusRedMask;
655 *GreenBitMask = gusGreenMask;
656 *BlueBitMask = gusBlueMask;
657 }
658
659
SetMouseCursorProperties(INT16 sOffsetX,INT16 sOffsetY,UINT16 usCursorHeight,UINT16 usCursorWidth)660 void SetMouseCursorProperties(INT16 sOffsetX, INT16 sOffsetY, UINT16 usCursorHeight, UINT16 usCursorWidth)
661 {
662 gsMouseCursorXOffset = sOffsetX;
663 gsMouseCursorYOffset = sOffsetY;
664 gusMouseCursorWidth = usCursorWidth;
665 gusMouseCursorHeight = usCursorHeight;
666 }
667
668
EndFrameBufferRender(void)669 void EndFrameBufferRender(void)
670 {
671 guiFrameBufferState = BUFFER_DIRTY;
672 }
673
674
RecreateBackBuffer()675 static void RecreateBackBuffer()
676 {
677 // ScreenBuffer should not be automatically removed because it was created
678 // with SDL_SetVideoMode. So, using SGPVSurface instead of SGPVSurfaceAuto
679 SGPVSurface* newBackbuffer = new SGPVSurface(ScreenBuffer);
680
681 if(g_back_buffer != NULL)
682 {
683 ReplaceFontBackBuffer(g_back_buffer, newBackbuffer);
684
685 delete g_back_buffer;
686 g_back_buffer = NULL;
687 }
688
689 g_back_buffer = newBackbuffer;
690 }
691
SetPrimaryVideoSurfaces(void)692 static void SetPrimaryVideoSurfaces(void)
693 {
694 // Delete surfaces if they exist
695 DeletePrimaryVideoSurfaces();
696
697 RecreateBackBuffer();
698
699 g_mouse_buffer = new SGPVSurfaceAuto(MouseCursor);
700 g_frame_buffer = new SGPVSurfaceAuto(FrameBuffer);
701 }
702
DeletePrimaryVideoSurfaces(void)703 static void DeletePrimaryVideoSurfaces(void)
704 {
705 delete g_back_buffer;
706 g_back_buffer = NULL;
707
708 delete g_frame_buffer;
709 g_frame_buffer = NULL;
710
711 delete g_mouse_buffer;
712 g_mouse_buffer = NULL;
713 }
714
715 SGPVSurface* gpVSurfaceHead = 0;
716
InitializeVideoSurfaceManager(void)717 void InitializeVideoSurfaceManager(void)
718 {
719 //Shouldn't be calling this if the video surface manager already exists.
720 //Call shutdown first...
721 Assert(gpVSurfaceHead == NULL);
722 gpVSurfaceHead = NULL;
723
724 // Create primary and backbuffer from globals
725 SetPrimaryVideoSurfaces();
726 }
727
728
ShutdownVideoSurfaceManager(void)729 void ShutdownVideoSurfaceManager(void)
730 {
731 SLOGD("Shutting down the Video Surface manager");
732
733 // Delete primary viedeo surfaces
734 DeletePrimaryVideoSurfaces();
735
736 while (gpVSurfaceHead)
737 {
738 delete gpVSurfaceHead;
739 }
740 }
741