File diff r24917:32c68f7840b0 → r24918:e55bb9103b0b
src/video/sdl2_v.cpp
Show inline comments
 
@@ -32,77 +32,18 @@
 

	
 
#include "../safeguards.h"
 

	
 
static FVideoDriver_SDL iFVideoDriver_SDL;
 

	
 
static SDL_Surface *_sdl_surface;
 
static SDL_Surface *_sdl_rgb_surface;
 
static SDL_Surface *_sdl_real_surface;
 
static SDL_Palette *_sdl_palette;
 

	
 
#ifdef __EMSCRIPTEN__
 
/** Whether we just had a window-enter event. */
 
static bool _cursor_new_in_window = false;
 
#endif
 

	
 
void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height)
 
void VideoDriver_SDL_Base::MakeDirty(int left, int top, int width, int height)
 
{
 
	Rect r = {left, top, left + width, top + height};
 
	this->dirty_rect = BoundingRect(this->dirty_rect, r);
 
}
 

	
 
void VideoDriver_SDL::UpdatePalette()
 
{
 
	SDL_Color pal[256];
 

	
 
	for (int i = 0; i != this->local_palette.count_dirty; i++) {
 
		pal[i].r = this->local_palette.palette[this->local_palette.first_dirty + i].r;
 
		pal[i].g = this->local_palette.palette[this->local_palette.first_dirty + i].g;
 
		pal[i].b = this->local_palette.palette[this->local_palette.first_dirty + i].b;
 
		pal[i].a = 0;
 
	}
 

	
 
	SDL_SetPaletteColors(_sdl_palette, pal, this->local_palette.first_dirty, this->local_palette.count_dirty);
 
	SDL_SetSurfacePalette(_sdl_surface, _sdl_palette);
 
}
 

	
 
void VideoDriver_SDL::MakePalette()
 
{
 
	if (_sdl_palette == nullptr) {
 
		_sdl_palette = SDL_AllocPalette(256);
 
		if (_sdl_palette == nullptr) usererror("SDL2: Couldn't allocate palette: %s", SDL_GetError());
 
	}
 

	
 
	_cur_palette.first_dirty = 0;
 
	_cur_palette.count_dirty = 256;
 
	this->local_palette = _cur_palette;
 
	this->UpdatePalette();
 

	
 
	if (_sdl_surface != _sdl_real_surface) {
 
		/* When using a shadow surface, also set our palette on the real screen. This lets SDL
 
		 * allocate as many colors (or approximations) as
 
		 * possible, instead of using only the default SDL
 
		 * palette. This allows us to get more colors exactly
 
		 * right and might allow using better approximations for
 
		 * other colors.
 
		 *
 
		 * Note that colors allocations are tried in-order, so
 
		 * this favors colors further up into the palette. Also
 
		 * note that if two colors from the same animation
 
		 * sequence are approximated using the same color, that
 
		 * animation will stop working.
 
		 *
 
		 * Since changing the system palette causes the colours
 
		 * to change right away, and allocations might
 
		 * drastically change, we can't use this for animation,
 
		 * since that could cause weird coloring between the
 
		 * palette change and the blitting below, so we only set
 
		 * the real palette during initialisation.
 
		 */
 
		SDL_SetSurfacePalette(_sdl_real_surface, _sdl_palette);
 
	}
 
}
 

	
 
void VideoDriver_SDL::CheckPaletteAnim()
 
void VideoDriver_SDL_Base::CheckPaletteAnim()
 
{
 
	if (_cur_palette.count_dirty == 0) return;
 

	
 
@@ -110,67 +51,7 @@ void VideoDriver_SDL::CheckPaletteAnim()
 
	this->MakeDirty(0, 0, _screen.width, _screen.height);
 
}
 

	
 
void VideoDriver_SDL::Paint()
 
{
 
	PerformanceMeasurer framerate(PFE_VIDEO);
 

	
 
	if (IsEmptyRect(this->dirty_rect) && _cur_palette.count_dirty == 0) return;
 

	
 
	if (_cur_palette.count_dirty != 0) {
 
		Blitter *blitter = BlitterFactory::GetCurrentBlitter();
 

	
 
		switch (blitter->UsePaletteAnimation()) {
 
			case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND:
 
				this->UpdatePalette();
 
				break;
 

	
 
			case Blitter::PALETTE_ANIMATION_BLITTER: {
 
				bool need_buf = _screen.dst_ptr == nullptr;
 
				if (need_buf) _screen.dst_ptr = this->GetVideoPointer();
 
				blitter->PaletteAnimate(this->local_palette);
 
				if (need_buf) {
 
					this->ReleaseVideoPointer();
 
					_screen.dst_ptr = nullptr;
 
				}
 
				break;
 
			}
 

	
 
			case Blitter::PALETTE_ANIMATION_NONE:
 
				break;
 

	
 
			default:
 
				NOT_REACHED();
 
		}
 
		_cur_palette.count_dirty = 0;
 
	}
 

	
 
	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 };
 

	
 
	if (_sdl_surface != _sdl_real_surface) {
 
		SDL_BlitSurface(_sdl_surface, &r, _sdl_real_surface, &r);
 
	}
 
	SDL_UpdateWindowSurfaceRects(this->sdl_window, &r, 1);
 

	
 
	this->dirty_rect = {};
 
}
 

	
 
void VideoDriver_SDL::PaintThread()
 
{
 
	/* First tell the main thread we're started */
 
	std::unique_lock<std::recursive_mutex> lock(*this->draw_mutex);
 
	this->draw_signal->notify_one();
 

	
 
	/* Now wait for the first thing to draw! */
 
	this->draw_signal->wait(*this->draw_mutex);
 

	
 
	while (this->draw_continue) {
 
		/* Then just draw and wait till we stop */
 
		this->Paint();
 
		this->draw_signal->wait(lock);
 
	}
 
}
 

	
 
/* static */ void VideoDriver_SDL::PaintThreadThunk(VideoDriver_SDL *drv)
 
/* static */ void VideoDriver_SDL_Base::PaintThreadThunk(VideoDriver_SDL_Base *drv)
 
{
 
	drv->PaintThread();
 
}
 
@@ -253,7 +134,7 @@ static uint FindStartupDisplay(uint star
 
	return 0;
 
}
 

	
 
void VideoDriver_SDL::ClientSizeChanged(int w, int h, bool force)
 
void VideoDriver_SDL_Base::ClientSizeChanged(int w, int h, bool force)
 
{
 
	/* Allocate backing store of the new size. */
 
	if (this->AllocateBackingStore(w, h, force)) {
 
@@ -268,7 +149,7 @@ void VideoDriver_SDL::ClientSizeChanged(
 
	}
 
}
 

	
 
bool VideoDriver_SDL::CreateMainWindow(uint w, uint h, uint flags)
 
bool VideoDriver_SDL_Base::CreateMainWindow(uint w, uint h, uint flags)
 
{
 
	if (this->sdl_window != nullptr) return true;
 

	
 
@@ -315,7 +196,7 @@ bool VideoDriver_SDL::CreateMainWindow(u
 
	return true;
 
}
 

	
 
bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize)
 
bool VideoDriver_SDL_Base::CreateMainSurface(uint w, uint h, bool resize)
 
{
 
	GetAvailableVideoMode(&w, &h);
 
	DEBUG(driver, 1, "SDL2: using mode %ux%u", w, h);
 
@@ -332,53 +213,7 @@ bool VideoDriver_SDL::CreateMainSurface(
 
	return true;
 
}
 

	
 
bool VideoDriver_SDL::AllocateBackingStore(int w, int h, bool force)
 
{
 
	int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 

	
 
	_sdl_real_surface = SDL_GetWindowSurface(this->sdl_window);
 
	if (_sdl_real_surface == nullptr) usererror("SDL2: Couldn't get window surface: %s", SDL_GetError());
 

	
 
	if (!force && w == _sdl_real_surface->w && h == _sdl_real_surface->h) return false;
 

	
 
	/* Free any previously allocated rgb surface. */
 
	if (_sdl_rgb_surface != nullptr) {
 
		SDL_FreeSurface(_sdl_rgb_surface);
 
		_sdl_rgb_surface = nullptr;
 
	}
 

	
 
	if (bpp == 8) {
 
		_sdl_rgb_surface = SDL_CreateRGBSurface(0, w, h, 8, 0, 0, 0, 0);
 
		if (_sdl_rgb_surface == nullptr) usererror("SDL2: Couldn't allocate shadow surface: %s", SDL_GetError());
 

	
 
		_sdl_surface = _sdl_rgb_surface;
 
	} else {
 
		_sdl_surface = _sdl_real_surface;
 
	}
 

	
 
	/* X11 doesn't appreciate it if we invalidate areas outside the window
 
	 * if shared memory is enabled (read: it crashes). So, as we might have
 
	 * gotten smaller, reset our dirty rects. GameSizeChanged() a bit lower
 
	 * will mark the whole screen dirty again anyway, but this time with the
 
	 * new dimensions. */
 
	this->dirty_rect = {};
 

	
 
	_screen.width = _sdl_surface->w;
 
	_screen.height = _sdl_surface->h;
 
	_screen.pitch = _sdl_surface->pitch / (bpp / 8);
 
	_screen.dst_ptr = this->GetVideoPointer();
 

	
 
	this->MakePalette();
 

	
 
	return true;
 
}
 

	
 
void *VideoDriver_SDL::GetVideoPointer()
 
{
 
	return _sdl_surface->pixels;
 
}
 

	
 
bool VideoDriver_SDL::ClaimMousePointer()
 
bool VideoDriver_SDL_Base::ClaimMousePointer()
 
{
 
	SDL_ShowCursor(0);
 
#ifdef __EMSCRIPTEN__
 
@@ -390,7 +225,7 @@ bool VideoDriver_SDL::ClaimMousePointer(
 
/**
 
 * This is called to indicate that an edit box has gained focus, text input mode should be enabled.
 
 */
 
void VideoDriver_SDL::EditBoxGainedFocus()
 
void VideoDriver_SDL_Base::EditBoxGainedFocus()
 
{
 
	if (!this->edit_box_focused) {
 
		SDL_StartTextInput();
 
@@ -401,7 +236,7 @@ void VideoDriver_SDL::EditBoxGainedFocus
 
/**
 
 * This is called to indicate that an edit box has lost focus, text input mode should be disabled.
 
 */
 
void VideoDriver_SDL::EditBoxLostFocus()
 
void VideoDriver_SDL_Base::EditBoxLostFocus()
 
{
 
	if (this->edit_box_focused) {
 
		SDL_StopTextInput();
 
@@ -535,7 +370,7 @@ static uint ConvertSdlKeycodeIntoMy(SDL_
 
	return key;
 
}
 

	
 
int VideoDriver_SDL::PollEvent()
 
int VideoDriver_SDL_Base::PollEvent()
 
{
 
	SDL_Event ev;
 

	
 
@@ -699,7 +534,7 @@ static const char *InitializeSDL()
 
	return nullptr;
 
}
 

	
 
const char *VideoDriver_SDL::Initialize()
 
const char *VideoDriver_SDL_Base::Initialize()
 
{
 
	this->UpdateAutoResolution();
 

	
 
@@ -712,7 +547,7 @@ const char *VideoDriver_SDL::Initialize(
 
	return nullptr;
 
}
 

	
 
const char *VideoDriver_SDL::Start(const StringList &parm)
 
const char *VideoDriver_SDL_Base::Start(const StringList &parm)
 
{
 
	if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return "Only real blitters supported";
 

	
 
@@ -749,7 +584,7 @@ const char *VideoDriver_SDL::Start(const
 
	return nullptr;
 
}
 

	
 
void VideoDriver_SDL::Stop()
 
void VideoDriver_SDL_Base::Stop()
 
{
 
	SDL_QuitSubSystem(SDL_INIT_VIDEO);
 
	if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) {
 
@@ -757,7 +592,7 @@ void VideoDriver_SDL::Stop()
 
	}
 
}
 

	
 
void VideoDriver_SDL::InputLoop()
 
void VideoDriver_SDL_Base::InputLoop()
 
{
 
	uint32 mod = SDL_GetModState();
 
	const Uint8 *keys = SDL_GetKeyboardState(NULL);
 
@@ -790,7 +625,7 @@ void VideoDriver_SDL::InputLoop()
 
	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
 
}
 

	
 
void VideoDriver_SDL::LoopOnce()
 
void VideoDriver_SDL_Base::LoopOnce()
 
{
 
	InteractiveRandom(); // randomness
 

	
 
@@ -824,7 +659,7 @@ void VideoDriver_SDL::LoopOnce()
 
#endif
 
}
 

	
 
void VideoDriver_SDL::MainLoop()
 
void VideoDriver_SDL_Base::MainLoop()
 
{
 
	if (this->draw_threaded) {
 
		/* Initialise the mutex first, because that's the thing we *need*
 
@@ -837,7 +672,7 @@ void VideoDriver_SDL::MainLoop()
 
			this->draw_signal = new std::condition_variable_any();
 
			this->draw_continue = true;
 

	
 
			this->draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &VideoDriver_SDL::PaintThreadThunk, this);
 
			this->draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &VideoDriver_SDL_Base::PaintThreadThunk, this);
 

	
 
			/* Free the mutex if we won't be able to use it. */
 
			if (!this->draw_threaded) {
 
@@ -868,7 +703,7 @@ void VideoDriver_SDL::MainLoop()
 
#endif
 
}
 

	
 
void VideoDriver_SDL::MainLoopCleanup()
 
void VideoDriver_SDL_Base::MainLoopCleanup()
 
{
 
	if (this->draw_mutex != nullptr) {
 
		this->draw_continue = false;
 
@@ -896,7 +731,7 @@ void VideoDriver_SDL::MainLoopCleanup()
 
#endif
 
}
 

	
 
bool VideoDriver_SDL::ChangeResolution(int w, int h)
 
bool VideoDriver_SDL_Base::ChangeResolution(int w, int h)
 
{
 
	std::unique_lock<std::recursive_mutex> lock;
 
	if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
 
@@ -904,7 +739,7 @@ bool VideoDriver_SDL::ChangeResolution(i
 
	return CreateMainSurface(w, h, true);
 
}
 

	
 
bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
 
bool VideoDriver_SDL_Base::ToggleFullscreen(bool fullscreen)
 
{
 
	std::unique_lock<std::recursive_mutex> lock;
 
	if (this->draw_mutex != nullptr) lock = std::unique_lock<std::recursive_mutex>(*this->draw_mutex);
 
@@ -937,7 +772,7 @@ bool VideoDriver_SDL::ToggleFullscreen(b
 
	return ret == 0;
 
}
 

	
 
bool VideoDriver_SDL::AfterBlitterChange()
 
bool VideoDriver_SDL_Base::AfterBlitterChange()
 
{
 
	assert(BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 0);
 
	int w, h;
 
@@ -945,17 +780,17 @@ bool VideoDriver_SDL::AfterBlitterChange
 
	return CreateMainSurface(w, h, false);
 
}
 

	
 
void VideoDriver_SDL::AcquireBlitterLock()
 
void VideoDriver_SDL_Base::AcquireBlitterLock()
 
{
 
	if (this->draw_mutex != nullptr) this->draw_mutex->lock();
 
}
 

	
 
void VideoDriver_SDL::ReleaseBlitterLock()
 
void VideoDriver_SDL_Base::ReleaseBlitterLock()
 
{
 
	if (this->draw_mutex != nullptr) this->draw_mutex->unlock();
 
}
 

	
 
Dimension VideoDriver_SDL::GetScreenSize() const
 
Dimension VideoDriver_SDL_Base::GetScreenSize() const
 
{
 
	SDL_DisplayMode mode;
 
	if (SDL_GetCurrentDisplayMode(this->startup_display, &mode) != 0) return VideoDriver::GetScreenSize();
 
@@ -963,7 +798,7 @@ Dimension VideoDriver_SDL::GetScreenSize
 
	return { static_cast<uint>(mode.w), static_cast<uint>(mode.h) };
 
}
 

	
 
bool VideoDriver_SDL::LockVideoBuffer()
 
bool VideoDriver_SDL_Base::LockVideoBuffer()
 
{
 
	if (this->buffer_locked) return false;
 
	this->buffer_locked = true;
 
@@ -976,7 +811,7 @@ bool VideoDriver_SDL::LockVideoBuffer()
 
	return true;
 
}
 

	
 
void VideoDriver_SDL::UnlockVideoBuffer()
 
void VideoDriver_SDL_Base::UnlockVideoBuffer()
 
{
 
	if (_screen.dst_ptr != nullptr) {
 
		/* Hand video buffer back to the drawing backend. */