mirror of
https://github.com/MadeOfJelly/MushMachine.git
synced 2025-06-20 11:46:36 +02:00
initial import, >900commits predate this
This commit is contained in:
292
framework/sdl_service/src/mm/services/sdl_service.cpp
Normal file
292
framework/sdl_service/src/mm/services/sdl_service.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
#include "./sdl_service.hpp"
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#ifdef MM_OPENGL_3_GLES
|
||||
//#include <SDL_opengles2_gl2.h>
|
||||
#include <GLES3/gl3.h>
|
||||
#else
|
||||
#include <glad/glad.h>
|
||||
#endif
|
||||
|
||||
#ifndef MM_OPENGL_3_GLES
|
||||
#include <tracy/TracyOpenGL.hpp>
|
||||
#else
|
||||
#define TracyGpuContext
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include <mm/logger.hpp>
|
||||
#define LOG_CRIT(...) __LOG_CRIT( "SDLService", __VA_ARGS__)
|
||||
#define LOG_ERROR(...) __LOG_ERROR("SDLService", __VA_ARGS__)
|
||||
#define LOG_WARN(...) __LOG_WARN( "SDLService", __VA_ARGS__)
|
||||
#define LOG_INFO(...) __LOG_INFO( "SDLService", __VA_ARGS__)
|
||||
#define LOG_DEBUG(...) __LOG_DEBUG("SDLService", __VA_ARGS__)
|
||||
#define LOG_TRACE(...) __LOG_TRACE("SDLService", __VA_ARGS__)
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
SDLService::SDLService(uint32_t sdl_init_flags) {
|
||||
MM::Logger::initSectionLogger("SDLService");
|
||||
|
||||
LOG_TRACE("constructing SDLService...");
|
||||
|
||||
//#ifdef __EMSCRIPTEN__
|
||||
//sdl_init_flags &= ~SDL_INIT_HAPTIC;
|
||||
//#endif
|
||||
|
||||
if (SDL_Init(sdl_init_flags)) {
|
||||
LOG_CRIT("SDL_Init() failed: {}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SDLService::~SDLService(void) {
|
||||
LOG_TRACE("deconstructing SDLService...");
|
||||
|
||||
if (gl_context) {
|
||||
SDL_GL_DeleteContext(gl_context);
|
||||
}
|
||||
|
||||
if (win) {
|
||||
LOG_WARN("destroying open window");
|
||||
destroyWindow();
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
bool SDLService::enable(Engine& engine) {
|
||||
bool succ = true;
|
||||
_func_handle = engine.addUpdate([this](Engine& e) { this->processEvents(e); });
|
||||
if (!_func_handle.expired()) {
|
||||
auto tmp_lock = _func_handle.lock();
|
||||
tmp_lock->priority = 100; // before the calls before the scene
|
||||
tmp_lock->name = "sdl events";
|
||||
} else {
|
||||
succ = false;
|
||||
}
|
||||
|
||||
_f_func_handle = engine.addFixedUpdate([this](Engine& e) { this->processEvents(e); });
|
||||
if (!_f_func_handle.expired()) {
|
||||
auto tmp_lock = _f_func_handle.lock();
|
||||
tmp_lock->priority = 100; // before the calls before the scene
|
||||
tmp_lock->name = "sdl events";
|
||||
} else {
|
||||
succ = false;
|
||||
}
|
||||
|
||||
return succ;
|
||||
}
|
||||
|
||||
void SDLService::disable(Engine& engine) {
|
||||
// remove update hooks
|
||||
if (!_func_handle.expired())
|
||||
engine.removeUpdate(_func_handle);
|
||||
|
||||
if (!_f_func_handle.expired())
|
||||
engine.removeFixedUpdate(_f_func_handle);
|
||||
|
||||
// destroy stuff
|
||||
if (gl_context) {
|
||||
SDL_GL_DeleteContext(gl_context);
|
||||
}
|
||||
|
||||
if (win) {
|
||||
LOG_WARN("destroying open window");
|
||||
destroyWindow();
|
||||
}
|
||||
}
|
||||
|
||||
bool SDLService::createWindow(const char* title, int screen_width, int screen_height, uint32_t sdl_window_flags) {
|
||||
if (!win) {
|
||||
win = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height, sdl_window_flags);
|
||||
if (setDefaultWindowIcon) {
|
||||
setDefaultIcon();
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("tried to create window while already existing. ignoring");
|
||||
}
|
||||
return win; // implicit conversion to bool
|
||||
}
|
||||
|
||||
void SDLService::destroyWindow(void) {
|
||||
if (win) {
|
||||
SDL_DestroyWindow(win);
|
||||
win = nullptr;
|
||||
} else {
|
||||
LOG_WARN("tried to destroy window while no window exists. ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<int, int> SDLService::getWindowSize(SDL_Window* win_ptr) {
|
||||
if (!win_ptr)
|
||||
win_ptr = win; // defaulting to currently managed window
|
||||
if (!win_ptr) {
|
||||
LOG_ERROR("cannot get size of nullptr window");
|
||||
return {0, 0};
|
||||
}
|
||||
int w, h;
|
||||
//SDL_GetWindowSize(win_ptr, &w, &h); // does not support hdpi
|
||||
SDL_GL_GetDrawableSize(win_ptr, &w, &h);
|
||||
return {w, h};
|
||||
}
|
||||
|
||||
bool SDLService::createGLContext(SDL_Window* win_ptr) {
|
||||
if (!win_ptr)
|
||||
win_ptr = win; // defaulting to currently managed window
|
||||
|
||||
if (!win_ptr) {
|
||||
LOG_ERROR("cannot create gl context with nullptr window");
|
||||
return false;
|
||||
}
|
||||
|
||||
gl_context = SDL_GL_CreateContext(win_ptr);
|
||||
if (!gl_context) {
|
||||
LOG_ERROR("SDL_GL_CreateContext(): {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef MM_OPENGL_3_GLES
|
||||
// glad
|
||||
if (!gladLoadGLLoader((GLADloadproc) SDL_GL_GetProcAddress)) {
|
||||
LOG_ERROR("Failed to initialize OpenGL context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SDL_GL_MakeCurrent(win, gl_context)) {
|
||||
LOG_ERROR("SDL_GL_MakeCurrent(): {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
TracyGpuContext;
|
||||
|
||||
LOG_INFO("gl: {}", glGetString(GL_VERSION));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDLService::createGLWindow(const char* title, int screen_width, int screen_height, uint32_t sdl_window_flags) {
|
||||
#ifdef MM_OPENGL_3_GLES
|
||||
// opengl es 3.0
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
#else
|
||||
//Use OpenGL 3.3 core
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
#endif
|
||||
if (!createWindow(title, screen_width, screen_height, SDL_WINDOW_OPENGL | sdl_window_flags)) {
|
||||
return false;
|
||||
}
|
||||
if (!createGLContext()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLService::processEvents(Engine& engine) {
|
||||
ZoneScoped;
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_QUIT) {
|
||||
engine.stop();
|
||||
} else {
|
||||
for (auto& h : _event_handler_list) {
|
||||
if ((*h)(e))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDLService::EventHandlerHandle SDLService::addEventHandler(std::function<bool(const SDL_Event&)> function) {
|
||||
if (!function) {
|
||||
// error
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto& r = _event_handler_list.emplace_back(std::make_unique<EventHandlerType>(function));
|
||||
|
||||
return r.get();
|
||||
}
|
||||
|
||||
void SDLService::removeEventHandler(EventHandlerHandle function_handle) {
|
||||
if (!function_handle) {
|
||||
// error
|
||||
return;
|
||||
}
|
||||
|
||||
_event_handler_list.erase(
|
||||
std::remove_if(_event_handler_list.begin(), _event_handler_list.end(),
|
||||
[&](std::unique_ptr<EventHandlerType>& eh) { return function_handle == eh.get(); }
|
||||
),
|
||||
_event_handler_list.end()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void SDLService::setDefaultIcon(void) {
|
||||
if (!win) {
|
||||
LOG_WARN("tried to set icon of NO window");
|
||||
return;
|
||||
}
|
||||
#include "../logo-f6c-square.png.h"
|
||||
|
||||
setIcon(
|
||||
(void*)logo_f6c_square.pixel_data,
|
||||
logo_f6c_square.width,
|
||||
logo_f6c_square.height,
|
||||
logo_f6c_square.bytes_per_pixel
|
||||
);
|
||||
}
|
||||
|
||||
void SDLService::setIcon(SDL_Surface* surf) {
|
||||
if (!win) {
|
||||
LOG_WARN("tried to set icon of NO window");
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SetWindowIcon(win, surf);
|
||||
}
|
||||
|
||||
void SDLService::setIcon(void* data, size_t width, size_t height, size_t bytes_per_pixel) {
|
||||
if (!win) {
|
||||
LOG_WARN("tried to set icon of NO window");
|
||||
return;
|
||||
}
|
||||
|
||||
// thanks to Danial at https://blog.gibson.sh/2015/04/13/how-to-integrate-your-sdl2-window-icon-or-any-image-into-your-executable/
|
||||
uint32_t rmask, gmask, bmask, amask;
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
int shift = (bytes_per_pixel == 3) ? 8 : 0;
|
||||
rmask = 0xff000000 >> shift;
|
||||
gmask = 0x00ff0000 >> shift;
|
||||
bmask = 0x0000ff00 >> shift;
|
||||
amask = 0x000000ff >> shift;
|
||||
#else // little endian, like x86
|
||||
rmask = 0x000000ff;
|
||||
gmask = 0x0000ff00;
|
||||
bmask = 0x00ff0000;
|
||||
amask = (bytes_per_pixel == 3) ? 0 : 0xff000000;
|
||||
#endif
|
||||
|
||||
SDL_Surface* icon = SDL_CreateRGBSurfaceFrom(
|
||||
data,
|
||||
width, height,
|
||||
bytes_per_pixel * 8,
|
||||
bytes_per_pixel * width,
|
||||
rmask, gmask, bmask, amask);
|
||||
|
||||
setIcon(icon);
|
||||
|
||||
SDL_FreeSurface(icon);
|
||||
}
|
||||
|
||||
} // namespace MM::Services
|
||||
|
64
framework/sdl_service/src/mm/services/sdl_service.hpp
Normal file
64
framework/sdl_service/src/mm/services/sdl_service.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <mm/engine.hpp>
|
||||
|
||||
//#include <vector> // engine.hpp
|
||||
//#include <functional> // engine.hpp
|
||||
|
||||
namespace MM::Services {
|
||||
|
||||
class SDLService : public Service {
|
||||
public:
|
||||
SDL_Window* win{nullptr};
|
||||
SDL_GLContext gl_context{nullptr};
|
||||
|
||||
bool setDefaultWindowIcon = true;
|
||||
|
||||
using EventHandlerType = std::function<bool(const SDL_Event&)>;
|
||||
using EventHandlerHandle = EventHandlerType*;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<EventHandlerType>> _event_handler_list;
|
||||
|
||||
Engine::FunctionDataHandle _func_handle;
|
||||
Engine::FunctionDataHandle _f_func_handle;
|
||||
|
||||
public:
|
||||
SDLService(uint32_t sdl_init_flags = SDL_INIT_EVERYTHING);
|
||||
~SDLService(void);
|
||||
|
||||
public:
|
||||
bool enable(Engine& engine) override;
|
||||
void disable(Engine& engine) override; // destroys windows and ass contexts
|
||||
|
||||
const char* name(void) override { return "SDLService"; }
|
||||
|
||||
public:
|
||||
// creates window, returns if created successfully
|
||||
bool createWindow(const char* title, int screen_width, int screen_height, uint32_t sdl_window_flags = SDL_WINDOW_SHOWN);
|
||||
void destroyWindow(void);
|
||||
|
||||
std::pair<int, int> getWindowSize(SDL_Window* win_ptr = nullptr);
|
||||
|
||||
bool createGLContext(SDL_Window* win_ptr = nullptr);
|
||||
|
||||
// creates a window and a gl_context
|
||||
bool createGLWindow(const char* title, int screen_width, int screen_height, uint32_t sdl_window_flags = SDL_WINDOW_SHOWN);
|
||||
|
||||
private:
|
||||
void processEvents(Engine& engine);
|
||||
|
||||
public:
|
||||
EventHandlerHandle addEventHandler(std::function<bool(const SDL_Event&)> function);
|
||||
void removeEventHandler(EventHandlerHandle function_handle);
|
||||
|
||||
// sets the icon of the "current" window
|
||||
void setDefaultIcon(void);
|
||||
void setIcon(SDL_Surface* surf);
|
||||
void setIcon(void* data, size_t width, size_t height, size_t bytes_per_pixel);
|
||||
};
|
||||
|
||||
} // namespace MM::Services
|
||||
|
Reference in New Issue
Block a user