Merge branch 'master' into jgrpp
# Conflicts: # src/dock_gui.cpp # src/rail_gui.cpp # src/road_gui.cpp # src/terraform_gui.cpp # src/vehicle.cpp # src/video/allegro_v.cpp # src/video/cocoa/cocoa_v.mm # src/video/dedicated_v.cpp # src/video/sdl2_v.cpp # src/video/sdl_v.cpp # src/video/win32_v.cpp
This commit is contained in:
		@@ -14,6 +14,7 @@
 | 
			
		||||
#include "../rev.h"
 | 
			
		||||
#include "../blitter/factory.hpp"
 | 
			
		||||
#include "../network/network.h"
 | 
			
		||||
#include "../core/geometry_func.hpp"
 | 
			
		||||
#include "../core/math_func.hpp"
 | 
			
		||||
#include "../core/random_func.hpp"
 | 
			
		||||
#include "../texteff.hpp"
 | 
			
		||||
@@ -49,7 +50,6 @@ static struct {
 | 
			
		||||
	HBITMAP dib_sect;     ///< System bitmap object referencing our rendering buffer.
 | 
			
		||||
	void *buffer_bits;    ///< Internal rendering buffer.
 | 
			
		||||
	HPALETTE gdi_palette; ///< Palette object for 8bpp blitter.
 | 
			
		||||
	RECT update_rect;     ///< Current dirty rect.
 | 
			
		||||
	int width;            ///< Width in pixels of our display surface.
 | 
			
		||||
	int height;           ///< Height in pixels of our display surface.
 | 
			
		||||
	int width_org;        ///< Original monitor resolution width, before we changed it.
 | 
			
		||||
@@ -59,9 +59,7 @@ static struct {
 | 
			
		||||
	bool running;         ///< Is the main loop running?
 | 
			
		||||
} _wnd;
 | 
			
		||||
 | 
			
		||||
bool _force_full_redraw;
 | 
			
		||||
bool _window_maximize;
 | 
			
		||||
uint _display_hz;
 | 
			
		||||
static Dimension _bck_resolution;
 | 
			
		||||
DWORD _imm_props;
 | 
			
		||||
 | 
			
		||||
@@ -75,6 +73,8 @@ static std::condition_variable_any *_draw_signal = nullptr;
 | 
			
		||||
static volatile bool _draw_continue;
 | 
			
		||||
/** Local copy of the palette for use in the drawing thread. */
 | 
			
		||||
static Palette _local_palette;
 | 
			
		||||
/** Region of the screen that needs redrawing. */
 | 
			
		||||
static Rect _dirty_rect;
 | 
			
		||||
 | 
			
		||||
static void MakePalette()
 | 
			
		||||
{
 | 
			
		||||
@@ -256,12 +256,10 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen)
 | 
			
		||||
		settings.dmFields =
 | 
			
		||||
			DM_BITSPERPEL |
 | 
			
		||||
			DM_PELSWIDTH |
 | 
			
		||||
			DM_PELSHEIGHT |
 | 
			
		||||
			(_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0);
 | 
			
		||||
			DM_PELSHEIGHT;
 | 
			
		||||
		settings.dmBitsPerPel = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
 | 
			
		||||
		settings.dmPelsWidth  = _wnd.width_org;
 | 
			
		||||
		settings.dmPelsHeight = _wnd.height_org;
 | 
			
		||||
		settings.dmDisplayFrequency = _display_hz;
 | 
			
		||||
 | 
			
		||||
		/* Check for 8 bpp support. */
 | 
			
		||||
		if (settings.dmBitsPerPel == 8 &&
 | 
			
		||||
@@ -335,10 +333,24 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Do palette animation and blit to the window. */
 | 
			
		||||
static void PaintWindow(HDC dc)
 | 
			
		||||
void VideoDriver_Win32::Paint()
 | 
			
		||||
{
 | 
			
		||||
	PerformanceMeasurer framerate(PFE_VIDEO);
 | 
			
		||||
 | 
			
		||||
	if (IsEmptyRect(_dirty_rect)) return;
 | 
			
		||||
 | 
			
		||||
	/* Convert update region from logical to device coordinates. */
 | 
			
		||||
	POINT pt = {0, 0};
 | 
			
		||||
	ClientToScreen(_wnd.main_wnd, &pt);
 | 
			
		||||
 | 
			
		||||
	RECT r = { _dirty_rect.left, _dirty_rect.top, _dirty_rect.right, _dirty_rect.bottom };
 | 
			
		||||
	OffsetRect(&r, pt.x, pt.y);
 | 
			
		||||
 | 
			
		||||
	/* Create a device context that is clipped to the region we need to draw.
 | 
			
		||||
	 * GetDCEx 'consumes' the update region, so we may not destroy it ourself. */
 | 
			
		||||
	HRGN rgn = CreateRectRgnIndirect(&r);
 | 
			
		||||
	HDC dc = GetDCEx(_wnd.main_wnd, rgn, DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_INTERSECTRGN);
 | 
			
		||||
 | 
			
		||||
	HDC dc2 = CreateCompatibleDC(dc);
 | 
			
		||||
	HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect);
 | 
			
		||||
	HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
 | 
			
		||||
@@ -368,9 +380,13 @@ static void PaintWindow(HDC dc)
 | 
			
		||||
	SelectPalette(dc, old_palette, TRUE);
 | 
			
		||||
	SelectObject(dc2, old_bmp);
 | 
			
		||||
	DeleteDC(dc2);
 | 
			
		||||
 | 
			
		||||
	ReleaseDC(_wnd.main_wnd, dc);
 | 
			
		||||
 | 
			
		||||
	_dirty_rect = {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void PaintWindowThread()
 | 
			
		||||
void VideoDriver_Win32::PaintThread()
 | 
			
		||||
{
 | 
			
		||||
	/* First tell the main thread we're started */
 | 
			
		||||
	std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
 | 
			
		||||
@@ -380,21 +396,7 @@ static void PaintWindowThread()
 | 
			
		||||
	_draw_signal->wait(*_draw_mutex);
 | 
			
		||||
 | 
			
		||||
	while (_draw_continue) {
 | 
			
		||||
		/* Convert update region from logical to device coordinates. */
 | 
			
		||||
		POINT pt = {0, 0};
 | 
			
		||||
		ClientToScreen(_wnd.main_wnd, &pt);
 | 
			
		||||
		OffsetRect(&_wnd.update_rect, pt.x, pt.y);
 | 
			
		||||
 | 
			
		||||
		/* Create a device context that is clipped to the region we need to draw.
 | 
			
		||||
		 * GetDCEx 'consumes' the update region, so we may not destroy it ourself. */
 | 
			
		||||
		HRGN rgn = CreateRectRgnIndirect(&_wnd.update_rect);
 | 
			
		||||
		HDC dc = GetDCEx(_wnd.main_wnd, rgn, DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_INTERSECTRGN);
 | 
			
		||||
 | 
			
		||||
		PaintWindow(dc);
 | 
			
		||||
 | 
			
		||||
		/* Clear update rect. */
 | 
			
		||||
		SetRectEmpty(&_wnd.update_rect);
 | 
			
		||||
		ReleaseDC(_wnd.main_wnd, dc);
 | 
			
		||||
		this->Paint();
 | 
			
		||||
 | 
			
		||||
		/* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */
 | 
			
		||||
		GdiFlush();
 | 
			
		||||
@@ -403,6 +405,11 @@ static void PaintWindowThread()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* static */ void VideoDriver_Win32::PaintThreadThunk(VideoDriver_Win32 *drv)
 | 
			
		||||
{
 | 
			
		||||
	drv->PaintThread();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Forward key presses to the window system. */
 | 
			
		||||
static LRESULT HandleCharMsg(uint keycode, WChar charcode)
 | 
			
		||||
{
 | 
			
		||||
@@ -606,7 +613,6 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
 | 
			
		||||
{
 | 
			
		||||
	static uint32 keycode = 0;
 | 
			
		||||
	static bool console = false;
 | 
			
		||||
	static bool in_sizemove = false;
 | 
			
		||||
 | 
			
		||||
	switch (msg) {
 | 
			
		||||
		case WM_CREATE:
 | 
			
		||||
@@ -615,32 +621,14 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
 | 
			
		||||
			_imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case WM_ENTERSIZEMOVE:
 | 
			
		||||
			in_sizemove = true;
 | 
			
		||||
			break;
 | 
			
		||||
		case WM_PAINT: {
 | 
			
		||||
			RECT r;
 | 
			
		||||
			GetUpdateRect(hwnd, &r, FALSE);
 | 
			
		||||
			static_cast<VideoDriver_Win32 *>(VideoDriver::GetInstance())->MakeDirty(r.left, r.top, r.right - r.left, r.bottom - r.top);
 | 
			
		||||
 | 
			
		||||
		case WM_EXITSIZEMOVE:
 | 
			
		||||
			in_sizemove = false;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case WM_PAINT:
 | 
			
		||||
			if (!in_sizemove && _draw_mutex != nullptr && !HasModalProgress()) {
 | 
			
		||||
				/* Get the union of the old update rect and the new update rect. */
 | 
			
		||||
				RECT r;
 | 
			
		||||
				GetUpdateRect(hwnd, &r, FALSE);
 | 
			
		||||
				UnionRect(&_wnd.update_rect, &_wnd.update_rect, &r);
 | 
			
		||||
 | 
			
		||||
				/* Mark the window as updated, otherwise Windows would send more WM_PAINT messages. */
 | 
			
		||||
				ValidateRect(hwnd, nullptr);
 | 
			
		||||
				_draw_signal->notify_one();
 | 
			
		||||
			} else {
 | 
			
		||||
				PAINTSTRUCT ps;
 | 
			
		||||
 | 
			
		||||
				BeginPaint(hwnd, &ps);
 | 
			
		||||
				PaintWindow(ps.hdc);
 | 
			
		||||
				EndPaint(hwnd, &ps);
 | 
			
		||||
			}
 | 
			
		||||
			ValidateRect(hwnd, nullptr);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case WM_PALETTECHANGED:
 | 
			
		||||
			if ((HWND)wParam == hwnd) return 0;
 | 
			
		||||
@@ -653,7 +641,9 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
 | 
			
		||||
 | 
			
		||||
			SelectPalette(hDC, hOldPalette, TRUE);
 | 
			
		||||
			ReleaseDC(hwnd, hDC);
 | 
			
		||||
			if (nChanged != 0) InvalidateRect(hwnd, nullptr, FALSE);
 | 
			
		||||
			if (nChanged != 0) {
 | 
			
		||||
				static_cast<VideoDriver_Win32 *>(VideoDriver::GetInstance())->MakeDirty(0, 0, _screen.width, _screen.height);
 | 
			
		||||
			}
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -1122,29 +1112,59 @@ void VideoDriver_Win32::Stop()
 | 
			
		||||
 | 
			
		||||
void VideoDriver_Win32::MakeDirty(int left, int top, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	RECT r = { left, top, left + width, top + height };
 | 
			
		||||
 | 
			
		||||
	InvalidateRect(_wnd.main_wnd, &r, FALSE);
 | 
			
		||||
	Rect r = {left, top, left + width, top + height};
 | 
			
		||||
	_dirty_rect = BoundingRect(_dirty_rect, r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void CheckPaletteAnim()
 | 
			
		||||
void VideoDriver_Win32::CheckPaletteAnim()
 | 
			
		||||
{
 | 
			
		||||
	if (_cur_palette.count_dirty == 0) return;
 | 
			
		||||
 | 
			
		||||
	_local_palette = _cur_palette;
 | 
			
		||||
	InvalidateRect(_wnd.main_wnd, nullptr, FALSE);
 | 
			
		||||
	this->MakeDirty(0, 0, _screen.width, _screen.height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VideoDriver_Win32::InputLoop()
 | 
			
		||||
{
 | 
			
		||||
	bool old_ctrl_pressed = _ctrl_pressed;
 | 
			
		||||
	bool old_shift_pressed = _shift_pressed;
 | 
			
		||||
 | 
			
		||||
	_ctrl_pressed = (_wnd.has_focus && GetAsyncKeyState(VK_CONTROL) < 0) != _invert_ctrl;
 | 
			
		||||
	_shift_pressed = (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0) != _invert_shift;
 | 
			
		||||
 | 
			
		||||
#if defined(_DEBUG)
 | 
			
		||||
	if (_shift_pressed)
 | 
			
		||||
#else
 | 
			
		||||
	/* Speedup when pressing tab, except when using ALT+TAB
 | 
			
		||||
	 * to switch to another application. */
 | 
			
		||||
	if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0)
 | 
			
		||||
#endif
 | 
			
		||||
	{
 | 
			
		||||
		if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2;
 | 
			
		||||
	} else if (_fast_forward & 2) {
 | 
			
		||||
		_fast_forward = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Determine which directional keys are down. */
 | 
			
		||||
	if (_wnd.has_focus) {
 | 
			
		||||
		_dirkeys =
 | 
			
		||||
			(GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
 | 
			
		||||
			(GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
 | 
			
		||||
			(GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
 | 
			
		||||
			(GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
 | 
			
		||||
	} else {
 | 
			
		||||
		_dirkeys = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
 | 
			
		||||
	if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VideoDriver_Win32::MainLoop()
 | 
			
		||||
{
 | 
			
		||||
	MSG mesg;
 | 
			
		||||
	auto cur_ticks = std::chrono::steady_clock::now();
 | 
			
		||||
	auto last_realtime_tick = cur_ticks;
 | 
			
		||||
	auto next_game_tick = cur_ticks;
 | 
			
		||||
	auto next_draw_tick = cur_ticks;
 | 
			
		||||
 | 
			
		||||
	std::thread draw_thread;
 | 
			
		||||
	std::unique_lock<std::recursive_mutex> draw_lock;
 | 
			
		||||
 | 
			
		||||
	if (_draw_threaded) {
 | 
			
		||||
		/* Initialise the mutex first, because that's the thing we *need*
 | 
			
		||||
@@ -1157,15 +1177,15 @@ void VideoDriver_Win32::MainLoop()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (_draw_threaded) {
 | 
			
		||||
			draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
 | 
			
		||||
			this->draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
 | 
			
		||||
 | 
			
		||||
			_draw_continue = true;
 | 
			
		||||
			_draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &PaintWindowThread);
 | 
			
		||||
			_draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &VideoDriver_Win32::PaintThreadThunk, this);
 | 
			
		||||
 | 
			
		||||
			/* Free the mutex if we won't be able to use it. */
 | 
			
		||||
			if (!_draw_threaded) {
 | 
			
		||||
				draw_lock.unlock();
 | 
			
		||||
				draw_lock.release();
 | 
			
		||||
				this->draw_lock.unlock();
 | 
			
		||||
				this->draw_lock.release();
 | 
			
		||||
				delete _draw_mutex;
 | 
			
		||||
				delete _draw_signal;
 | 
			
		||||
				_draw_mutex = nullptr;
 | 
			
		||||
@@ -1180,108 +1200,27 @@ void VideoDriver_Win32::MainLoop()
 | 
			
		||||
 | 
			
		||||
	_wnd.running = true;
 | 
			
		||||
 | 
			
		||||
	CheckPaletteAnim();
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		InteractiveRandom(); // randomness
 | 
			
		||||
 | 
			
		||||
		while (PeekMessage(&mesg, nullptr, 0, 0, PM_REMOVE)) {
 | 
			
		||||
			InteractiveRandom(); // randomness
 | 
			
		||||
			/* Convert key messages to char messages if we want text input. */
 | 
			
		||||
			if (EditBoxInGlobalFocus()) TranslateMessage(&mesg);
 | 
			
		||||
			DispatchMessage(&mesg);
 | 
			
		||||
		}
 | 
			
		||||
		if (_exit_game) break;
 | 
			
		||||
 | 
			
		||||
#if defined(_DEBUG)
 | 
			
		||||
		if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
 | 
			
		||||
#else
 | 
			
		||||
		/* Speed up using TAB, but disable for ALT+TAB of course */
 | 
			
		||||
		if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0 &&
 | 
			
		||||
#endif
 | 
			
		||||
			  !_networking && _game_mode != GM_MENU) {
 | 
			
		||||
			_fast_forward |= 2;
 | 
			
		||||
		} else if (_fast_forward & 2) {
 | 
			
		||||
			_fast_forward = 0;
 | 
			
		||||
		}
 | 
			
		||||
		/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
 | 
			
		||||
		GdiFlush();
 | 
			
		||||
 | 
			
		||||
		cur_ticks = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
		/* If more than a millisecond has passed, increase the _realtime_tick. */
 | 
			
		||||
		if (cur_ticks - last_realtime_tick > std::chrono::milliseconds(1)) {
 | 
			
		||||
			auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(cur_ticks - last_realtime_tick);
 | 
			
		||||
			IncreaseRealtimeTick(delta.count());
 | 
			
		||||
			last_realtime_tick += delta;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
 | 
			
		||||
			if (_fast_forward && !_pause_mode) {
 | 
			
		||||
				next_game_tick = cur_ticks + this->GetGameInterval();
 | 
			
		||||
		if (this->Tick()) {
 | 
			
		||||
			if (_draw_mutex != nullptr && !HasModalProgress()) {
 | 
			
		||||
				_draw_signal->notify_one();
 | 
			
		||||
			} else {
 | 
			
		||||
				next_game_tick += this->GetGameInterval();
 | 
			
		||||
				/* Avoid next_game_tick getting behind more and more if it cannot keep up. */
 | 
			
		||||
				if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
 | 
			
		||||
			GdiFlush();
 | 
			
		||||
 | 
			
		||||
			/* The game loop is the part that can run asynchronously.
 | 
			
		||||
			 * The rest except sleeping can't. */
 | 
			
		||||
			if (_draw_threaded) draw_lock.unlock();
 | 
			
		||||
			GameLoop();
 | 
			
		||||
			if (_draw_threaded) draw_lock.lock();
 | 
			
		||||
			GameLoopPaletteAnimations();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Prevent drawing when switching mode, as windows can be removed when they should still appear. */
 | 
			
		||||
		if (cur_ticks >= next_draw_tick && (_switch_mode == SM_NONE || HasModalProgress())) {
 | 
			
		||||
			next_draw_tick += this->GetDrawInterval();
 | 
			
		||||
			/* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
 | 
			
		||||
			if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) next_draw_tick = cur_ticks;
 | 
			
		||||
 | 
			
		||||
			bool old_ctrl_pressed = _ctrl_pressed;
 | 
			
		||||
			bool old_shift_pressed = _shift_pressed;
 | 
			
		||||
 | 
			
		||||
			_ctrl_pressed = (_wnd.has_focus && GetAsyncKeyState(VK_CONTROL) < 0) != _invert_ctrl;
 | 
			
		||||
			_shift_pressed = (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0) != _invert_shift;
 | 
			
		||||
 | 
			
		||||
			/* determine which directional keys are down */
 | 
			
		||||
			if (_wnd.has_focus) {
 | 
			
		||||
				_dirkeys =
 | 
			
		||||
					(GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) +
 | 
			
		||||
					(GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) +
 | 
			
		||||
					(GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) +
 | 
			
		||||
					(GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0);
 | 
			
		||||
			} else {
 | 
			
		||||
				_dirkeys = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged();
 | 
			
		||||
			if (old_shift_pressed != _shift_pressed) HandleShiftChanged();
 | 
			
		||||
 | 
			
		||||
			if (_force_full_redraw) MarkWholeScreenDirty();
 | 
			
		||||
 | 
			
		||||
			/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
 | 
			
		||||
			GdiFlush();
 | 
			
		||||
 | 
			
		||||
			InputLoop();
 | 
			
		||||
			UpdateWindows();
 | 
			
		||||
			CheckPaletteAnim();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* If we are not in fast-forward, create some time between calls to ease up CPU usage. */
 | 
			
		||||
		if (!_fast_forward || _pause_mode) {
 | 
			
		||||
			/* See how much time there is till we have to process the next event, and try to hit that as close as possible. */
 | 
			
		||||
			auto next_tick = std::min(next_draw_tick, next_game_tick);
 | 
			
		||||
			auto now = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
			if (next_tick > now) {
 | 
			
		||||
				/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
 | 
			
		||||
				GdiFlush();
 | 
			
		||||
 | 
			
		||||
				if (_draw_mutex != nullptr) draw_lock.unlock();
 | 
			
		||||
				std::this_thread::sleep_for(next_tick - now);
 | 
			
		||||
				if (_draw_mutex != nullptr) draw_lock.lock();
 | 
			
		||||
				this->Paint();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		this->SleepTillNextTick();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_draw_threaded) {
 | 
			
		||||
@@ -1289,8 +1228,8 @@ void VideoDriver_Win32::MainLoop()
 | 
			
		||||
		/* Sending signal if there is no thread blocked
 | 
			
		||||
		 * is very valid and results in noop */
 | 
			
		||||
		_draw_signal->notify_all();
 | 
			
		||||
		if (draw_lock.owns_lock()) draw_lock.unlock();
 | 
			
		||||
		draw_lock.release();
 | 
			
		||||
		if (this->draw_lock.owns_lock()) this->draw_lock.unlock();
 | 
			
		||||
		this->draw_lock.release();
 | 
			
		||||
		draw_thread.join();
 | 
			
		||||
 | 
			
		||||
		delete _draw_mutex;
 | 
			
		||||
@@ -1391,3 +1330,14 @@ float VideoDriver_Win32::GetDPIScale()
 | 
			
		||||
 | 
			
		||||
	return cur_dpi > 0 ? cur_dpi / 96.0f : 1.0f; // Default Windows DPI value is 96.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VideoDriver_Win32::LockVideoBuffer()
 | 
			
		||||
{
 | 
			
		||||
	if (_draw_threaded) this->draw_lock.lock();
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VideoDriver_Win32::UnlockVideoBuffer()
 | 
			
		||||
{
 | 
			
		||||
	if (_draw_threaded) this->draw_lock.unlock();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user