Archived
1
Fork 0
This repository has been archived on 2025-04-12. You can view files and clone it, but cannot push or open issues or pull requests.
prism/platforms/sdl/main.cpp.in

550 lines
15 KiB
C++
Raw Normal View History

2021-03-01 14:40:02 -05:00
#include <@APP_INCLUDE@>
#include <engine.hpp>
#include <chrono>
2021-03-01 14:40:02 -05:00
#include "platform.hpp"
#include <string_utils.hpp>
2021-03-01 14:40:02 -05:00
#include <SDL.h>
#include <SDL_vulkan.h>
2021-03-01 14:40:02 -05:00
2022-02-21 15:53:42 -05:00
#ifdef ENABLE_DX12
#include "gfx_dx12.hpp"
#endif
#ifdef ENABLE_VULKAN
#include "gfx_vulkan.hpp"
#endif
#ifdef ENABLE_METAL
#include "gfx_metal.hpp"
#endif
#include "gfx_dummy.hpp"
#if defined(PLATFORM_WINDOWS) && !defined(__MINGW32__)
#include <winrt/Windows.UI.ViewManagement.h>
#pragma comment(lib, "windowsapp")
#endif
2021-03-01 14:40:02 -05:00
@APP_CLASS@* app = nullptr;
GFX* gfx_interface = nullptr;
2021-03-01 14:40:02 -05:00
std::vector<SDL_Window*> windows;
2022-02-18 14:36:38 -05:00
std::map<SDL_Window*, SDL_Renderer*> renderers;
SDL_Window* main_window = nullptr;
SDL_Window* get_window(const platform::window_ptr index) {
for(auto& window : windows) {
if(window == index)
return window;
}
return nullptr;
}
SDL_Window* get_window_by_sdl_id(const Uint32 id) {
2021-04-20 00:47:04 -04:00
for(auto& window : windows) {
if(SDL_GetWindowID(window) == id)
return window;
2021-04-20 00:47:04 -04:00
}
return nullptr;
}
#ifdef ENABLE_METAL
void* create_metal_surface(platform::window_ptr window, void* surface_creation_info);
void* get_next_metal_drawable(platform::window_ptr window);
#endif
#ifdef ENABLE_VULKAN
void* create_vulkan_surface(platform::window_ptr window, void* surface_creation_info);
#endif
2021-03-01 14:40:02 -05:00
static std::map<InputButton, int> inputToKeyCode = { {
{InputButton::C, SDL_SCANCODE_C},
{InputButton::V, SDL_SCANCODE_V},
{InputButton::X, SDL_SCANCODE_X},
{InputButton::Y, SDL_SCANCODE_Y},
{InputButton::Z, SDL_SCANCODE_Z},
{InputButton::Backspace, SDL_SCANCODE_BACKSPACE},
{InputButton::Enter, SDL_SCANCODE_RETURN},
{InputButton::W, SDL_SCANCODE_W},
{InputButton::A, SDL_SCANCODE_A},
{InputButton::S, SDL_SCANCODE_S},
{InputButton::D, SDL_SCANCODE_D},
{InputButton::Q, SDL_SCANCODE_Q},
{InputButton::Shift, SDL_SCANCODE_LSHIFT},
{InputButton::Alt, SDL_SCANCODE_LALT},
{InputButton::Super, SDL_SCANCODE_APPLICATION},
{InputButton::Escape, SDL_SCANCODE_ESCAPE},
{InputButton::Tab, SDL_SCANCODE_TAB},
{InputButton::Ctrl, SDL_SCANCODE_LCTRL},
{InputButton::Space, SDL_SCANCODE_SPACE},
{InputButton::LeftArrow, SDL_SCANCODE_LEFT},
{InputButton::RightArrow, SDL_SCANCODE_RIGHT}
2021-03-01 14:40:02 -05:00
}};
/*
* Platform functions"
*/
const char* platform::get_name() {
return SDL_GetPlatform();
2021-03-01 14:40:02 -05:00
}
bool platform::supports_feature(const PlatformFeature feature) {
if(feature == PlatformFeature::Windowing)
return true;
return false;
}
platform::window_ptr platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) {
2021-03-01 14:40:02 -05:00
auto& win = windows.emplace_back();
2022-02-15 11:29:56 -05:00
int sdl_flags = SDL_WINDOW_ALLOW_HIGHDPI;
if(gfx_interface->required_context() == GFXContext::Vulkan)
sdl_flags |= SDL_WINDOW_VULKAN;
2022-02-15 11:29:56 -05:00
if(flags & WindowFlags::Borderless)
2021-04-20 00:47:04 -04:00
sdl_flags |= SDL_WINDOW_BORDERLESS;
if(flags & WindowFlags::Resizable)
2021-04-20 00:47:04 -04:00
sdl_flags |= SDL_WINDOW_RESIZABLE;
if(flags & WindowFlags::Hidden)
sdl_flags |= SDL_WINDOW_HIDDEN;
auto resolution = platform::get_monitor_resolution();
int real_x = rect.offset.x;
int real_y = rect.offset.y;
2021-10-12 11:42:10 -04:00
if(rect.offset.x <= -1 || rect.offset.x > resolution.extent.width)
real_x = SDL_WINDOWPOS_CENTERED;
2021-10-12 11:42:10 -04:00
if(rect.offset.y <= -1 || rect.offset.x > resolution.extent.height)
real_y = SDL_WINDOWPOS_CENTERED;
int real_width = rect.extent.width;
int real_height = rect.extent.height;
2021-10-12 11:42:10 -04:00
if(rect.extent.width <= -1 || rect.extent.width > resolution.extent.width)
real_width = 640;
2021-10-12 11:42:10 -04:00
if(rect.extent.height <= -1 || rect.extent.height > resolution.extent.height)
real_height = 480;
2021-03-01 14:40:02 -05:00
win = SDL_CreateWindow(title.data(), real_x, real_y, real_width, real_height, sdl_flags);
if(windows.size() == 1)
main_window = win;
#ifdef ENABLE_METAL
if(gfx_interface->required_context() == GFXContext::Metal) {
SDL_Renderer* renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
renderers[win] = renderer;
}
#endif
2022-02-18 14:36:38 -05:00
2021-10-12 11:42:10 -04:00
engine->add_window((void*)win, win, {static_cast<uint32_t>(real_width), static_cast<uint32_t>(real_height)});
2021-03-01 14:40:02 -05:00
app->initialize_render();
return win;
}
bool platform::is_main_window(platform::window_ptr index) {
return index == main_window;
2021-03-01 14:40:02 -05:00
}
void platform::close_window(const platform::window_ptr index) {
auto window = get_window(index);
engine->remove_window(index);
SDL_DestroyWindow(window);
utility::erase(windows, window);
2021-03-01 14:40:02 -05:00
}
void platform::force_quit() {
SDL_Quit();
2021-03-01 14:40:02 -05:00
}
float platform::get_monitor_dpi() {
float dpi = 1.0f;
if (!SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr))
dpi = dpi / 96.0f;
return dpi;
2021-03-01 14:40:02 -05:00
}
prism::Rectangle platform::get_monitor_resolution() {
SDL_Rect r;
SDL_GetDisplayBounds(0, &r);
2021-10-12 11:42:10 -04:00
return {r.x, r.y, static_cast<uint32_t>(r.w), static_cast<uint32_t>(r.h)};
2021-03-01 14:40:02 -05:00
}
prism::Rectangle platform::get_monitor_work_area() {
SDL_Rect r = {};
SDL_GetDisplayUsableBounds(0, &r);
2021-10-12 11:42:10 -04:00
return {r.x, r.y, static_cast<uint32_t>(r.w), static_cast<uint32_t>(r.h)};
2021-03-01 14:40:02 -05:00
}
prism::Offset platform::get_window_position(const platform::window_ptr index) {
auto window = get_window(index);
2021-03-01 14:40:02 -05:00
int x, y;
SDL_GetWindowPosition(window, &x, &y);
2021-03-01 14:40:02 -05:00
return {(int32_t)x, (int32_t)y};
2021-03-01 14:40:02 -05:00
}
prism::Extent platform::get_window_size(const platform::window_ptr index) {
2021-03-01 14:40:02 -05:00
auto window = get_window(index);
int width, height;
SDL_GetWindowSize(window, &width, &height);
2021-03-01 14:40:02 -05:00
return {(uint32_t)width, (uint32_t)height};
}
prism::Extent platform::get_window_drawable_size(const platform::window_ptr index) {
2021-03-01 14:40:02 -05:00
auto window = get_window(index);
int width, height;
2021-10-12 11:42:10 -04:00
SDL_Vulkan_GetDrawableSize(window, &width, &height);
2021-03-01 14:40:02 -05:00
return {(uint32_t)width, (uint32_t)height};
}
bool platform::is_window_focused(const platform::window_ptr index) {
auto window = get_window(index);
return (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) != 0;
2021-03-01 14:40:02 -05:00
}
void platform::set_window_focused(const platform::window_ptr index) {
auto window = get_window(index);
SDL_RaiseWindow(window);
2021-03-01 14:40:02 -05:00
}
void platform::set_window_position(const platform::window_ptr index, const prism::Offset offset) {
auto window = get_window(index);
SDL_SetWindowPosition(window, offset.x, offset.y);
2021-03-01 14:40:02 -05:00
}
void platform::set_window_size(const platform::window_ptr index, const prism::Extent extent) {
auto window = get_window(index);
SDL_SetWindowSize(window, extent.width, extent.height);
2021-03-01 14:40:02 -05:00
}
void platform::set_window_title(const platform::window_ptr index, const std::string_view title) {
2021-03-01 14:40:02 -05:00
auto window = get_window(index);
SDL_SetWindowTitle(window, title.data());
2021-03-01 14:40:02 -05:00
}
void platform::show_window(const platform::window_ptr index) {
auto window = get_window(index);
SDL_ShowWindow(window);
}
2021-03-01 14:40:02 -05:00
bool platform::get_key_down(const InputButton key) {
const Uint8 *state = SDL_GetKeyboardState(NULL);
return state[inputToKeyCode[key]] && state[SDL_SCANCODE_DOWN];
2021-03-01 14:40:02 -05:00
}
int platform::get_keycode(const InputButton key) {
return inputToKeyCode[key];
}
prism::Offset platform::get_cursor_position() {
int x, y;
SDL_GetMouseState(&x, &y);
return {(int32_t)x, (int32_t)y};
2021-03-01 14:40:02 -05:00
}
prism::Offset platform::get_screen_cursor_position() {
int x, y;
SDL_GetGlobalMouseState(&x, &y);
return {(int32_t)x, (int32_t)y};
2021-03-01 14:40:02 -05:00
}
bool platform::get_mouse_button_down(const int button) {
Uint8 sdl_button = SDL_BUTTON_LEFT;
switch(button) {
case 0:
sdl_button = SDL_BUTTON_LEFT;
break;
case 1:
sdl_button = SDL_BUTTON_RIGHT;
break;
case 2:
sdl_button = SDL_BUTTON_MIDDLE;
break;
}
return (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(sdl_button)) != 0;
2021-03-01 14:40:02 -05:00
}
float mouse_wheel_x, mouse_wheel_y;
2021-03-01 14:40:02 -05:00
std::tuple<float, float> platform::get_wheel_delta() {
return {mouse_wheel_x, mouse_wheel_y};
2021-03-01 14:40:02 -05:00
}
std::tuple<float, float> platform::get_right_stick_position() {
return {0.0f, 0.0f};
2021-03-01 14:40:02 -05:00
}
std::tuple<float, float> platform::get_left_stick_position() {
return {0.0f, 0.0f};
2021-03-01 14:40:02 -05:00
}
void platform::capture_mouse(const bool capture) {
SDL_SetRelativeMouseMode((SDL_bool)capture);
2021-03-01 14:40:02 -05:00
}
void platform::begin_text_input() {
SDL_StartTextInput();
}
void platform::end_text_input() {
SDL_StopTextInput();
2021-03-01 14:40:02 -05:00
}
bool platform::supports_context(GFXContext context) {
2022-02-21 15:53:42 -05:00
#ifdef ENABLE_DX12
if(context == GFXContext::DirectX)
return true;
#endif
#ifdef ENABLE_VULKAN
if(context == GFXContext::Vulkan)
return true;
#endif
#ifdef ENABLE_METAL
if(context == GFXContext::Metal)
return true;
#endif
if(context == GFXContext::None)
return true;
return false;
}
void platform::initialize_context(const GFXContext context) {
#ifdef ENABLE_METAL
if(context == GFXContext::Metal) {
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
}
#endif
}
void* platform::get_context_information() {
#ifdef ENABLE_VULKAN
if(gfx_interface->required_context() == GFXContext::Vulkan) {
// dummy window
auto dummy = SDL_CreateWindow("", 0, 0, 1, 1, SDL_WINDOW_VULKAN);
unsigned int count = 0;
SDL_Vulkan_GetInstanceExtensions(dummy, &count, nullptr);
std::vector<const char*> extensions(count);
SDL_Vulkan_GetInstanceExtensions(dummy, &count, extensions.data());
SDL_DestroyWindow(dummy);
auto info = new vulkan_information();
info->surface_extensions = extensions;
return (void*)info;
}
#endif
return nullptr;
}
void* platform::create_surface(window_ptr window, void* surface_creation_info) {
#ifdef ENABLE_VULKAN
if(gfx_interface->required_context() == GFXContext::Vulkan) {
return create_vulkan_surface(window, surface_creation_info);
}
#endif
#ifdef ENABLE_METAL
if(gfx_interface->required_context() == GFXContext::Metal) {
return create_metal_surface(window, surface_creation_info);
}
#endif
return nullptr;
}
void* platform::get_next_image(window_ptr window) {
#ifdef ENABLE_METAL
if(gfx_interface->required_context() == GFXContext::Metal) {
return get_next_metal_drawable(window);
}
#endif
return nullptr;
}
template<class GFXBackend>
void try_initialize() {
if(gfx_interface == nullptr) {
auto backend = new GFXBackend();
2022-02-21 15:53:42 -05:00
const bool supported = backend->is_supported() && platform::supports_context(backend->required_context());
if(!supported) {
prism::log("Failed to initialize GFX backend... trying next...");
} else {
gfx_interface = backend;
platform::initialize_context(gfx_interface->required_context());
}
}
}
2021-03-01 14:40:02 -05:00
int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
2021-03-01 14:40:02 -05:00
// determine gfx context at the beginning
2022-02-21 15:53:42 -05:00
#ifdef ENABLE_DX12
try_initialize<gfx_dx12>();
#endif
2022-02-15 11:29:56 -05:00
#ifdef ENABLE_METAL
try_initialize<GFXMetal>();
#endif
#ifdef ENABLE_VULKAN
try_initialize<GFXVulkan>();
2022-02-15 11:29:56 -05:00
#endif
try_initialize<GFXDummy>();
engine = new prism::engine(argc, argv);
2021-03-01 14:40:02 -05:00
app = new @APP_CLASS@();
engine->set_app(app);
GFXCreateInfo info = {};
if(gfx_interface->initialize(info)) {
engine->set_gfx(gfx_interface);
2021-03-01 14:40:02 -05:00
} else {
return -1;
}
app_main(engine);
auto end = std::chrono::high_resolution_clock::now();
2021-04-20 00:47:04 -04:00
while(!engine->is_quitting()) {
2021-03-01 14:40:02 -05:00
SDL_Event event = {};
while(SDL_PollEvent(&event)) {
2021-04-20 00:47:04 -04:00
switch(event.type) {
case SDL_QUIT:
engine->quit();
break;
case SDL_MOUSEWHEEL: {
mouse_wheel_x = event.wheel.x;
mouse_wheel_y = event.wheel.y;
}
break;
case SDL_MOUSEBUTTONDOWN:
{
int engine_button = 0;
if(event.button.button == SDL_BUTTON_RIGHT)
engine_button = 1;
else if(event.button.button == SDL_BUTTON_MIDDLE)
engine_button = 2;
engine->process_mouse_down(engine_button, {0, 0});
}
break;
case SDL_KEYDOWN:
{
engine->process_key_down(event.key.keysym.scancode);
}
break;
case SDL_KEYUP:
{
engine->process_key_up(event.key.keysym.scancode);
}
break;
2021-04-20 00:47:04 -04:00
case SDL_WINDOWEVENT:
{
2021-04-20 00:47:04 -04:00
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
auto window = get_window_by_sdl_id(event.window.windowID);
if(window != nullptr)
engine->resize(window, {static_cast<uint32_t>(event.window.data1), static_cast<uint32_t>(event.window.data2)});
} else if(event.window.event == SDL_WINDOWEVENT_MOVED) {
auto window = get_window_by_sdl_id(event.window.windowID);
if(window != nullptr)
engine->move(window);
} else if(event.window.event == SDL_WINDOWEVENT_CLOSE) {
engine->quit();
2021-04-20 00:47:04 -04:00
}
}
2021-04-20 00:47:04 -04:00
break;
case SDL_TEXTINPUT:
{
engine->process_text_input(event.text.text);
}
break;
2021-04-20 00:47:04 -04:00
}
2021-03-01 14:40:02 -05:00
}
if(engine->is_quitting())
break;
auto begin = std::chrono::high_resolution_clock::now();
float deltatime = (float)std::chrono::duration_cast<std::chrono::nanoseconds>(begin - end).count() / 1000000000ULL;
end = begin;
engine->update(deltatime);
engine->begin_frame(deltatime);
2021-04-20 00:47:04 -04:00
for(auto window : windows)
engine->render(window);
2021-03-01 14:40:02 -05:00
engine->end_frame();
2021-03-01 14:40:02 -05:00
}
engine->prepare_quit();
return 0;
2021-03-01 14:40:02 -05:00
}
#if defined(PLATFORM_WINDOWS) && !defined(__MINGW32__)
PlatformTheme platform::get_theme() {
using namespace winrt::Windows::UI::ViewManagement;
// TODO: figure out if this works pre-anniversary update/other windows other than 10
UISettings settings;
auto background = settings.GetColorValue(UIColorType::Background);
auto foreground = settings.GetColorValue(UIColorType::Foreground);
if (background == winrt::Windows::UI::Colors::White())
return PlatformTheme::Light;
else
return PlatformTheme::Dark;
}
#else
2021-03-01 14:40:02 -05:00
PlatformTheme platform::get_theme() {
return PlatformTheme::Light;
}
#endif