OpenTTD Source 20260711-master-g3fb3006dff
sdl2_default_v.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11#include "../openttd.h"
12#include "../error_func.h"
13#include "../gfx_func.h"
14#include "../rev.h"
16#include "../network/network.h"
17#include "../thread.h"
18#include "../progress.h"
20#include "../fileio_func.h"
21#include "../framerate_type.h"
22#include "../window_func.h"
23#include "sdl2_default_v.h"
24#include <SDL.h>
25#include <mutex>
26#include <condition_variable>
27#ifdef __EMSCRIPTEN__
28# include <emscripten.h>
29# include <emscripten/html5.h>
30#endif
31
32#include "../safeguards.h"
33
35
36static SDL_Surface *_sdl_surface;
37static SDL_Surface *_sdl_rgb_surface;
38static SDL_Surface *_sdl_real_surface;
39static SDL_Palette *_sdl_palette;
40
45{
46 SDL_Color pal[256];
47
48 for (int i = 0; i != this->local_palette.count_dirty; i++) {
49 pal[i].r = this->local_palette.palette[this->local_palette.first_dirty + i].r;
50 pal[i].g = this->local_palette.palette[this->local_palette.first_dirty + i].g;
51 pal[i].b = this->local_palette.palette[this->local_palette.first_dirty + i].b;
52 pal[i].a = 0;
53 }
54
55 SDL_SetPaletteColors(_sdl_palette, pal, this->local_palette.first_dirty, this->local_palette.count_dirty);
56 SDL_SetSurfacePalette(_sdl_surface, _sdl_palette);
57}
58
63{
64 if (_sdl_palette == nullptr) {
65 _sdl_palette = SDL_AllocPalette(256);
66 if (_sdl_palette == nullptr) UserError("SDL2: Couldn't allocate palette: {}", SDL_GetError());
67 }
68
69 CopyPalette(this->local_palette, true);
70 this->UpdatePalette();
71
73 /* When using a shadow surface, also set our palette on the real screen. This lets SDL
74 * allocate as many colours (or approximations) as
75 * possible, instead of using only the default SDL
76 * palette. This allows us to get more colours exactly
77 * right and might allow using better approximations for
78 * other colours.
79 *
80 * Note that colours allocations are tried in-order, so
81 * this favors colours further up into the palette. Also
82 * note that if two colours from the same animation
83 * sequence are approximated using the same colour, that
84 * animation will stop working.
85 *
86 * Since changing the system palette causes the colours
87 * to change right away, and allocations might
88 * drastically change, we can't use this for animation,
89 * since that could cause weird colouring between the
90 * palette change and the blitting below, so we only set
91 * the real palette during initialisation.
92 */
93 SDL_SetSurfacePalette(_sdl_real_surface, _sdl_palette);
94 }
95}
96
98{
100
101 if (IsEmptyRect(this->dirty_rect) && this->local_palette.count_dirty == 0) return;
102
103 if (this->local_palette.count_dirty != 0) {
105
106 switch (blitter->UsePaletteAnimation()) {
108 this->UpdatePalette();
109 break;
110
112 blitter->PaletteAnimate(this->local_palette);
113 break;
114 }
115
117 break;
118
119 default:
120 NOT_REACHED();
121 }
122 this->local_palette.count_dirty = 0;
123 }
124
125 SDL_Rect r = { this->dirty_rect.left, this->dirty_rect.top, this->dirty_rect.right - this->dirty_rect.left, this->dirty_rect.bottom - this->dirty_rect.top };
126
128 SDL_BlitSurface(_sdl_surface, &r, _sdl_real_surface, &r);
129 }
130 SDL_UpdateWindowSurfaceRects(this->sdl_window, &r, 1);
131
132 this->dirty_rect = {};
133}
134
136{
138
139 _sdl_real_surface = SDL_GetWindowSurface(this->sdl_window);
140 if (_sdl_real_surface == nullptr) UserError("SDL2: Couldn't get window surface: {}", SDL_GetError());
141
142 if (!force && w == _sdl_real_surface->w && h == _sdl_real_surface->h) return false;
143
144 /* Free any previously allocated rgb surface. */
145 if (_sdl_rgb_surface != nullptr) {
146 SDL_FreeSurface(_sdl_rgb_surface);
147 _sdl_rgb_surface = nullptr;
148 }
149
150 if (bpp == 8) {
151 _sdl_rgb_surface = SDL_CreateRGBSurface(0, w, h, 8, 0, 0, 0, 0);
152 if (_sdl_rgb_surface == nullptr) UserError("SDL2: Couldn't allocate shadow surface: {}", SDL_GetError());
153
155 } else {
157 }
158
159 /* X11 doesn't appreciate it if we invalidate areas outside the window
160 * if shared memory is enabled (read: it crashes). So, as we might have
161 * gotten smaller, reset our dirty rects. GameSizeChanged() a bit lower
162 * will mark the whole screen dirty again anyway, but this time with the
163 * new dimensions. */
164 this->dirty_rect = {};
165
166 _screen.width = _sdl_surface->w;
167 _screen.height = _sdl_surface->h;
168 _screen.pitch = _sdl_surface->pitch / (bpp / 8);
169 _screen.dst_ptr = this->GetVideoPointer();
170
171 this->MakePalette();
172
173 return true;
174}
175
177{
178 return _sdl_surface->pixels;
179}
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:139
How all blitters should look like.
Definition base.hpp:29
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
virtual Blitter::PaletteAnimation UsePaletteAnimation()=0
Check if the blitter uses palette animation at all.
virtual void PaletteAnimate(const Palette &palette)=0
Called when the 8bpp palette is changed; you should redraw all pixels on the screen that are equal to...
@ None
No palette animation.
Definition base.hpp:51
@ Blitter
The blitter takes care of the palette animation.
Definition base.hpp:53
@ VideoBackend
Palette animation should be done by video backend (8bpp only!).
Definition base.hpp:52
Factory for the SDL video driver.
RAII class for measuring simple elements of performance.
Palette local_palette
Current palette to use for drawing.
Definition sdl2_v.h:54
Rect dirty_rect
Rectangle encompassing the dirty area of the video buffer.
Definition sdl2_v.h:56
struct SDL_Window * sdl_window
Main SDL window.
Definition sdl2_v.h:53
void UpdatePalette()
Update the dirty palette colours.
bool AllocateBackingStore(int w, int h, bool force=false) override
(Re-)create the backing store.
void * GetVideoPointer() override
Get a pointer to the video buffer.
void Paint() override
Paint the window.
void MakePalette()
Allocate and configure the palette.
Error reporting related functions.
Factory to 'query' all available blitters.
Functions for standard in/out file operations.
Types for recording game performance data.
@ Video
Speed of painting drawn video buffer.
Geometry functions.
bool IsEmptyRect(const Rect &r)
Check if a rectangle is empty.
Functions related to the gfx engine.
Basic functions/variables used all over the place.
Some generic types.
bool CopyPalette(Palette &local_palette, bool force_copy)
Copy the current palette if the palette was updated.
Definition palette.cpp:230
Functions related to modal progress.
Declaration of OTTD revision dependent variables.
A number of safeguards to prevent using unsafe methods.
static SDL_Palette * _sdl_palette
The palette mapping.
static FVideoDriver_SDL_Default iFVideoDriver_SDL_Default
The default, non-GL, SDL video driver.
static SDL_Surface * _sdl_real_surface
The actual surface of the screen.
static SDL_Surface * _sdl_rgb_surface
Optional surface to use for blitting all changes at once.
static SDL_Surface * _sdl_surface
The surface to draw on/to.
Default backend of the SDL2 video driver.
Definition of base types and functions in a cross-platform compatible way.
Base of all threads.
Window functions not directly related to making/drawing windows.