Fix #8316: Make sort industries by production and transported with a cargo filter...
[openttd-github.git] / src / video / sdl2_default_v.cpp
blobe164e499e898012ad65b05b47766dac6393cf137
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 <http://www.gnu.org/licenses/>.
6 */
8 /** @file sdl2_default_v.cpp Implementation of the default backend for SDL2 video driver. */
10 #include "../stdafx.h"
11 #include "../openttd.h"
12 #include "../gfx_func.h"
13 #include "../rev.h"
14 #include "../blitter/factory.hpp"
15 #include "../network/network.h"
16 #include "../thread.h"
17 #include "../progress.h"
18 #include "../core/random_func.hpp"
19 #include "../core/math_func.hpp"
20 #include "../core/mem_func.hpp"
21 #include "../core/geometry_func.hpp"
22 #include "../fileio_func.h"
23 #include "../framerate_type.h"
24 #include "../window_func.h"
25 #include "sdl2_default_v.h"
26 #include <SDL.h>
27 #include <mutex>
28 #include <condition_variable>
29 #ifdef __EMSCRIPTEN__
30 # include <emscripten.h>
31 # include <emscripten/html5.h>
32 #endif
34 #include "../safeguards.h"
36 static FVideoDriver_SDL_Default iFVideoDriver_SDL_Default;
38 static SDL_Surface *_sdl_surface;
39 static SDL_Surface *_sdl_rgb_surface;
40 static SDL_Surface *_sdl_real_surface;
41 static SDL_Palette *_sdl_palette;
43 void VideoDriver_SDL_Default::UpdatePalette()
45 SDL_Color pal[256];
47 for (int i = 0; i != this->local_palette.count_dirty; i++) {
48 pal[i].r = this->local_palette.palette[this->local_palette.first_dirty + i].r;
49 pal[i].g = this->local_palette.palette[this->local_palette.first_dirty + i].g;
50 pal[i].b = this->local_palette.palette[this->local_palette.first_dirty + i].b;
51 pal[i].a = 0;
54 SDL_SetPaletteColors(_sdl_palette, pal, this->local_palette.first_dirty, this->local_palette.count_dirty);
55 SDL_SetSurfacePalette(_sdl_surface, _sdl_palette);
58 void VideoDriver_SDL_Default::MakePalette()
60 if (_sdl_palette == nullptr) {
61 _sdl_palette = SDL_AllocPalette(256);
62 if (_sdl_palette == nullptr) usererror("SDL2: Couldn't allocate palette: %s", SDL_GetError());
65 CopyPalette(this->local_palette, true);
66 this->UpdatePalette();
68 if (_sdl_surface != _sdl_real_surface) {
69 /* When using a shadow surface, also set our palette on the real screen. This lets SDL
70 * allocate as many colors (or approximations) as
71 * possible, instead of using only the default SDL
72 * palette. This allows us to get more colors exactly
73 * right and might allow using better approximations for
74 * other colors.
76 * Note that colors allocations are tried in-order, so
77 * this favors colors further up into the palette. Also
78 * note that if two colors from the same animation
79 * sequence are approximated using the same color, that
80 * animation will stop working.
82 * Since changing the system palette causes the colours
83 * to change right away, and allocations might
84 * drastically change, we can't use this for animation,
85 * since that could cause weird coloring between the
86 * palette change and the blitting below, so we only set
87 * the real palette during initialisation.
89 SDL_SetSurfacePalette(_sdl_real_surface, _sdl_palette);
93 void VideoDriver_SDL_Default::Paint()
95 PerformanceMeasurer framerate(PFE_VIDEO);
97 if (IsEmptyRect(this->dirty_rect) && this->local_palette.count_dirty == 0) return;
99 if (this->local_palette.count_dirty != 0) {
100 Blitter *blitter = BlitterFactory::GetCurrentBlitter();
102 switch (blitter->UsePaletteAnimation()) {
103 case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
104 this->UpdatePalette();
105 break;
107 case Blitter::PALETTE_ANIMATION_BLITTER: {
108 blitter->PaletteAnimate(this->local_palette);
109 break;
112 case Blitter::PALETTE_ANIMATION_NONE:
113 break;
115 default:
116 NOT_REACHED();
118 this->local_palette.count_dirty = 0;
121 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 };
123 if (_sdl_surface != _sdl_real_surface) {
124 SDL_BlitSurface(_sdl_surface, &r, _sdl_real_surface, &r);
126 SDL_UpdateWindowSurfaceRects(this->sdl_window, &r, 1);
128 this->dirty_rect = {};
131 bool VideoDriver_SDL_Default::AllocateBackingStore(int w, int h, bool force)
133 int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
135 _sdl_real_surface = SDL_GetWindowSurface(this->sdl_window);
136 if (_sdl_real_surface == nullptr) usererror("SDL2: Couldn't get window surface: %s", SDL_GetError());
138 if (!force && w == _sdl_real_surface->w && h == _sdl_real_surface->h) return false;
140 /* Free any previously allocated rgb surface. */
141 if (_sdl_rgb_surface != nullptr) {
142 SDL_FreeSurface(_sdl_rgb_surface);
143 _sdl_rgb_surface = nullptr;
146 if (bpp == 8) {
147 _sdl_rgb_surface = SDL_CreateRGBSurface(0, w, h, 8, 0, 0, 0, 0);
148 if (_sdl_rgb_surface == nullptr) usererror("SDL2: Couldn't allocate shadow surface: %s", SDL_GetError());
150 _sdl_surface = _sdl_rgb_surface;
151 } else {
152 _sdl_surface = _sdl_real_surface;
155 /* X11 doesn't appreciate it if we invalidate areas outside the window
156 * if shared memory is enabled (read: it crashes). So, as we might have
157 * gotten smaller, reset our dirty rects. GameSizeChanged() a bit lower
158 * will mark the whole screen dirty again anyway, but this time with the
159 * new dimensions. */
160 this->dirty_rect = {};
162 _screen.width = _sdl_surface->w;
163 _screen.height = _sdl_surface->h;
164 _screen.pitch = _sdl_surface->pitch / (bpp / 8);
165 _screen.dst_ptr = this->GetVideoPointer();
167 this->MakePalette();
169 return true;
172 void *VideoDriver_SDL_Default::GetVideoPointer()
174 return _sdl_surface->pixels;