2017-03-24 03:47:43 +01:00
|
|
|
/*****************************************************************************
|
2019-03-17 08:16:15 +01:00
|
|
|
* Copyright (c) 2014-2019 OpenRCT2 developers
|
2018-06-15 14:07:34 +02:00
|
|
|
*
|
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
|
|
|
*
|
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
|
|
|
*****************************************************************************/
|
2017-03-24 03:47:43 +01:00
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
#include "UiContext.h"
|
|
|
|
|
|
|
|
#include "CursorRepository.h"
|
|
|
|
#include "SDLException.h"
|
|
|
|
#include "TextComposition.h"
|
|
|
|
#include "WindowManager.h"
|
|
|
|
#include "drawing/engines/DrawingEngineFactory.hpp"
|
|
|
|
#include "input/KeyboardShortcuts.h"
|
|
|
|
#include "interface/InGameConsole.h"
|
|
|
|
#include "interface/Theme.h"
|
|
|
|
#include "title/TitleSequencePlayer.h"
|
|
|
|
|
2019-01-02 21:23:58 +01:00
|
|
|
#include <SDL.h>
|
2017-03-25 15:57:02 +01:00
|
|
|
#include <algorithm>
|
2017-04-01 14:38:52 +02:00
|
|
|
#include <chrono>
|
2017-05-12 01:37:00 +02:00
|
|
|
#include <cmath>
|
2018-06-22 23:22:29 +02:00
|
|
|
#include <cstdlib>
|
2017-03-24 17:26:43 +01:00
|
|
|
#include <memory>
|
2018-06-22 23:22:29 +02:00
|
|
|
#include <openrct2-ui/interface/Window.h>
|
|
|
|
#include <openrct2/Context.h>
|
|
|
|
#include <openrct2/Input.h>
|
|
|
|
#include <openrct2/Version.h>
|
2017-03-25 18:42:14 +01:00
|
|
|
#include <openrct2/audio/AudioMixer.h>
|
2017-03-25 15:57:02 +01:00
|
|
|
#include <openrct2/config/Config.h>
|
2017-04-01 14:38:52 +02:00
|
|
|
#include <openrct2/core/String.hpp>
|
2018-03-19 23:28:40 +01:00
|
|
|
#include <openrct2/drawing/Drawing.h>
|
2018-06-22 23:22:29 +02:00
|
|
|
#include <openrct2/drawing/IDrawingEngine.h>
|
2018-06-02 01:31:06 +02:00
|
|
|
#include <openrct2/interface/Chat.h>
|
2018-06-22 23:22:29 +02:00
|
|
|
#include <openrct2/interface/InteractiveConsole.h>
|
|
|
|
#include <openrct2/localisation/StringIds.h>
|
2017-04-01 14:38:52 +02:00
|
|
|
#include <openrct2/platform/Platform2.h>
|
2018-06-02 13:33:20 +02:00
|
|
|
#include <openrct2/title/TitleSequencePlayer.h>
|
2017-03-25 04:16:40 +01:00
|
|
|
#include <openrct2/ui/UiContext.h>
|
2017-07-30 17:33:42 +02:00
|
|
|
#include <openrct2/ui/WindowManager.h>
|
2018-06-22 23:22:29 +02:00
|
|
|
#include <vector>
|
2018-03-11 23:25:34 +01:00
|
|
|
|
2017-03-24 03:47:43 +01:00
|
|
|
using namespace OpenRCT2;
|
2017-03-25 04:16:40 +01:00
|
|
|
using namespace OpenRCT2::Drawing;
|
2017-06-11 13:30:00 +02:00
|
|
|
using namespace OpenRCT2::Input;
|
2017-03-24 03:47:43 +01:00
|
|
|
using namespace OpenRCT2::Ui;
|
|
|
|
|
2017-03-25 18:42:14 +01:00
|
|
|
#ifdef __MACOSX__
|
2018-06-22 23:22:29 +02:00
|
|
|
// macOS uses COMMAND rather than CTRL for many keyboard shortcuts
|
2018-07-21 16:17:06 +02:00
|
|
|
# define KEYBOARD_PRIMARY_MODIFIER KMOD_GUI
|
2017-03-25 18:42:14 +01:00
|
|
|
#else
|
2018-07-21 16:17:06 +02:00
|
|
|
# define KEYBOARD_PRIMARY_MODIFIER KMOD_CTRL
|
2017-03-25 18:42:14 +01:00
|
|
|
#endif
|
|
|
|
|
2017-05-08 19:11:42 +02:00
|
|
|
class UiContext final : public IUiContext
|
2017-03-24 03:47:43 +01:00
|
|
|
{
|
2017-03-25 15:57:02 +01:00
|
|
|
private:
|
2018-06-20 17:28:51 +02:00
|
|
|
constexpr static uint32_t TOUCH_DOUBLE_TIMEOUT = 300;
|
2017-03-25 18:42:14 +01:00
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
IPlatformUiContext* const _platformUiContext;
|
|
|
|
IWindowManager* const _windowManager;
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
CursorRepository _cursorRepository;
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
SDL_Window* _window = nullptr;
|
|
|
|
int32_t _width = 0;
|
|
|
|
int32_t _height = 0;
|
|
|
|
int32_t _scaleQuality = 0;
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
std::vector<Resolution> _fsResolutions;
|
|
|
|
|
|
|
|
bool _steamOverlayActive = false;
|
|
|
|
|
2017-03-25 18:42:14 +01:00
|
|
|
// Input
|
2018-06-22 23:22:29 +02:00
|
|
|
KeyboardShortcuts _keyboardShortcuts;
|
|
|
|
TextComposition _textComposition;
|
|
|
|
CursorState _cursorState = {};
|
|
|
|
uint32_t _lastKeyPressed = 0;
|
|
|
|
const uint8_t* _keysState = nullptr;
|
|
|
|
uint8_t _keysPressed[256] = {};
|
|
|
|
uint32_t _lastGestureTimestamp = 0;
|
|
|
|
float _gestureRadius = 0;
|
|
|
|
|
|
|
|
InGameConsole _inGameConsole;
|
2018-06-02 13:33:20 +02:00
|
|
|
std::unique_ptr<ITitleSequencePlayer> _titleSequencePlayer;
|
2018-03-11 23:25:34 +01:00
|
|
|
|
2017-03-24 03:47:43 +01:00
|
|
|
public:
|
2018-06-22 23:22:29 +02:00
|
|
|
InGameConsole& GetInGameConsole()
|
|
|
|
{
|
|
|
|
return _inGameConsole;
|
|
|
|
}
|
2018-03-11 23:25:34 +01:00
|
|
|
|
2018-04-27 19:47:57 +02:00
|
|
|
explicit UiContext(const std::shared_ptr<IPlatformEnvironment>& env)
|
2018-06-22 23:22:29 +02:00
|
|
|
: _platformUiContext(CreatePlatformUiContext())
|
|
|
|
, _windowManager(CreateWindowManager())
|
|
|
|
, _keyboardShortcuts(env)
|
2017-03-24 03:47:43 +01:00
|
|
|
{
|
2017-03-26 22:04:14 +02:00
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
|
|
|
{
|
|
|
|
SDLException::Throw("SDL_Init(SDL_INIT_VIDEO)");
|
|
|
|
}
|
2017-03-26 22:42:07 +02:00
|
|
|
_cursorRepository.LoadCursors();
|
2017-06-11 13:30:00 +02:00
|
|
|
_keyboardShortcuts.Reset();
|
|
|
|
_keyboardShortcuts.Load();
|
2017-03-24 03:47:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~UiContext() override
|
|
|
|
{
|
2017-03-25 15:57:02 +01:00
|
|
|
CloseWindow();
|
2017-07-30 17:33:42 +02:00
|
|
|
delete _windowManager;
|
2017-03-29 19:44:19 +02:00
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
2017-03-29 20:37:56 +02:00
|
|
|
delete _platformUiContext;
|
2017-03-24 03:47:43 +01:00
|
|
|
}
|
2017-03-25 04:16:40 +01:00
|
|
|
|
2018-03-11 23:25:34 +01:00
|
|
|
void Update() override
|
|
|
|
{
|
|
|
|
_inGameConsole.Update();
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
void Draw(rct_drawpixelinfo* dpi) override
|
2018-03-11 23:25:34 +01:00
|
|
|
{
|
2018-06-02 01:31:06 +02:00
|
|
|
auto bgColour = theme_get_colour(WC_CHAT, 0);
|
|
|
|
chat_draw(dpi, bgColour);
|
2018-03-11 23:25:34 +01:00
|
|
|
_inGameConsole.Draw(dpi);
|
|
|
|
}
|
|
|
|
|
2017-03-25 04:16:40 +01:00
|
|
|
// Window
|
2018-06-22 23:22:29 +02:00
|
|
|
void* GetWindow() override
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
return _window;
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t GetWidth() override
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
return _width;
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t GetHeight() override
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
return _height;
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t GetScaleQuality() override
|
2017-10-25 03:17:40 +02:00
|
|
|
{
|
|
|
|
return _scaleQuality;
|
|
|
|
}
|
|
|
|
|
2017-03-25 15:57:02 +01:00
|
|
|
void SetFullscreenMode(FULLSCREEN_MODE mode) override
|
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
static constexpr const int32_t SDLFSFlags[] = { 0, SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN_DESKTOP };
|
|
|
|
uint32_t windowFlags = SDLFSFlags[(int32_t)mode];
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
// HACK Changing window size when in fullscreen usually has no effect
|
|
|
|
if (mode == FULLSCREEN_MODE::FULLSCREEN)
|
|
|
|
{
|
|
|
|
SDL_SetWindowFullscreen(_window, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set window size
|
|
|
|
if (mode == FULLSCREEN_MODE::FULLSCREEN)
|
|
|
|
{
|
|
|
|
UpdateFullscreenResolutions();
|
|
|
|
Resolution resolution = GetClosestResolution(gConfigGeneral.fullscreen_width, gConfigGeneral.fullscreen_height);
|
|
|
|
SDL_SetWindowSize(_window, resolution.Width, resolution.Height);
|
|
|
|
}
|
|
|
|
else if (mode == FULLSCREEN_MODE::WINDOWED)
|
|
|
|
{
|
|
|
|
SDL_SetWindowSize(_window, gConfigGeneral.window_width, gConfigGeneral.window_height);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SDL_SetWindowFullscreen(_window, windowFlags))
|
|
|
|
{
|
|
|
|
log_fatal("SDL_SetWindowFullscreen %s", SDL_GetError());
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
// TODO try another display mode rather than just exiting the game
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-06 07:20:57 +01:00
|
|
|
const std::vector<Resolution>& GetFullscreenResolutions() override
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
2017-03-26 04:36:22 +02:00
|
|
|
UpdateFullscreenResolutions();
|
2017-03-25 15:57:02 +01:00
|
|
|
return _fsResolutions;
|
|
|
|
}
|
2017-03-25 04:16:40 +01:00
|
|
|
|
2017-04-01 14:38:52 +02:00
|
|
|
bool HasFocus() override
|
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
uint32_t windowFlags = GetWindowFlags();
|
2017-05-06 22:33:23 +02:00
|
|
|
return (windowFlags & SDL_WINDOW_INPUT_FOCUS) != 0;
|
2017-04-01 14:38:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsMinimised() override
|
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
uint32_t windowFlags = GetWindowFlags();
|
2018-06-22 23:22:29 +02:00
|
|
|
return (windowFlags & SDL_WINDOW_MINIMIZED) || (windowFlags & SDL_WINDOW_HIDDEN);
|
2017-04-01 14:38:52 +02:00
|
|
|
}
|
|
|
|
|
2017-03-25 18:42:14 +01:00
|
|
|
bool IsSteamOverlayActive() override
|
|
|
|
{
|
|
|
|
return _steamOverlayActive;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Input
|
2018-06-22 23:22:29 +02:00
|
|
|
const CursorState* GetCursorState() override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
return &_cursorState;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
const uint8_t* GetKeysState() override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
return _keysState;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
const uint8_t* GetKeysPressed() override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
return _keysPressed;
|
|
|
|
}
|
|
|
|
|
|
|
|
CURSOR_ID GetCursor() override
|
|
|
|
{
|
|
|
|
return _cursorRepository.GetCurrentCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetCursor(CURSOR_ID cursor) override
|
|
|
|
{
|
|
|
|
_cursorRepository.SetCurrentCursor(cursor);
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
void SetCursorScale(uint8_t scale) override
|
2017-12-09 17:08:38 +01:00
|
|
|
{
|
|
|
|
_cursorRepository.SetCursorScale(scale);
|
|
|
|
}
|
|
|
|
|
2017-03-25 18:42:14 +01:00
|
|
|
void SetCursorVisible(bool value) override
|
|
|
|
{
|
|
|
|
SDL_ShowCursor(value ? SDL_ENABLE : SDL_DISABLE);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
void GetCursorPosition(int32_t* x, int32_t* y) override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
SDL_GetMouseState(x, y);
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
void SetCursorPosition(int32_t x, int32_t y) override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
SDL_WarpMouseInWindow(nullptr, x, y);
|
|
|
|
}
|
|
|
|
|
2017-04-01 14:38:52 +02:00
|
|
|
void SetCursorTrap(bool value) override
|
|
|
|
{
|
|
|
|
SDL_SetWindowGrab(_window, value ? SDL_TRUE : SDL_FALSE);
|
|
|
|
}
|
2017-05-27 20:59:59 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
void SetKeysPressed(uint32_t keysym, uint8_t scancode) override
|
2017-05-17 17:36:53 +02:00
|
|
|
{
|
|
|
|
_lastKeyPressed = keysym;
|
|
|
|
_keysPressed[scancode] = 1;
|
|
|
|
}
|
2017-04-01 14:38:52 +02:00
|
|
|
|
2017-03-25 04:16:40 +01:00
|
|
|
// Drawing
|
2018-04-21 01:29:12 +02:00
|
|
|
std::shared_ptr<Drawing::IDrawingEngineFactory> GetDrawingEngineFactory() override
|
|
|
|
{
|
|
|
|
return std::make_shared<DrawingEngineFactory>();
|
2017-03-25 04:16:40 +01:00
|
|
|
}
|
|
|
|
|
2018-06-15 08:46:04 +02:00
|
|
|
void DrawRainAnimation(IRainDrawer* rainDrawer, rct_drawpixelinfo* dpi, DrawRainFunc drawFunc) override
|
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t left = dpi->x;
|
|
|
|
int32_t right = left + dpi->width;
|
|
|
|
int32_t top = dpi->y;
|
|
|
|
int32_t bottom = top + dpi->height;
|
2018-06-15 08:46:04 +02:00
|
|
|
|
2018-06-16 03:14:59 +02:00
|
|
|
for (auto& w : g_window_list)
|
2018-06-15 08:46:04 +02:00
|
|
|
{
|
2018-06-16 16:36:59 +02:00
|
|
|
DrawRainWindow(rainDrawer, w.get(), left, right, top, bottom, drawFunc);
|
2018-06-15 08:46:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-25 04:16:40 +01:00
|
|
|
// Text input
|
2017-03-25 18:42:14 +01:00
|
|
|
bool IsTextInputActive() override
|
|
|
|
{
|
|
|
|
return _textComposition.IsActive();
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
TextInputSession* StartTextInput(utf8* buffer, size_t bufferSize) override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
return _textComposition.Start(buffer, bufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void StopTextInput() override
|
|
|
|
{
|
|
|
|
_textComposition.Stop();
|
|
|
|
}
|
|
|
|
|
2017-03-26 04:36:22 +02:00
|
|
|
void ProcessMessages() override
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
|
|
|
_lastKeyPressed = 0;
|
|
|
|
_cursorState.left &= ~CURSOR_CHANGED;
|
|
|
|
_cursorState.middle &= ~CURSOR_CHANGED;
|
|
|
|
_cursorState.right &= ~CURSOR_CHANGED;
|
|
|
|
_cursorState.old = 0;
|
|
|
|
|
|
|
|
SDL_Event e;
|
|
|
|
while (SDL_PollEvent(&e))
|
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
switch (e.type)
|
|
|
|
{
|
|
|
|
case SDL_QUIT:
|
|
|
|
context_quit();
|
|
|
|
break;
|
|
|
|
case SDL_WINDOWEVENT:
|
|
|
|
// HACK: Fix #2158, OpenRCT2 does not draw if it does not think that the window is
|
|
|
|
// visible - due a bug in SDL 2.0.3 this hack is required if the
|
|
|
|
// window is maximised, minimised and then restored again.
|
|
|
|
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
if (SDL_GetWindowFlags(_window) & SDL_WINDOW_MAXIMIZED)
|
|
|
|
{
|
|
|
|
SDL_RestoreWindow(_window);
|
|
|
|
SDL_MaximizeWindow(_window);
|
|
|
|
}
|
|
|
|
if ((SDL_GetWindowFlags(_window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
|
|
|
|
{
|
|
|
|
SDL_RestoreWindow(_window);
|
|
|
|
SDL_SetWindowFullscreen(_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
|
|
|
}
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
|
2017-05-28 00:28:54 +02:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
OnResize(e.window.data1, e.window.data2);
|
2017-05-28 00:28:54 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
switch (e.window.event)
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
|
|
|
case SDL_WINDOWEVENT_MOVED:
|
|
|
|
case SDL_WINDOWEVENT_MAXIMIZED:
|
|
|
|
case SDL_WINDOWEVENT_RESTORED:
|
|
|
|
{
|
|
|
|
// Update default display index
|
|
|
|
int32_t displayIndex = SDL_GetWindowDisplayIndex(_window);
|
|
|
|
if (displayIndex != gConfigGeneral.default_display)
|
|
|
|
{
|
|
|
|
gConfigGeneral.default_display = displayIndex;
|
|
|
|
config_save_default();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
|
2018-10-16 23:07:41 +02:00
|
|
|
if (gConfigSound.audio_focus)
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
|
|
|
{
|
|
|
|
Mixer_SetVolume(1);
|
|
|
|
}
|
|
|
|
if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
|
|
|
{
|
|
|
|
Mixer_SetVolume(0);
|
|
|
|
}
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
|
|
|
break;
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_MOUSEMOTION:
|
|
|
|
_cursorState.x = (int32_t)(e.motion.x / gConfigGeneral.window_scale);
|
|
|
|
_cursorState.y = (int32_t)(e.motion.y / gConfigGeneral.window_scale);
|
2017-03-25 18:42:14 +01:00
|
|
|
break;
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_MOUSEWHEEL:
|
|
|
|
if (_inGameConsole.IsOpen())
|
|
|
|
{
|
|
|
|
_inGameConsole.Scroll(e.wheel.y * 3); // Scroll 3 lines at a time
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_cursorState.wheel -= e.wheel.y;
|
2017-03-25 18:42:14 +01:00
|
|
|
break;
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
{
|
2018-10-06 17:43:39 +02:00
|
|
|
if (e.button.which == SDL_TOUCH_MOUSEID)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
int32_t x = (int32_t)(e.button.x / gConfigGeneral.window_scale);
|
|
|
|
int32_t y = (int32_t)(e.button.y / gConfigGeneral.window_scale);
|
|
|
|
switch (e.button.button)
|
|
|
|
{
|
|
|
|
case SDL_BUTTON_LEFT:
|
|
|
|
store_mouse_input(MOUSE_STATE_LEFT_PRESS, x, y);
|
|
|
|
_cursorState.left = CURSOR_PRESSED;
|
|
|
|
_cursorState.old = 1;
|
|
|
|
break;
|
|
|
|
case SDL_BUTTON_MIDDLE:
|
|
|
|
_cursorState.middle = CURSOR_PRESSED;
|
|
|
|
break;
|
|
|
|
case SDL_BUTTON_RIGHT:
|
|
|
|
store_mouse_input(MOUSE_STATE_RIGHT_PRESS, x, y);
|
|
|
|
_cursorState.right = CURSOR_PRESSED;
|
|
|
|
_cursorState.old = 2;
|
|
|
|
break;
|
|
|
|
}
|
2018-10-09 20:50:17 +02:00
|
|
|
_cursorState.touch = false;
|
2017-03-25 18:42:14 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
{
|
2018-10-06 17:43:39 +02:00
|
|
|
if (e.button.which == SDL_TOUCH_MOUSEID)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
int32_t x = (int32_t)(e.button.x / gConfigGeneral.window_scale);
|
|
|
|
int32_t y = (int32_t)(e.button.y / gConfigGeneral.window_scale);
|
|
|
|
switch (e.button.button)
|
|
|
|
{
|
|
|
|
case SDL_BUTTON_LEFT:
|
|
|
|
store_mouse_input(MOUSE_STATE_LEFT_RELEASE, x, y);
|
|
|
|
_cursorState.left = CURSOR_RELEASED;
|
|
|
|
_cursorState.old = 3;
|
|
|
|
break;
|
|
|
|
case SDL_BUTTON_MIDDLE:
|
|
|
|
_cursorState.middle = CURSOR_RELEASED;
|
|
|
|
break;
|
|
|
|
case SDL_BUTTON_RIGHT:
|
|
|
|
store_mouse_input(MOUSE_STATE_RIGHT_RELEASE, x, y);
|
|
|
|
_cursorState.right = CURSOR_RELEASED;
|
|
|
|
_cursorState.old = 4;
|
|
|
|
break;
|
|
|
|
}
|
2018-10-09 20:50:17 +02:00
|
|
|
_cursorState.touch = false;
|
2017-03-25 18:42:14 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
// Apple sends touchscreen events for trackpads, so ignore these events on macOS
|
2017-03-25 18:42:14 +01:00
|
|
|
#ifndef __MACOSX__
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_FINGERMOTION:
|
|
|
|
_cursorState.x = (int32_t)(e.tfinger.x * _width);
|
|
|
|
_cursorState.y = (int32_t)(e.tfinger.y * _height);
|
|
|
|
break;
|
|
|
|
case SDL_FINGERDOWN:
|
|
|
|
{
|
|
|
|
int32_t x = (int32_t)(e.tfinger.x * _width);
|
|
|
|
int32_t y = (int32_t)(e.tfinger.y * _height);
|
2017-03-25 18:42:14 +01:00
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
_cursorState.touchIsDouble
|
|
|
|
= (!_cursorState.touchIsDouble
|
|
|
|
&& e.tfinger.timestamp - _cursorState.touchDownTimestamp < TOUCH_DOUBLE_TIMEOUT);
|
2017-03-25 18:42:14 +01:00
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
if (_cursorState.touchIsDouble)
|
|
|
|
{
|
|
|
|
store_mouse_input(MOUSE_STATE_RIGHT_PRESS, x, y);
|
|
|
|
_cursorState.right = CURSOR_PRESSED;
|
|
|
|
_cursorState.old = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
store_mouse_input(MOUSE_STATE_LEFT_PRESS, x, y);
|
|
|
|
_cursorState.left = CURSOR_PRESSED;
|
|
|
|
_cursorState.old = 1;
|
|
|
|
}
|
|
|
|
_cursorState.touch = true;
|
|
|
|
_cursorState.touchDownTimestamp = e.tfinger.timestamp;
|
|
|
|
break;
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
case SDL_FINGERUP:
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
int32_t x = (int32_t)(e.tfinger.x * _width);
|
|
|
|
int32_t y = (int32_t)(e.tfinger.y * _height);
|
2017-03-25 18:42:14 +01:00
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
if (_cursorState.touchIsDouble)
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
store_mouse_input(MOUSE_STATE_RIGHT_RELEASE, x, y);
|
|
|
|
_cursorState.right = CURSOR_RELEASED;
|
|
|
|
_cursorState.old = 4;
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
else
|
2017-03-25 18:42:14 +01:00
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
store_mouse_input(MOUSE_STATE_LEFT_RELEASE, x, y);
|
|
|
|
_cursorState.left = CURSOR_RELEASED;
|
|
|
|
_cursorState.old = 3;
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
_cursorState.touch = true;
|
|
|
|
break;
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
2018-06-22 23:22:29 +02:00
|
|
|
#endif
|
|
|
|
case SDL_KEYDOWN:
|
|
|
|
_textComposition.HandleMessage(&e);
|
|
|
|
break;
|
|
|
|
case SDL_MULTIGESTURE:
|
|
|
|
if (e.mgesture.numFingers == 2)
|
|
|
|
{
|
|
|
|
if (e.mgesture.timestamp > _lastGestureTimestamp + 1000)
|
|
|
|
{
|
|
|
|
_gestureRadius = 0;
|
|
|
|
}
|
|
|
|
_lastGestureTimestamp = e.mgesture.timestamp;
|
|
|
|
_gestureRadius += e.mgesture.dDist;
|
|
|
|
|
|
|
|
// Zoom gesture
|
|
|
|
constexpr int32_t tolerance = 128;
|
|
|
|
int32_t gesturePixels = (int32_t)(_gestureRadius * _width);
|
|
|
|
if (abs(gesturePixels) > tolerance)
|
|
|
|
{
|
|
|
|
_gestureRadius = 0;
|
|
|
|
main_window_zoom(gesturePixels > 0, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SDL_TEXTEDITING:
|
|
|
|
_textComposition.HandleMessage(&e);
|
|
|
|
break;
|
|
|
|
case SDL_TEXTINPUT:
|
|
|
|
_textComposition.HandleMessage(&e);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2017-03-25 18:42:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_cursorState.any = _cursorState.left | _cursorState.middle | _cursorState.right;
|
|
|
|
|
|
|
|
// Updates the state of the keys
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t numKeys = 256;
|
2017-03-25 18:42:14 +01:00
|
|
|
_keysState = SDL_GetKeyboardState(&numKeys);
|
|
|
|
}
|
2017-03-25 15:57:02 +01:00
|
|
|
|
2017-03-26 04:36:22 +02:00
|
|
|
/**
|
|
|
|
* Helper function to set various render target features.
|
|
|
|
* Does not get triggered on resize, but rather manually on config changes.
|
|
|
|
*/
|
|
|
|
void TriggerResize() override
|
|
|
|
{
|
|
|
|
char scaleQualityBuffer[4];
|
2017-10-25 03:17:40 +02:00
|
|
|
_scaleQuality = gConfigGeneral.scale_quality;
|
2017-12-03 22:35:16 +01:00
|
|
|
if (gConfigGeneral.window_scale == std::floor(gConfigGeneral.window_scale))
|
2017-03-26 04:36:22 +02:00
|
|
|
{
|
2017-10-30 21:44:10 +01:00
|
|
|
_scaleQuality = SCALE_QUALITY_NN;
|
2017-03-26 04:36:22 +02:00
|
|
|
}
|
2017-12-03 22:35:16 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t scaleQuality = _scaleQuality;
|
2017-10-30 21:44:10 +01:00
|
|
|
if (_scaleQuality == SCALE_QUALITY_SMOOTH_NN)
|
2017-10-30 19:11:57 +01:00
|
|
|
{
|
2017-11-05 16:08:25 +01:00
|
|
|
scaleQuality = SCALE_QUALITY_LINEAR;
|
2017-10-30 19:11:57 +01:00
|
|
|
}
|
2017-11-05 16:08:25 +01:00
|
|
|
snprintf(scaleQualityBuffer, sizeof(scaleQualityBuffer), "%u", scaleQuality);
|
2017-03-26 04:36:22 +02:00
|
|
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaleQualityBuffer);
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t width, height;
|
2017-03-26 04:36:22 +02:00
|
|
|
SDL_GetWindowSize(_window, &width, &height);
|
|
|
|
OnResize(width, height);
|
|
|
|
}
|
|
|
|
|
2017-03-26 22:04:14 +02:00
|
|
|
void CreateWindow() override
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss ? "1" : "0");
|
|
|
|
|
2017-05-28 00:28:54 +02:00
|
|
|
// Set window position to default display
|
2018-08-12 13:50:40 +02:00
|
|
|
int32_t defaultDisplay = std::clamp(gConfigGeneral.default_display, 0, 0xFFFF);
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(defaultDisplay);
|
|
|
|
int32_t y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(defaultDisplay);
|
2017-05-28 00:28:54 +02:00
|
|
|
|
2017-07-11 15:56:17 +02:00
|
|
|
CreateWindow(x, y);
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
// Check if steam overlay renderer is loaded into the process
|
|
|
|
_steamOverlayActive = _platformUiContext->IsSteamOverlayAttached();
|
|
|
|
}
|
|
|
|
|
2017-03-26 22:04:14 +02:00
|
|
|
void CloseWindow() override
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
drawing_engine_dispose();
|
2018-05-04 21:24:35 +02:00
|
|
|
if (_window != nullptr)
|
|
|
|
{
|
|
|
|
SDL_DestroyWindow(_window);
|
|
|
|
_window = nullptr;
|
|
|
|
}
|
2017-07-11 15:56:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RecreateWindow() override
|
|
|
|
{
|
|
|
|
// Use the position of the current window for the new window
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t x, y;
|
2017-07-11 15:56:17 +02:00
|
|
|
SDL_SetWindowFullscreen(_window, 0);
|
|
|
|
SDL_GetWindowPosition(_window, &x, &y);
|
|
|
|
|
|
|
|
CloseWindow();
|
|
|
|
CreateWindow(x, y);
|
2017-03-25 15:57:02 +01:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
void ShowMessageBox(const std::string& message) override
|
2017-04-01 14:38:52 +02:00
|
|
|
{
|
|
|
|
_platformUiContext->ShowMessageBox(_window, message);
|
|
|
|
}
|
|
|
|
|
2018-09-04 11:40:51 +02:00
|
|
|
void OpenFolder(const std::string& path) override
|
|
|
|
{
|
|
|
|
_platformUiContext->OpenFolder(path);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
std::string ShowFileDialog(const FileDialogDesc& desc) override
|
2017-04-01 18:27:39 +02:00
|
|
|
{
|
|
|
|
return _platformUiContext->ShowFileDialog(_window, desc);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
std::string ShowDirectoryDialog(const std::string& title) override
|
2017-04-01 18:27:39 +02:00
|
|
|
{
|
|
|
|
return _platformUiContext->ShowDirectoryDialog(_window, title);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
IWindowManager* GetWindowManager() override
|
2017-06-11 16:16:47 +02:00
|
|
|
{
|
|
|
|
return _windowManager;
|
|
|
|
}
|
|
|
|
|
2017-06-06 15:34:30 +02:00
|
|
|
bool SetClipboardText(const utf8* target) override
|
|
|
|
{
|
|
|
|
return (SDL_SetClipboardText(target) == 0);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
ITitleSequencePlayer* GetTitleSequencePlayer() override
|
2018-06-02 13:33:20 +02:00
|
|
|
{
|
|
|
|
if (_titleSequencePlayer == nullptr)
|
|
|
|
{
|
|
|
|
auto context = GetContext();
|
|
|
|
auto scenarioRepository = context->GetScenarioRepository();
|
|
|
|
auto gameState = context->GetGameState();
|
|
|
|
_titleSequencePlayer = CreateTitleSequencePlayer(*scenarioRepository, *gameState);
|
|
|
|
}
|
|
|
|
return _titleSequencePlayer.get();
|
|
|
|
}
|
2017-06-14 20:47:22 +02:00
|
|
|
|
2017-03-26 22:04:14 +02:00
|
|
|
private:
|
2018-06-20 17:28:51 +02:00
|
|
|
void CreateWindow(int32_t x, int32_t y)
|
2017-07-11 15:56:17 +02:00
|
|
|
{
|
|
|
|
// Get saved window size
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t width = gConfigGeneral.window_width;
|
|
|
|
int32_t height = gConfigGeneral.window_height;
|
2018-06-22 23:22:29 +02:00
|
|
|
if (width <= 0)
|
|
|
|
width = 640;
|
|
|
|
if (height <= 0)
|
|
|
|
height = 480;
|
2017-07-11 15:56:17 +02:00
|
|
|
|
|
|
|
// Create window in window first rather than fullscreen so we have the display the window is on first
|
2018-06-20 17:28:51 +02:00
|
|
|
uint32_t flags = SDL_WINDOW_RESIZABLE;
|
2017-07-11 15:56:17 +02:00
|
|
|
if (gConfigGeneral.drawing_engine == DRAWING_ENGINE_OPENGL)
|
|
|
|
{
|
|
|
|
flags |= SDL_WINDOW_OPENGL;
|
|
|
|
}
|
|
|
|
|
|
|
|
_window = SDL_CreateWindow(OPENRCT2_NAME, x, y, width, height, flags);
|
|
|
|
if (_window == nullptr)
|
|
|
|
{
|
|
|
|
SDLException::Throw("SDL_CreateWindow(...)");
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_SetWindowMinimumSize(_window, 720, 480);
|
|
|
|
SetCursorTrap(gConfigGeneral.trap_cursor);
|
|
|
|
_platformUiContext->SetWindowIcon(_window);
|
|
|
|
|
|
|
|
// Initialise the surface, palette and draw buffer
|
|
|
|
drawing_engine_init();
|
|
|
|
OnResize(width, height);
|
|
|
|
|
|
|
|
UpdateFullscreenResolutions();
|
|
|
|
SetFullscreenMode((FULLSCREEN_MODE)gConfigGeneral.fullscreen_mode);
|
|
|
|
|
|
|
|
TriggerResize();
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
void OnResize(int32_t width, int32_t height)
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
// Scale the native window size to the game's canvas size
|
2018-06-20 17:28:51 +02:00
|
|
|
_width = (int32_t)(width / gConfigGeneral.window_scale);
|
|
|
|
_height = (int32_t)(height / gConfigGeneral.window_scale);
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
drawing_engine_resize();
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint32_t flags = SDL_GetWindowFlags(_window);
|
2017-03-25 15:57:02 +01:00
|
|
|
if ((flags & SDL_WINDOW_MINIMIZED) == 0)
|
|
|
|
{
|
|
|
|
window_resize_gui(_width, _height);
|
|
|
|
window_relocate_windows(_width, _height);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx_invalidate_screen();
|
|
|
|
|
|
|
|
// Check if the window has been resized in windowed mode and update the config file accordingly
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t nonWindowFlags =
|
2017-06-10 17:33:00 +02:00
|
|
|
#ifndef __MACOSX__
|
|
|
|
SDL_WINDOW_MAXIMIZED |
|
|
|
|
#endif
|
2018-06-22 23:22:29 +02:00
|
|
|
SDL_WINDOW_MINIMIZED | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP;
|
2017-06-10 17:33:00 +02:00
|
|
|
|
2017-03-25 15:57:02 +01:00
|
|
|
if (!(flags & nonWindowFlags))
|
|
|
|
{
|
|
|
|
if (width != gConfigGeneral.window_width || height != gConfigGeneral.window_height)
|
|
|
|
{
|
|
|
|
gConfigGeneral.window_width = width;
|
|
|
|
gConfigGeneral.window_height = height;
|
|
|
|
config_save_default();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateFullscreenResolutions()
|
|
|
|
{
|
|
|
|
// Query number of display modes
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t displayIndex = SDL_GetWindowDisplayIndex(_window);
|
|
|
|
int32_t numDisplayModes = SDL_GetNumDisplayModes(displayIndex);
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
// Get desktop aspect ratio
|
|
|
|
SDL_DisplayMode mode;
|
|
|
|
SDL_GetDesktopDisplayMode(displayIndex, &mode);
|
|
|
|
|
|
|
|
// Get resolutions
|
2017-06-02 19:36:21 +02:00
|
|
|
auto resolutions = std::vector<Resolution>();
|
2017-03-25 15:57:02 +01:00
|
|
|
float desktopAspectRatio = (float)mode.w / mode.h;
|
2018-06-20 17:28:51 +02:00
|
|
|
for (int32_t i = 0; i < numDisplayModes; i++)
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
SDL_GetDisplayMode(displayIndex, i, &mode);
|
2017-06-02 19:36:21 +02:00
|
|
|
if (mode.w > 0 && mode.h > 0)
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
2017-06-02 19:36:21 +02:00
|
|
|
float aspectRatio = (float)mode.w / mode.h;
|
2018-07-18 23:33:20 +02:00
|
|
|
if (std::fabs(desktopAspectRatio - aspectRatio) < 0.1f)
|
2017-06-02 19:36:21 +02:00
|
|
|
{
|
|
|
|
resolutions.push_back({ mode.w, mode.h });
|
|
|
|
}
|
2017-03-25 15:57:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort by area
|
2018-06-22 23:22:29 +02:00
|
|
|
std::sort(resolutions.begin(), resolutions.end(), [](const Resolution& a, const Resolution& b) -> bool {
|
|
|
|
int32_t areaA = a.Width * a.Height;
|
|
|
|
int32_t areaB = b.Width * b.Height;
|
|
|
|
return areaA < areaB;
|
|
|
|
});
|
2017-03-25 15:57:02 +01:00
|
|
|
|
|
|
|
// Remove duplicates
|
2018-06-22 23:22:29 +02:00
|
|
|
auto last = std::unique(resolutions.begin(), resolutions.end(), [](const Resolution& a, const Resolution& b) -> bool {
|
|
|
|
return (a.Width == b.Width && a.Height == b.Height);
|
|
|
|
});
|
2017-03-25 15:57:02 +01:00
|
|
|
resolutions.erase(last, resolutions.end());
|
|
|
|
|
|
|
|
// Update config fullscreen resolution if not set
|
|
|
|
if (gConfigGeneral.fullscreen_width == -1 || gConfigGeneral.fullscreen_height == -1)
|
|
|
|
{
|
|
|
|
gConfigGeneral.fullscreen_width = resolutions.back().Width;
|
|
|
|
gConfigGeneral.fullscreen_height = resolutions.back().Height;
|
|
|
|
}
|
2017-06-02 19:36:21 +02:00
|
|
|
|
|
|
|
_fsResolutions = resolutions;
|
2017-03-25 15:57:02 +01:00
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
Resolution GetClosestResolution(int32_t inWidth, int32_t inHeight)
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
Resolution result = { 640, 480 };
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t closestAreaDiff = -1;
|
|
|
|
int32_t destinationArea = inWidth * inHeight;
|
2018-06-22 23:22:29 +02:00
|
|
|
for (const Resolution& resolution : _fsResolutions)
|
2017-03-25 15:57:02 +01:00
|
|
|
{
|
|
|
|
// Check if exact match
|
|
|
|
if (resolution.Width == inWidth && resolution.Height == inHeight)
|
|
|
|
{
|
|
|
|
result = resolution;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if area is closer to best match
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t areaDiff = std::abs((resolution.Width * resolution.Height) - destinationArea);
|
2017-03-25 15:57:02 +01:00
|
|
|
if (closestAreaDiff == -1 || areaDiff < closestAreaDiff)
|
|
|
|
{
|
|
|
|
closestAreaDiff = areaDiff;
|
|
|
|
result = resolution;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2017-04-01 14:38:52 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint32_t GetWindowFlags()
|
2017-04-01 14:38:52 +02:00
|
|
|
{
|
2017-07-24 22:33:40 +02:00
|
|
|
return SDL_GetWindowFlags(_window);
|
2017-04-01 14:38:52 +02:00
|
|
|
}
|
2018-06-15 08:46:04 +02:00
|
|
|
|
|
|
|
static void DrawRainWindow(
|
2018-07-21 13:51:54 +02:00
|
|
|
IRainDrawer* rainDrawer, rct_window* original_w, int16_t left, int16_t right, int16_t top, int16_t bottom,
|
2018-06-15 08:46:04 +02:00
|
|
|
DrawRainFunc drawFunc)
|
|
|
|
{
|
2018-06-22 23:22:29 +02:00
|
|
|
rct_window* w{};
|
2019-05-29 19:15:50 +02:00
|
|
|
auto itStart = window_get_iterator(original_w);
|
|
|
|
for (auto it = std::next(itStart);; it++)
|
2018-06-15 08:46:04 +02:00
|
|
|
{
|
2019-05-29 19:15:50 +02:00
|
|
|
if (it == g_window_list.end())
|
2018-06-15 08:46:04 +02:00
|
|
|
{
|
|
|
|
// Loop ended, draw rain for original_w
|
|
|
|
auto vp = original_w->viewport;
|
|
|
|
if (vp != nullptr)
|
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
left = std::max<int16_t>(left, vp->x);
|
|
|
|
right = std::min<int16_t>(right, vp->x + vp->width);
|
|
|
|
top = std::max<int16_t>(top, vp->y);
|
|
|
|
bottom = std::min<int16_t>(bottom, vp->y + vp->height);
|
2018-06-15 08:46:04 +02:00
|
|
|
if (left < right && top < bottom)
|
|
|
|
{
|
|
|
|
auto width = right - left;
|
|
|
|
auto height = bottom - top;
|
|
|
|
drawFunc(rainDrawer, left, top, width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-29 19:15:50 +02:00
|
|
|
w = it->get();
|
2018-06-15 08:46:04 +02:00
|
|
|
if (right <= w->x || bottom <= w->y)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RCT_WINDOW_RIGHT(w) <= left || RCT_WINDOW_BOTTOM(w) <= top)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (left >= w->x)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DrawRainWindow(rainDrawer, original_w, left, w->x, top, bottom, drawFunc);
|
|
|
|
|
|
|
|
left = w->x;
|
|
|
|
DrawRainWindow(rainDrawer, original_w, left, right, top, bottom, drawFunc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int16_t w_right = RCT_WINDOW_RIGHT(w);
|
2018-06-22 23:22:29 +02:00
|
|
|
if (right > w_right)
|
|
|
|
{
|
2018-06-15 08:46:04 +02:00
|
|
|
DrawRainWindow(rainDrawer, original_w, left, w_right, top, bottom, drawFunc);
|
|
|
|
|
|
|
|
left = w_right;
|
|
|
|
DrawRainWindow(rainDrawer, original_w, left, right, top, bottom, drawFunc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:22:29 +02:00
|
|
|
if (top < w->y)
|
|
|
|
{
|
2018-06-15 08:46:04 +02:00
|
|
|
DrawRainWindow(rainDrawer, original_w, left, right, top, w->y, drawFunc);
|
|
|
|
|
|
|
|
top = w->y;
|
|
|
|
DrawRainWindow(rainDrawer, original_w, left, right, top, bottom, drawFunc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int16_t w_bottom = RCT_WINDOW_BOTTOM(w);
|
2018-06-15 08:46:04 +02:00
|
|
|
if (bottom > w_bottom)
|
|
|
|
{
|
|
|
|
DrawRainWindow(rainDrawer, original_w, left, right, top, w_bottom, drawFunc);
|
|
|
|
|
|
|
|
top = w_bottom;
|
|
|
|
DrawRainWindow(rainDrawer, original_w, left, right, top, bottom, drawFunc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-03-24 03:47:43 +01:00
|
|
|
};
|
|
|
|
|
2018-04-27 19:47:57 +02:00
|
|
|
std::unique_ptr<IUiContext> OpenRCT2::Ui::CreateUiContext(const std::shared_ptr<IPlatformEnvironment>& env)
|
2017-03-24 03:47:43 +01:00
|
|
|
{
|
2018-04-20 20:58:59 +02:00
|
|
|
return std::make_unique<UiContext>(env);
|
2017-03-24 03:47:43 +01:00
|
|
|
}
|
2018-03-11 23:25:34 +01:00
|
|
|
|
|
|
|
InGameConsole& OpenRCT2::Ui::GetInGameConsole()
|
|
|
|
{
|
2018-04-21 01:29:12 +02:00
|
|
|
auto uiContext = std::static_pointer_cast<UiContext>(GetContext()->GetUiContext());
|
2018-03-11 23:25:34 +01:00
|
|
|
return uiContext->GetInGameConsole();
|
|
|
|
}
|