2020-08-26 15:38:01 +08:00
|
|
|
#ifdef BLAH_USE_SDL2
|
|
|
|
|
2021-01-01 05:43:23 +08:00
|
|
|
#include "../internal/platform_backend.h"
|
|
|
|
#include "../internal/input_backend.h"
|
|
|
|
#include "../internal/graphics_backend.h"
|
2020-08-26 15:38:01 +08:00
|
|
|
#include <blah/input/input.h>
|
2021-01-01 05:43:23 +08:00
|
|
|
#include <blah/core/app.h>
|
|
|
|
#include <blah/core/filesystem.h>
|
|
|
|
#include <blah/core/log.h>
|
2021-02-06 16:13:50 +08:00
|
|
|
#include <blah/core/time.h>
|
2020-08-26 15:38:01 +08:00
|
|
|
|
|
|
|
#include <SDL.h>
|
2020-12-29 10:31:06 +08:00
|
|
|
#include <SDL_syswm.h>
|
2020-08-26 15:38:01 +08:00
|
|
|
|
|
|
|
#if _WIN32
|
|
|
|
// on Windows we're using the C++ <filesystem> API for now
|
2020-10-25 06:21:36 +08:00
|
|
|
#define WIN32_LEAN_AND_MEAN
|
2020-08-26 15:38:01 +08:00
|
|
|
#include <windows.h>
|
|
|
|
#include <winuser.h> // for SetProcessDPIAware
|
|
|
|
#include <filesystem> // for File Reading/Writing
|
|
|
|
#include <shellapi.h> // for file explore
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
#else
|
|
|
|
// on non-Windows we use POSIX standard file system stuff
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace Blah;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2020-12-24 08:58:04 +08:00
|
|
|
SDL_Window* window = nullptr;
|
2020-08-28 10:43:23 +08:00
|
|
|
SDL_Joystick* joysticks[Blah::Input::max_controllers];
|
2020-12-24 08:58:04 +08:00
|
|
|
SDL_GameController* gamepads[Blah::Input::max_controllers];
|
2020-08-28 10:11:49 +08:00
|
|
|
char* basePath = nullptr;
|
|
|
|
char* userPath = nullptr;
|
|
|
|
bool displayed = false;
|
2020-08-26 15:38:01 +08:00
|
|
|
|
|
|
|
void sdl_log(void* userdata, int category, SDL_LogPriority priority, const char* message)
|
|
|
|
{
|
|
|
|
if (priority <= SDL_LOG_PRIORITY_INFO)
|
|
|
|
Log::print(message);
|
|
|
|
else if (priority <= SDL_LOG_PRIORITY_WARN)
|
|
|
|
Log::warn(message);
|
|
|
|
else
|
|
|
|
Log::error(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::init(const Config* config)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
// Required to call this for Windows
|
|
|
|
// I'm not sure why SDL2 doesn't do this on Windows automatically?
|
|
|
|
#if _WIN32
|
|
|
|
SetProcessDPIAware();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// control this via some kind of config flag
|
|
|
|
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
|
|
|
|
SDL_LogSetOutputFunction(sdl_log, nullptr);
|
|
|
|
|
|
|
|
// Get SDL version
|
|
|
|
SDL_version version;
|
|
|
|
SDL_GetVersion(&version);
|
|
|
|
Log::print("SDL v%i.%i.%i", version.major, version.minor, version.patch);
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
|
|
|
|
2020-12-29 10:31:06 +08:00
|
|
|
// enable OpenGL
|
2020-12-27 06:44:48 +08:00
|
|
|
if (App::renderer() == Renderer::OpenGL)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
2020-12-24 08:16:09 +08:00
|
|
|
flags |= SDL_WINDOW_OPENGL;
|
|
|
|
|
2021-01-04 16:58:24 +08:00
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
|
|
|
#else
|
2020-08-26 15:38:01 +08:00
|
|
|
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);
|
2021-01-04 16:58:24 +08:00
|
|
|
#endif
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
2020-12-29 10:31:06 +08:00
|
|
|
// enable DirectX
|
|
|
|
else if (App::renderer() == Renderer::D3D11)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2020-08-26 15:38:01 +08:00
|
|
|
|
|
|
|
// create the window
|
|
|
|
window = SDL_CreateWindow(config->name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config->width, config->height, flags);
|
|
|
|
if (window == nullptr)
|
|
|
|
{
|
|
|
|
Log::error("Failed to create a Window");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scale Window to monitor for High DPI displays
|
|
|
|
// Other platforms do this automatically ... Windows we need to explitely do so
|
|
|
|
#if _WIN32
|
|
|
|
{
|
|
|
|
// find the display index
|
|
|
|
int display = SDL_GetWindowDisplayIndex(window);
|
|
|
|
float ddpi, hdpi, vdpi;
|
|
|
|
if (SDL_GetDisplayDPI(display, &ddpi, &hdpi, &vdpi) == 0)
|
|
|
|
{
|
|
|
|
// scale the window up basesd on the display DPI
|
|
|
|
float hidpiRes = 96;
|
|
|
|
float dpi = (ddpi / hidpiRes);
|
|
|
|
if (dpi != 1)
|
|
|
|
{
|
|
|
|
SDL_DisplayMode mode;
|
|
|
|
SDL_GetDesktopDisplayMode(display, &mode);
|
|
|
|
SDL_SetWindowPosition(window, (int)(mode.w - config->width * dpi) / 2, (int)(mode.h - config->height * dpi) / 2);
|
|
|
|
SDL_SetWindowSize(window, (int)(config->width * dpi), (int)(config->height * dpi));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// set window properties
|
|
|
|
SDL_SetWindowResizable(window, SDL_TRUE);
|
|
|
|
SDL_SetWindowMinimumSize(window, 256, 256);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::ready()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
2021-01-04 16:58:24 +08:00
|
|
|
#ifndef __EMSCRIPTEN__
|
2020-08-26 15:38:01 +08:00
|
|
|
// enable V-Sync
|
2021-01-06 12:44:02 +08:00
|
|
|
// TODO:
|
|
|
|
// This should be a toggle or controllable in some way
|
2020-12-27 06:44:48 +08:00
|
|
|
if (App::renderer() == Renderer::OpenGL)
|
2020-08-26 15:38:01 +08:00
|
|
|
SDL_GL_SetSwapInterval(1);
|
2021-01-04 16:58:24 +08:00
|
|
|
#endif
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::shutdown()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (window != nullptr)
|
|
|
|
SDL_DestroyWindow(window);
|
|
|
|
window = nullptr;
|
|
|
|
displayed = false;
|
|
|
|
|
|
|
|
if (basePath != nullptr)
|
|
|
|
SDL_free(basePath);
|
|
|
|
|
|
|
|
if (userPath != nullptr)
|
|
|
|
SDL_free(userPath);
|
|
|
|
|
|
|
|
SDL_Quit();
|
|
|
|
}
|
|
|
|
|
2021-02-06 16:13:50 +08:00
|
|
|
uint64_t PlatformBackend::ticks()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
2021-02-06 16:13:50 +08:00
|
|
|
auto counter = SDL_GetPerformanceCounter();
|
|
|
|
auto per_second = (double)SDL_GetPerformanceFrequency();
|
|
|
|
return (uint64_t)(counter * (Time::ticks_per_second / per_second));
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
|
2021-01-04 15:04:01 +08:00
|
|
|
// Macro defined by X11 conflicts with MouseButton enum
|
|
|
|
#undef None
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::frame()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
// update the mouse every frame
|
|
|
|
{
|
|
|
|
int winX, winY, x, y;
|
|
|
|
SDL_GetWindowPosition(window, &winX, &winY);
|
|
|
|
SDL_GetGlobalMouseState(&x, &y);
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_mouse_move((float)(x - winX), (float)(y - winY));
|
|
|
|
InputBackend::on_mouse_screen_move((float)x, (float)y);
|
2020-08-26 15:38:01 +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;
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_mouse_down(btn);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
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;
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_mouse_up(btn);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_MOUSEWHEEL)
|
|
|
|
{
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_mouse_wheel(Point(event.wheel.x, event.wheel.y));
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
// Keyboard
|
|
|
|
else if (event.type == SDL_KEYDOWN)
|
|
|
|
{
|
|
|
|
if (event.key.repeat == 0)
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_key_down((Key)event.key.keysym.scancode);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_KEYUP)
|
|
|
|
{
|
|
|
|
if (event.key.repeat == 0)
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_key_up((Key)event.key.keysym.scancode);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_TEXTINPUT)
|
|
|
|
{
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_text_utf8(event.text.text);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
// Joystick Controller
|
|
|
|
else if (event.type == SDL_JOYDEVICEADDED)
|
|
|
|
{
|
|
|
|
Sint32 index = event.jdevice.which;
|
|
|
|
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
|
|
|
{
|
|
|
|
SDL_Joystick* ptr = joysticks[index] = SDL_JoystickOpen(index);
|
|
|
|
const char* name = SDL_JoystickName(ptr);
|
|
|
|
int button_count = SDL_JoystickNumButtons(ptr);
|
|
|
|
int axis_count = SDL_JoystickNumAxes(ptr);
|
2020-12-24 08:58:04 +08:00
|
|
|
uint16_t vendor = SDL_JoystickGetVendor(ptr);
|
|
|
|
uint16_t product = SDL_JoystickGetProduct(ptr);
|
|
|
|
uint16_t version = SDL_JoystickGetProductVersion(ptr);
|
2020-08-26 15:38:01 +08:00
|
|
|
|
2020-12-24 08:58:04 +08:00
|
|
|
InputBackend::on_controller_connect(index, name, 0, button_count, axis_count, vendor, product, version);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYDEVICEREMOVED)
|
|
|
|
{
|
|
|
|
Sint32 index = event.jdevice.which;
|
|
|
|
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
|
|
|
{
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_controller_disconnect(index);
|
2020-08-26 15:38:01 +08:00
|
|
|
SDL_JoystickClose(joysticks[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYBUTTONDOWN)
|
|
|
|
{
|
|
|
|
Sint32 index = event.jdevice.which;
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_button_down(index, event.jbutton.button);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYBUTTONUP)
|
|
|
|
{
|
|
|
|
Sint32 index = event.jdevice.which;
|
|
|
|
if (SDL_IsGameController(index) == SDL_FALSE)
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_button_up(index, event.jbutton.button);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_JOYAXISMOTION)
|
|
|
|
{
|
|
|
|
Sint32 index = event.jaxis.which;
|
|
|
|
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;
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_axis_move(index, event.jaxis.axis, value);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Gamepad Controller
|
|
|
|
else if (event.type == SDL_CONTROLLERDEVICEADDED)
|
|
|
|
{
|
|
|
|
Sint32 index = event.cdevice.which;
|
|
|
|
SDL_GameController* ptr = gamepads[index] = SDL_GameControllerOpen(index);
|
|
|
|
const char* name = SDL_GameControllerName(ptr);
|
2020-12-24 08:58:04 +08:00
|
|
|
uint16_t vendor = SDL_GameControllerGetVendor(ptr);
|
|
|
|
uint16_t product = SDL_GameControllerGetProduct(ptr);
|
|
|
|
uint16_t version = SDL_GameControllerGetProductVersion(ptr);
|
|
|
|
|
|
|
|
InputBackend::on_controller_connect(index, name, 1, 15, 6, vendor, product, version);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERDEVICEREMOVED)
|
|
|
|
{
|
|
|
|
Sint32 index = event.cdevice.which;
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_controller_disconnect(index);
|
2020-08-26 15:38:01 +08:00
|
|
|
SDL_GameControllerClose(gamepads[index]);
|
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERBUTTONDOWN)
|
|
|
|
{
|
|
|
|
Sint32 index = event.cbutton.which;
|
|
|
|
|
|
|
|
int button = (int)Button::None;
|
|
|
|
if (event.cbutton.button >= 0 && event.cbutton.button < 15)
|
|
|
|
button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_button_down(index, button);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERBUTTONUP)
|
|
|
|
{
|
|
|
|
Sint32 index = event.cbutton.which;
|
|
|
|
|
|
|
|
int button = (int)Button::None;
|
|
|
|
if (event.cbutton.button >= 0 && event.cbutton.button < 15)
|
|
|
|
button = event.cbutton.button; // NOTE: These map directly to Engine Buttons enum!
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_button_up(index, button);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else if (event.type == SDL_CONTROLLERAXISMOTION)
|
|
|
|
{
|
|
|
|
Sint32 index = event.caxis.which;
|
|
|
|
|
|
|
|
int axis = (int)Axis::None;
|
|
|
|
if (event.caxis.axis >= 0 && event.caxis.axis < 6)
|
|
|
|
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;
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
InputBackend::on_axis_move(index, axis, value);
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::sleep(int milliseconds)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (milliseconds >= 0)
|
|
|
|
SDL_Delay((uint32_t)milliseconds);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::present()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
2020-12-27 06:44:48 +08:00
|
|
|
if (App::renderer() == Renderer::OpenGL)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_GL_SwapWindow(window);
|
|
|
|
}
|
|
|
|
|
|
|
|
// display the window
|
|
|
|
// this avoids a short black screen on macoS
|
|
|
|
if (!displayed)
|
|
|
|
{
|
|
|
|
SDL_ShowWindow(window);
|
|
|
|
displayed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
const char* PlatformBackend::get_title()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::set_title(const char* title)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_SetWindowTitle(window, title);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::get_position(int* x, int* y)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_GetWindowPosition(window, x, y);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::set_position(int x, int y)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_SetWindowPosition(window, x, y);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::set_fullscreen(bool enabled)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (enabled)
|
|
|
|
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
|
|
|
else
|
|
|
|
SDL_SetWindowFullscreen(window, 0);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::get_size(int* width, int* height)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_GetWindowSize(window, width, height);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::set_size(int width, int height)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_SetWindowSize(window, width, height);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::get_draw_size(int* width, int* height)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
2020-12-27 06:44:48 +08:00
|
|
|
if (App::renderer() == Renderer::OpenGL)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_GL_GetDrawableSize(window, width, height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDL_GetWindowSize(window, width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
float PlatformBackend::get_content_scale()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
// TODO:
|
2020-08-29 12:11:43 +08:00
|
|
|
// This is incorrect! but for some reason the scale
|
2020-08-26 15:38:01 +08:00
|
|
|
// is HUGE if I use the Display DPI on macOS :/
|
|
|
|
#if __APPLE__
|
|
|
|
return 2.0f;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if _WIN32
|
|
|
|
float hidpiRes = 96;
|
|
|
|
#else
|
|
|
|
float hidpiRes = 72;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int index = SDL_GetWindowDisplayIndex(window);
|
|
|
|
if (index < 0)
|
|
|
|
Log::error(SDL_GetError());
|
|
|
|
|
|
|
|
float ddpi, x, y;
|
|
|
|
if (SDL_GetDisplayDPI(index, &ddpi, &x, &y) != 0)
|
|
|
|
Log::error(SDL_GetError());
|
|
|
|
|
|
|
|
return (ddpi / hidpiRes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FILE IO
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
const char* PlatformBackend::app_path()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (basePath == nullptr)
|
|
|
|
basePath = SDL_GetBasePath();
|
|
|
|
return basePath;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
const char* PlatformBackend::user_path()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (userPath == nullptr)
|
|
|
|
{
|
|
|
|
const Config* config = App::config();
|
|
|
|
userPath = SDL_GetPrefPath(nullptr, config->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return userPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Windows File System methods
|
|
|
|
#if _WIN32
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::file_exists(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return fs::is_regular_file(path);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::file_delete(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return fs::remove(path);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::dir_create(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
std::error_code error;
|
|
|
|
return fs::create_directories(path, error);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::dir_exists(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return fs::is_directory(path);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::dir_delete(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
BLAH_ERROR("not implemented");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (fs::is_directory(path))
|
|
|
|
{
|
|
|
|
if (recursive)
|
|
|
|
{
|
|
|
|
for (auto& p : fs::recursive_directory_iterator(path))
|
2020-10-25 06:21:36 +08:00
|
|
|
list.emplace_back(p.path().string().c_str());
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (auto& p : fs::directory_iterator(path))
|
2020-10-25 06:21:36 +08:00
|
|
|
list.emplace_back(p.path().string().c_str());
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::dir_explore(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
ShellExecute(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Non-Windows File System Methods
|
|
|
|
#else
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::file_exists(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
struct stat buffer;
|
|
|
|
return (stat(path, &buffer) == 0) && S_ISREG(buffer.st_mode);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::file_delete(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
BLAH_ERROR("not implemented");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::dir_create(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
char tmp[265];
|
|
|
|
char* p = NULL;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
snprintf(tmp, sizeof(tmp), "%s", path);
|
|
|
|
len = strlen(tmp);
|
|
|
|
if (tmp[len - 1] == '/')
|
|
|
|
tmp[len - 1] = 0;
|
|
|
|
for (p = tmp + 1; *p; p++)
|
|
|
|
if (*p == '/') {
|
|
|
|
*p = 0;
|
|
|
|
mkdir(tmp, S_IRWXU);
|
|
|
|
*p = '/';
|
|
|
|
}
|
|
|
|
return mkdir(tmp, S_IRWXU) == 0;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::dir_exists(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
struct stat buffer;
|
|
|
|
return (stat(path, &buffer) == 0) && S_ISDIR(buffer.st_mode);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::dir_delete(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
BLAH_ERROR("not implemented");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::dir_enumerate(Vector<FilePath>& list, const char* path, bool recursive)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
DIR* dirp = opendir(path);
|
|
|
|
if (dirp != NULL)
|
|
|
|
{
|
|
|
|
struct dirent* dp;
|
|
|
|
while ((dp = readdir(dirp)) != NULL)
|
|
|
|
{
|
|
|
|
if (dp->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2021-01-04 15:04:01 +08:00
|
|
|
FilePath subpath = FilePath(path);
|
|
|
|
if (subpath.end()[-1] != '/') subpath = subpath.append("/");
|
|
|
|
subpath = subpath.append(dp->d_name);
|
2020-10-25 06:23:48 +08:00
|
|
|
list.push_back(subpath);
|
2020-08-26 15:38:01 +08:00
|
|
|
|
|
|
|
if (recursive && dp->d_type == DT_DIR)
|
|
|
|
dir_enumerate(list, subpath + "/", true);
|
|
|
|
}
|
|
|
|
closedir(dirp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::dir_explore(const char* path)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
2020-10-25 06:23:48 +08:00
|
|
|
BLAH_ERROR("'dir_explore' Not Implemented");
|
2020-08-26 15:38:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
bool PlatformBackend::file_open(const char* path, PlatformBackend::FileHandle* handle, FileMode mode)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
const char* sdlMode = "rb";
|
|
|
|
if (mode == FileMode::Write)
|
|
|
|
sdlMode = "wb";
|
|
|
|
|
|
|
|
auto ptr = SDL_RWFromFile(path, sdlMode);
|
2020-12-24 08:16:09 +08:00
|
|
|
*handle = (PlatformBackend::FileHandle)ptr;
|
2020-08-26 15:38:01 +08:00
|
|
|
return ptr != nullptr;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
int64_t PlatformBackend::file_length(PlatformBackend::FileHandle stream)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return SDL_RWsize((SDL_RWops*)stream);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
int64_t PlatformBackend::file_position(PlatformBackend::FileHandle stream)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return SDL_RWtell((SDL_RWops*)stream);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
int64_t PlatformBackend::file_seek(PlatformBackend::FileHandle stream, int64_t seekTo)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return SDL_RWseek((SDL_RWops*)stream, seekTo, RW_SEEK_SET);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
int64_t PlatformBackend::file_read(PlatformBackend::FileHandle stream, void* ptr, int64_t length)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return SDL_RWread((SDL_RWops*)stream, ptr, sizeof(char), length);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
int64_t PlatformBackend::file_write(PlatformBackend::FileHandle stream, const void* ptr, int64_t length)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return SDL_RWwrite((SDL_RWops*)stream, ptr, sizeof(char), length);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::file_close(PlatformBackend::FileHandle stream)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
if (stream != nullptr)
|
|
|
|
SDL_RWclose((SDL_RWops*)stream);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void* PlatformBackend::gl_get_func(const char* name)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
return SDL_GL_GetProcAddress(name);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void* PlatformBackend::gl_context_create()
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
void* pointer = SDL_GL_CreateContext(window);
|
|
|
|
if (pointer == nullptr)
|
|
|
|
Log::error("SDL_GL_CreateContext failed: %s", SDL_GetError());
|
|
|
|
return pointer;
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::gl_context_make_current(void* context)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_GL_MakeCurrent(window, context);
|
|
|
|
}
|
|
|
|
|
2020-12-24 08:16:09 +08:00
|
|
|
void PlatformBackend::gl_context_destroy(void* context)
|
2020-08-26 15:38:01 +08:00
|
|
|
{
|
|
|
|
SDL_GL_DeleteContext(context);
|
|
|
|
}
|
|
|
|
|
2020-12-29 10:31:06 +08:00
|
|
|
void* PlatformBackend::d3d11_get_hwnd()
|
|
|
|
{
|
2021-01-03 12:46:42 +08:00
|
|
|
#if _WIN32
|
2020-12-29 10:31:06 +08:00
|
|
|
SDL_SysWMinfo info;
|
|
|
|
SDL_VERSION(&info.version);
|
|
|
|
SDL_GetWindowWMInfo(window, &info);
|
|
|
|
return info.info.win.window;
|
2021-01-03 12:46:42 +08:00
|
|
|
#else
|
|
|
|
return nullptr;
|
2021-01-03 10:27:58 +08:00
|
|
|
#endif
|
2021-01-03 12:46:42 +08:00
|
|
|
}
|
|
|
|
|
2020-08-26 15:38:01 +08:00
|
|
|
#endif // BLAH_USE_SDL2
|