2021-05-26 12:30:46 +08:00
|
|
|
#ifdef BLAH_PLATFORM_SDL2
|
|
|
|
|
|
|
|
#include "platform.h"
|
2022-02-10 10:49:47 +08:00
|
|
|
#include "renderer.h"
|
2022-08-22 05:48:46 +08:00
|
|
|
#include "internal.h"
|
2021-05-26 12:30:46 +08:00
|
|
|
#include <blah/input.h>
|
|
|
|
#include <blah/app.h>
|
|
|
|
#include <blah/filesystem.h>
|
|
|
|
#include <blah/common.h>
|
|
|
|
#include <blah/time.h>
|
|
|
|
|
|
|
|
#include <SDL.h>
|
|
|
|
|
2022-02-12 07:20:07 +08:00
|
|
|
// for File Reading / Writing
|
2022-01-26 14:54:38 +08:00
|
|
|
#include <filesystem>
|
|
|
|
|
2022-02-12 07:20:07 +08:00
|
|
|
// Windows requires a few extra includes
|
2021-05-26 12:30:46 +08:00
|
|
|
#if _WIN32
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
2022-02-12 07:20:07 +08:00
|
|
|
#include <windows.h> // for the following includes
|
|
|
|
#include <shellapi.h> // for ShellExecute for dir_explore
|
|
|
|
#include <SDL_syswm.h> // for SDL_SysWMinfo for D3D11
|
2021-05-26 12:30:46 +08:00
|
|
|
#endif
|
|
|
|
|
2022-01-26 14:54:38 +08:00
|
|
|
// Macro defined by X11 conflicts with MouseButton enum
|
|
|
|
#undef None
|
|
|
|
|
2021-05-26 12:30:46 +08:00
|
|
|
namespace Blah
|
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
void blah_sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
if (priority <= SDL_LOG_PRIORITY_INFO)
|
|
|
|
Log::info(message);
|
|
|
|
else if (priority <= SDL_LOG_PRIORITY_WARN)
|
|
|
|
Log::warn(message);
|
|
|
|
else
|
|
|
|
Log::error(message);
|
|
|
|
}
|
|
|
|
|
2022-02-12 07:20:07 +08:00
|
|
|
int blah_sdl_find_joystick_index(SDL_Joystick** joysticks, SDL_JoystickID instance_id)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
for (int i = 0; i < Input::max_controllers; i++)
|
|
|
|
if (joysticks[i] != nullptr && SDL_JoystickInstanceID(joysticks[i]) == instance_id)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-02-12 07:20:07 +08:00
|
|
|
int blah_sdl_find_gamepad_index(SDL_GameController** gamepads, SDL_JoystickID instance_id)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
for (int i = 0; i < Input::max_controllers; i++)
|
|
|
|
{
|
|
|
|
if (gamepads[i] != nullptr)
|
|
|
|
{
|
|
|
|
auto joystick = SDL_GameControllerGetJoystick(gamepads[i]);
|
|
|
|
if (SDL_JoystickInstanceID(joystick) == instance_id)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2022-02-12 12:19:14 +08:00
|
|
|
|
|
|
|
struct SDL2_File : public File
|
|
|
|
{
|
|
|
|
SDL_RWops* handle;
|
|
|
|
SDL2_File(SDL_RWops* handle) : handle(handle) { }
|
|
|
|
~SDL2_File() { if (handle) SDL_RWclose(handle); }
|
|
|
|
size_t length() override { return SDL_RWsize(handle); }
|
|
|
|
size_t position() override { return SDL_RWtell(handle); }
|
|
|
|
size_t seek(size_t position) override { return SDL_RWseek(handle, position, RW_SEEK_SET); }
|
2022-02-13 04:19:53 +08:00
|
|
|
size_t read(void* buffer, size_t length) override { return SDL_RWread(handle, buffer, sizeof(char), length); }
|
|
|
|
size_t write(const void* buffer, size_t length) override { return SDL_RWwrite(handle, buffer, sizeof(char), length); }
|
2022-02-12 12:19:14 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SDL2_Platform : public Platform
|
|
|
|
{
|
|
|
|
SDL_Window* window = nullptr;
|
|
|
|
SDL_Joystick* joysticks[Input::max_controllers];
|
|
|
|
SDL_GameController* gamepads[Input::max_controllers];
|
|
|
|
char* base_path_value = nullptr;
|
|
|
|
char* user_path_value = nullptr;
|
2022-03-16 17:12:10 +08:00
|
|
|
char* clipboard_text = nullptr;
|
2022-02-12 12:19:14 +08:00
|
|
|
bool displayed = false;
|
|
|
|
|
|
|
|
SDL2_Platform();
|
|
|
|
bool init(const Config& config) override;
|
|
|
|
void ready() override;
|
|
|
|
void shutdown() override;
|
|
|
|
u64 ticks() override;
|
|
|
|
void update(InputState& state) override;
|
|
|
|
void sleep(int milliseconds) override;
|
|
|
|
void present() override;
|
|
|
|
const char* get_title() override;
|
|
|
|
void set_title(const char* title) override;
|
|
|
|
void get_position(int* x, int* y) override;
|
|
|
|
void set_position(int x, int y) override;
|
|
|
|
bool get_focused() override;
|
|
|
|
void set_fullscreen(bool enabled) override;
|
|
|
|
void get_size(int* width, int* height) override;
|
|
|
|
void set_size(int width, int height) override;
|
|
|
|
void get_draw_size(int* width, int* height) override;
|
|
|
|
float get_content_scale() override;
|
|
|
|
const char* app_path() override;
|
|
|
|
const char* user_path() override;
|
|
|
|
FileRef file_open(const char* path, FileMode mode) override;
|
|
|
|
bool file_exists(const char* path) override;
|
|
|
|
bool file_delete(const char* path) override;
|
|
|
|
bool dir_create(const char* path) override;
|
|
|
|
bool dir_exists(const char* path) override;
|
|
|
|
bool dir_delete(const char* path) override;
|
|
|
|
void dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive) override;
|
|
|
|
void dir_explore(const char* path) override;
|
|
|
|
void set_clipboard(const char* text) override;
|
|
|
|
const char* get_clipboard() override;
|
|
|
|
void open_url(const char* url) override;
|
|
|
|
void* gl_get_func(const char* name) override;
|
|
|
|
void* gl_context_create() override;
|
|
|
|
void gl_context_make_current(void* context) override;
|
|
|
|
void gl_context_destroy(void* context) override;
|
|
|
|
void* d3d11_get_hwnd() override;
|
|
|
|
};
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
using namespace Blah;
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL2_Platform::SDL2_Platform()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
for (int i = 0; i < Input::max_controllers; i++)
|
|
|
|
{
|
|
|
|
joysticks[i] = nullptr;
|
|
|
|
gamepads[i] = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::init(const Config& config)
|
|
|
|
{
|
2021-05-26 12:30:46 +08:00
|
|
|
// TODO:
|
|
|
|
// control this via some kind of config flag
|
2022-07-31 07:30:13 +08:00
|
|
|
#ifndef __EMSCRIPTEN__
|
|
|
|
// Note: Emscripten gets a Stack Overflow if this is assigned to Verbose, even when
|
|
|
|
// increasing the node stack size to +8mb. Some kind of SDL2 problem?
|
2021-05-26 12:30:46 +08:00
|
|
|
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
|
2022-07-31 07:30:13 +08:00
|
|
|
#endif
|
2022-02-12 07:20:07 +08:00
|
|
|
SDL_LogSetOutputFunction(blah_sdl_log, nullptr);
|
2021-05-26 12:30:46 +08:00
|
|
|
|
|
|
|
// Get SDL version
|
|
|
|
SDL_version version;
|
|
|
|
SDL_GetVersion(&version);
|
|
|
|
Log::info("SDL v%i.%i.%i", version.major, version.minor, version.patch);
|
|
|
|
|
2022-08-22 05:48:46 +08:00
|
|
|
// Make us DPI aware on Windows
|
|
|
|
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitorv2");
|
|
|
|
SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "1");
|
|
|
|
|
2021-05-26 12:30:46 +08:00
|
|
|
// initialize SDL
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) != 0)
|
|
|
|
{
|
|
|
|
Log::error("Failed to initialize SDL2");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
|
|
|
|
|
|
|
// enable OpenGL
|
2022-02-10 10:49:47 +08:00
|
|
|
if (config.renderer_type == RendererType::OpenGL)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
flags |= SDL_WINDOW_OPENGL;
|
|
|
|
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
|
|
|
#else
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// This should be controlled via the gfx api somehow?
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// create the window
|
2022-02-12 12:19:14 +08:00
|
|
|
window = SDL_CreateWindow(config.name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config.width, config.height, flags);
|
|
|
|
if (window == nullptr)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
Log::error("Failed to create a Window");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set window properties
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_SetWindowResizable(window, SDL_TRUE);
|
|
|
|
SDL_SetWindowMinimumSize(window, 256, 256);
|
2021-05-26 12:30:46 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::ready()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
#ifndef __EMSCRIPTEN__
|
|
|
|
// enable V-Sync
|
|
|
|
// TODO:
|
|
|
|
// This should be a toggle or controllable in some way
|
2022-02-10 10:49:47 +08:00
|
|
|
if (App::renderer().type == RendererType::OpenGL)
|
2021-05-26 12:30:46 +08:00
|
|
|
SDL_GL_SetSwapInterval(1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::shutdown()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
if (window != nullptr)
|
|
|
|
SDL_DestroyWindow(window);
|
|
|
|
window = nullptr;
|
|
|
|
displayed = false;
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
if (base_path_value != nullptr)
|
|
|
|
SDL_free(base_path_value);
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
if (user_path_value != nullptr)
|
|
|
|
SDL_free(user_path_value);
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-03-16 17:12:10 +08:00
|
|
|
if (clipboard_text != nullptr)
|
|
|
|
SDL_free(clipboard_text);
|
|
|
|
|
2021-05-26 12:30:46 +08:00
|
|
|
SDL_Quit();
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
u64 SDL2_Platform::ticks()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
auto counter = SDL_GetPerformanceCounter();
|
|
|
|
auto per_second = (double)SDL_GetPerformanceFrequency();
|
|
|
|
return (u64)(counter * (Time::ticks_per_second / per_second));
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::update(InputState& state)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
// update the mouse every frame
|
|
|
|
{
|
|
|
|
int win_x, win_y, x, y;
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GetWindowPosition(window, &win_x, &win_y);
|
2021-05-26 12:30:46 +08:00
|
|
|
SDL_GetGlobalMouseState(&x, &y);
|
|
|
|
|
|
|
|
state.mouse.on_move(
|
2021-12-13 12:41:23 +08:00
|
|
|
Vec2f((float)(x - win_x), (float)(y - win_y)),
|
|
|
|
Vec2f((float)x, (float)y));
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// poll normal events
|
|
|
|
SDL_Event event;
|
|
|
|
while (SDL_PollEvent(&event))
|
|
|
|
{
|
|
|
|
if (event.type == SDL_QUIT)
|
|
|
|
{
|
|
|
|
auto& config = App::config();
|
|
|
|
if (config.on_exit_request != nullptr)
|
|
|
|
config.on_exit_request();
|
|
|
|
}
|
|
|
|
// Mouse
|
|
|
|
else if (event.type == SDL_MOUSEBUTTONDOWN)
|
|
|
|
{
|
|
|
|
MouseButton btn = MouseButton::None;
|
|
|
|
if (event.button.button == SDL_BUTTON_LEFT)
|
|
|
|
btn = MouseButton::Left;
|
|
|
|
else if (event.button.button == SDL_BUTTON_RIGHT)
|
|
|
|
btn = MouseButton::Right;
|
|
|
|
else if (event.button.button == SDL_BUTTON_MIDDLE)
|
|
|
|
btn = MouseButton::Middle;
|
|
|
|
|
|
|
|
state.mouse.on_press(btn);
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_MOUSEBUTTONUP)
|
|
|
|
{
|
|
|
|
MouseButton btn = MouseButton::None;
|
|
|
|
if (event.button.button == SDL_BUTTON_LEFT)
|
|
|
|
btn = MouseButton::Left;
|
|
|
|
else if (event.button.button == SDL_BUTTON_RIGHT)
|
|
|
|
btn = MouseButton::Right;
|
|
|
|
else if (event.button.button == SDL_BUTTON_MIDDLE)
|
|
|
|
btn = MouseButton::Middle;
|
|
|
|
|
|
|
|
state.mouse.on_release(btn);
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_MOUSEWHEEL)
|
|
|
|
{
|
|
|
|
state.mouse.wheel = Point(event.wheel.x, event.wheel.y);
|
|
|
|
}
|
|
|
|
// Keyboard
|
|
|
|
else if (event.type == SDL_KEYDOWN)
|
|
|
|
{
|
|
|
|
if (event.key.repeat == 0)
|
|
|
|
state.keyboard.on_press((Key)event.key.keysym.scancode);
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_KEYUP)
|
|
|
|
{
|
|
|
|
if (event.key.repeat == 0)
|
|
|
|
state.keyboard.on_release((Key)event.key.keysym.scancode);
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_TEXTINPUT)
|
|
|
|
{
|
|
|
|
state.keyboard.text += event.text.text;
|
|
|
|
}
|
|
|
|
// Joystick Controller
|
|
|
|
else if (event.type == SDL_JOYDEVICEADDED)
|
|
|
|
{
|
|
|
|
auto index = event.jdevice.which;
|
|
|
|
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE && index >= 0 && index < Input::max_controllers)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto ptr = joysticks[index] = SDL_JoystickOpen(index);
|
2021-05-26 12:30:46 +08:00
|
|
|
auto name = SDL_JoystickName(ptr);
|
|
|
|
auto button_count = SDL_JoystickNumButtons(ptr);
|
|
|
|
auto axis_count = SDL_JoystickNumAxes(ptr);
|
|
|
|
auto vendor = SDL_JoystickGetVendor(ptr);
|
|
|
|
auto product = SDL_JoystickGetProduct(ptr);
|
|
|
|
auto version = SDL_JoystickGetProductVersion(ptr);
|
|
|
|
|
|
|
|
state.controllers[index].on_connect(name, 0, button_count, axis_count, vendor, product, version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYDEVICEREMOVED)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
|
|
|
{
|
|
|
|
state.controllers[index].on_disconnect();
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_JoystickClose(joysticks[index]);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYBUTTONDOWN)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
|
|
|
state.controllers[index].on_press((Button)event.jbutton.button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYBUTTONUP)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
|
|
|
state.controllers[index].on_release((Button)event.jbutton.button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYAXISMOTION)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_joystick_index(joysticks, event.jdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
|
|
|
{
|
|
|
|
float value;
|
|
|
|
if (event.jaxis.value >= 0)
|
|
|
|
value = event.jaxis.value / 32767.0f;
|
|
|
|
else
|
|
|
|
value = event.jaxis.value / 32768.0f;
|
|
|
|
state.controllers[index].on_axis((Axis)event.jaxis.axis, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Gamepad Controller
|
|
|
|
else if (event.type == SDL_CONTROLLERDEVICEADDED)
|
|
|
|
{
|
|
|
|
auto index = event.cdevice.which;
|
|
|
|
if (index >= 0 && index < Input::max_controllers)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto ptr = gamepads[index] = SDL_GameControllerOpen(index);
|
2021-05-26 12:30:46 +08:00
|
|
|
auto name = SDL_GameControllerName(ptr);
|
|
|
|
auto vendor = SDL_GameControllerGetVendor(ptr);
|
|
|
|
auto product = SDL_GameControllerGetProduct(ptr);
|
|
|
|
auto version = SDL_GameControllerGetProductVersion(ptr);
|
|
|
|
|
|
|
|
state.controllers[index].on_connect(name, 1, 15, 6, vendor, product, version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERDEVICEREMOVED)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
state.controllers[index].on_disconnect();
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GameControllerClose(gamepads[index]);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERBUTTONDOWN)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
Button button = Button::None;
|
|
|
|
if (event.cbutton.button >= 0 && event.cbutton.button < 15)
|
|
|
|
button = (Button)event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
|
|
|
|
|
|
|
|
state.controllers[index].on_press(button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERBUTTONUP)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
Button button = Button::None;
|
|
|
|
if (event.cbutton.button >= 0 && event.cbutton.button < 15)
|
|
|
|
button = (Button)event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
|
|
|
|
|
|
|
|
state.controllers[index].on_release(button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERAXISMOTION)
|
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto index = blah_sdl_find_gamepad_index(gamepads, event.cdevice.which);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
Axis axis = Axis::None;
|
|
|
|
if (event.caxis.axis >= 0 && event.caxis.axis < 6)
|
|
|
|
axis = (Axis)event.caxis.axis; // NOTE: These map directly to Engine Axis enum!
|
|
|
|
|
|
|
|
float value;
|
|
|
|
if (event.caxis.value >= 0)
|
|
|
|
value = event.caxis.value / 32767.0f;
|
|
|
|
else
|
|
|
|
value = event.caxis.value / 32768.0f;
|
|
|
|
|
|
|
|
state.controllers[index].on_axis(axis, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::sleep(int milliseconds)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
if (milliseconds >= 0)
|
|
|
|
SDL_Delay((u32)milliseconds);
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::present()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-10 10:49:47 +08:00
|
|
|
if (App::renderer().type == RendererType::OpenGL)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GL_SwapWindow(window);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// display the window
|
|
|
|
// this avoids a short black screen on macoS
|
2022-02-12 12:19:14 +08:00
|
|
|
if (!displayed)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_ShowWindow(window);
|
|
|
|
displayed = true;
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
const char* SDL2_Platform::get_title()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
return SDL_GetWindowTitle(window);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::set_title(const char* title)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_SetWindowTitle(window, title);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::get_position(int* x, int* y)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GetWindowPosition(window, x, y);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::set_position(int x, int y)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_SetWindowPosition(window, x, y);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::get_focused()
|
2022-01-26 14:50:20 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
auto flags = SDL_GetWindowFlags(window);
|
2022-01-26 14:50:20 +08:00
|
|
|
return (flags & SDL_WINDOW_INPUT_FOCUS) != 0 && (flags & SDL_WINDOW_MINIMIZED) == 0;
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::set_fullscreen(bool enabled)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
if (enabled)
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
2021-05-26 12:30:46 +08:00
|
|
|
else
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_SetWindowFullscreen(window, 0);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::get_size(int* width, int* height)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GetWindowSize(window, width, height);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::set_size(int width, int height)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_SetWindowSize(window, width, height);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::get_draw_size(int* width, int* height)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-08-22 05:48:46 +08:00
|
|
|
switch (App::renderer().type)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-08-22 05:48:46 +08:00
|
|
|
case RendererType::OpenGL:
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GL_GetDrawableSize(window, width, height);
|
2022-08-22 05:48:46 +08:00
|
|
|
break;
|
|
|
|
case RendererType::None:
|
|
|
|
case RendererType::D3D11:
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GetWindowSize(window, width, height);
|
2022-08-22 05:48:46 +08:00
|
|
|
break;
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
float SDL2_Platform::get_content_scale()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
// TODO:
|
|
|
|
// This is incorrect! but for some reason the scale
|
|
|
|
// is HUGE if I use the Display DPI on macOS :/
|
|
|
|
#if __APPLE__
|
|
|
|
return 2.0f;
|
|
|
|
#endif
|
|
|
|
|
2022-03-17 14:05:38 +08:00
|
|
|
// TODO:
|
|
|
|
// is there a way to get this value properly? My Windows & Linux PC's both seem to thing 96 is correct
|
|
|
|
const float hidpi_res = 96;
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
int index = SDL_GetWindowDisplayIndex(window);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (index < 0)
|
2022-03-17 14:05:38 +08:00
|
|
|
{
|
2021-05-26 12:30:46 +08:00
|
|
|
Log::error(SDL_GetError());
|
2022-03-17 14:05:38 +08:00
|
|
|
return 1.0f;
|
|
|
|
}
|
2021-05-26 12:30:46 +08:00
|
|
|
|
|
|
|
float ddpi, x, y;
|
|
|
|
if (SDL_GetDisplayDPI(index, &ddpi, &x, &y) != 0)
|
2022-03-17 14:05:38 +08:00
|
|
|
{
|
2021-05-26 12:30:46 +08:00
|
|
|
Log::error(SDL_GetError());
|
2022-03-17 14:05:38 +08:00
|
|
|
return 1.0f;
|
|
|
|
}
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-03-17 14:05:38 +08:00
|
|
|
return (ddpi / hidpi_res);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
const char* SDL2_Platform::app_path()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
if (base_path_value == nullptr)
|
|
|
|
base_path_value = SDL_GetBasePath();
|
|
|
|
return base_path_value;
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
const char* SDL2_Platform::user_path()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
if (user_path_value == nullptr)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
auto& config = App::config();
|
2022-02-12 12:19:14 +08:00
|
|
|
user_path_value = SDL_GetPrefPath(nullptr, config.name);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
return user_path_value;
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
FileRef SDL2_Platform::file_open(const char* path, FileMode mode)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
const char* sdl_mode = "";
|
|
|
|
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case FileMode::OpenRead:
|
|
|
|
sdl_mode = "rb";
|
|
|
|
break;
|
|
|
|
case FileMode::Open:
|
|
|
|
sdl_mode = "r+b";
|
|
|
|
break;
|
|
|
|
case FileMode::CreateWrite:
|
|
|
|
sdl_mode = "wb";
|
|
|
|
break;
|
|
|
|
case FileMode::Create:
|
|
|
|
sdl_mode = "w+b";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ptr = SDL_RWFromFile(path, sdl_mode);
|
|
|
|
if (!ptr)
|
|
|
|
return FileRef();
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
return FileRef(new SDL2_File(ptr));
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::file_exists(const char* path)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
return std::filesystem::is_regular_file(path);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::file_delete(const char* path)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
return std::filesystem::remove(path);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::dir_create(const char* path)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
return std::filesystem::create_directories(path);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::dir_exists(const char* path)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
return std::filesystem::is_directory(path);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
bool SDL2_Platform::dir_delete(const char* path)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
return std::filesystem::remove_all(path) > 0;
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
if (std::filesystem::is_directory(path))
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
if (recursive)
|
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
for (auto& p : std::filesystem::recursive_directory_iterator(path))
|
2021-05-26 12:30:46 +08:00
|
|
|
list.emplace_back(p.path().string().c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-12 07:20:07 +08:00
|
|
|
for (auto& p : std::filesystem::directory_iterator(path))
|
2021-05-26 12:30:46 +08:00
|
|
|
list.emplace_back(p.path().string().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::dir_explore(const char* path)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-01-26 14:54:38 +08:00
|
|
|
#if _WIN32
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-01-26 14:54:38 +08:00
|
|
|
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT);
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-01-26 14:54:38 +08:00
|
|
|
#elif __linux__
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-01-26 14:54:38 +08:00
|
|
|
system(String::fmt("xdg-open \"%s\"", path).cstr());
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-01-26 14:54:38 +08:00
|
|
|
#else
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-01-26 14:54:38 +08:00
|
|
|
BLAH_ASSERT(false, "'dir_explore' not implemented");
|
2021-05-26 12:30:46 +08:00
|
|
|
|
|
|
|
#endif
|
2022-01-26 14:54:38 +08:00
|
|
|
}
|
2021-05-26 12:30:46 +08:00
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::set_clipboard(const char* text)
|
2021-12-13 12:41:23 +08:00
|
|
|
{
|
|
|
|
SDL_SetClipboardText(text);
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
const char* SDL2_Platform::get_clipboard()
|
2021-12-13 12:41:23 +08:00
|
|
|
{
|
2022-03-16 17:12:10 +08:00
|
|
|
// free previous clipboard text
|
|
|
|
if (clipboard_text != nullptr)
|
|
|
|
SDL_free(clipboard_text);
|
|
|
|
|
|
|
|
clipboard_text = SDL_GetClipboardText();
|
|
|
|
return clipboard_text;
|
2021-12-13 12:41:23 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void* SDL2_Platform::gl_get_func(const char* name)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
return SDL_GL_GetProcAddress(name);
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void* SDL2_Platform::gl_context_create()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
void* pointer = SDL_GL_CreateContext(window);
|
2021-05-26 12:30:46 +08:00
|
|
|
if (pointer == nullptr)
|
|
|
|
Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError());
|
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::gl_context_make_current(void* context)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GL_MakeCurrent(window, context);
|
2021-05-26 12:30:46 +08:00
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::gl_context_destroy(void* context)
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
SDL_GL_DeleteContext(context);
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void* SDL2_Platform::d3d11_get_hwnd()
|
2021-05-26 12:30:46 +08:00
|
|
|
{
|
|
|
|
#if _WIN32
|
|
|
|
SDL_SysWMinfo info;
|
|
|
|
SDL_VERSION(&info.version);
|
2022-02-12 12:19:14 +08:00
|
|
|
SDL_GetWindowWMInfo(window, &info);
|
2021-05-26 12:30:46 +08:00
|
|
|
return info.info.win.window;
|
|
|
|
#else
|
|
|
|
return nullptr;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
void SDL2_Platform::open_url(const char* url)
|
2022-01-26 14:50:20 +08:00
|
|
|
{
|
|
|
|
SDL_OpenURL(url);
|
|
|
|
}
|
|
|
|
|
2022-02-12 12:19:14 +08:00
|
|
|
Platform* Platform::try_make_platform(const Config& config)
|
|
|
|
{
|
|
|
|
return new SDL2_Platform();
|
|
|
|
}
|
|
|
|
|
2021-05-26 12:30:46 +08:00
|
|
|
#endif // BLAH_PLATFORM_SDL2
|