Initial implementation.

This commit is contained in:
2025-03-02 16:01:30 +01:00
parent 1aa4656eb0
commit f51dd5b437
9 changed files with 503 additions and 12 deletions

31
private/raid/SModule Normal file
View File

@@ -0,0 +1,31 @@
Import('env')
src_files = Split("""
application.cpp
""")
lib_raid = env.UnityStaticLibrary(
name = 'RAID',
target = env['LIB_DIR'] + '/raid',
source = src_files,
dependencies = {
'fmt': {},
'mijin': {},
'imgui': {
'options': {
'docking': True,
'backends': [
'sdl3',
'opengl3'
]
}
},
'SDL': {
'min': (3,0,0)
}
}
)
env.Default(lib_raid)
Return('env')

View File

@@ -0,0 +1,240 @@
#include "raid/raid.hpp"
#include <chrono>
#include <thread>
#include <fmt/base.h>
#include <SDL3/SDL.h>
#include <mijin/debug/assert.hpp>
#include <mijin/util/scope_guard.hpp>
#include <imgui.h>
#include <backends/imgui_impl_opengl3.h>
#include <backends/imgui_impl_sdl3.h>
namespace raid
{
namespace
{
constexpr int GL_COLOR_BUFFER_BIT = 0x00004000;
const char* IMGUI_GLSL_VERSION = "#version 130";
}
int Application::run(int argc, char** argv)
{
(void) argc;
(void) argv;
MIJIN_SCOPE_EXIT {
cleanup();
};
if (!initSDL())
{
return ERR_INIT_FAILED;
}
if (!initGL())
{
return ERR_INIT_FAILED;
}
if (!initImGui())
{
return ERR_INIT_FAILED;
}
while (mRunning)
{
handleSDLEvents();
if (SDL_GetWindowFlags(mWindow) & SDL_WINDOW_MINIMIZED)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
continue;
}
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowPos({0, 0});
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::Begin("##main", nullptr, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration);
render();
ImGui::End();
ImGui::Render();
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(mWindow);
}
return 0;
}
void Application::handleMessage(const Message& message)
{
switch (message.severity)
{
case MessageSeverity::INFO:
fmt::print("INFO: {}", message.text);
break;
case MessageSeverity::WARNING:
fmt::print("WARNING: {}", message.text);
break;
case MessageSeverity::ERROR:
fmt::print(stderr, "ERROR: {}", message.text);
break;
}
}
void Application::handleSDLEvent(const SDL_Event& event)
{
switch (event.type)
{
case SDL_EVENT_QUIT:
mRunning = false;
return;
default:
ImGui_ImplSDL3_ProcessEvent(&event);
break;
}
}
bool Application::initSDL()
{
if (!SDL_Init(0))
{
msgError("Error initializing SDL: {}.", SDL_GetError());
return false;
}
// GL attributes must be set before window creation
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// TODO: not sure if these really make sense, but they are in the example
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
const SDL_WindowFlags WINDOW_FLAGS = 0
| SDL_WINDOW_OPENGL
| SDL_WINDOW_RESIZABLE
| SDL_WINDOW_HIGH_PIXEL_DENSITY;
mWindow = SDL_CreateWindow(
/* title = */ "RAID",
/* w = */ 1280,
/* h = */ 720,
/* flags = */ WINDOW_FLAGS
);
return true;
}
bool Application::initGL()
{
mGLContext = SDL_GL_CreateContext(mWindow);
if (mWindow == nullptr)
{
msgError("Error creating SDL window: {}.", SDL_GetError());
return false;
}
SDL_GL_MakeCurrent(mWindow, mGLContext);
SDL_GL_SetSwapInterval(1); // enable vsync, at least for now
glClear = reinterpret_cast<glClear_fn_t>(SDL_GL_GetProcAddress("glClear"));
glClearColor = reinterpret_cast<glClearColor_fn_t>(SDL_GL_GetProcAddress("glClearColor"));
return true;
}
bool Application::initImGui()
{
IMGUI_CHECKVERSION(); // not exactly useful when using static libs, but won't hurt
if (ImGui::CreateContext() == nullptr)
{
msgError("Error initializing ImGui context.");
return false;
}
ImGuiIO& imguiIO = ImGui::GetIO();
imguiIO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
imguiIO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
// default style
ImGui::StyleColorsDark();
// init the backends
if (!ImGui_ImplSDL3_InitForOpenGL(mWindow, mGLContext))
{
msgError("Error initializing ImGui SDL3 backend.");
return false;
}
if (!ImGui_ImplOpenGL3_Init(IMGUI_GLSL_VERSION))
{
msgError("Error initializing ImGui OpenGL3 backend.");
return false;
}
// init font
imguiIO.Fonts->AddFontDefault();
return true;
}
void Application::cleanup()
{
if (ImGui::GetCurrentContext() != nullptr)
{
const ImGuiIO& imguiIO = ImGui::GetIO();
if (imguiIO.BackendRendererUserData != nullptr)
{
ImGui_ImplOpenGL3_Shutdown();
}
if (imguiIO.BackendPlatformUserData != nullptr)
{
ImGui_ImplSDL3_Shutdown();
}
ImGui::DestroyContext();
}
if (mGLContext != nullptr)
{
SDL_GL_DestroyContext(mGLContext);
}
if (mWindow != nullptr)
{
SDL_DestroyWindow(mWindow);
}
SDL_Quit();
}
void Application::handleSDLEvents()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
handleSDLEvent(event);
}
}
void QuickApp::init(QuickAppOptions options)
{
MIJIN_ASSERT_FATAL(options.callbacks.render, "Missing render callback.");
mOptions = std::move(options);
}
void QuickApp::render()
{
mOptions.callbacks.render();
}
int runQuick(int argc, char* argv[], QuickAppOptions options)
{
QuickApp app;
app.init(std::move(options));
return app.run(argc, argv);
}
}

View File

@@ -6,11 +6,12 @@ src_files = Split("""
""")
prog_app = env.UnityProgram(
name = 'Template',
target = env['BIN_DIR'] + '/spp_template',
name = 'Test App',
target = env['BIN_DIR'] + '/raid_test',
source = src_files,
dependencies = {
'mijin': {}
'mijin': {},
'RAID': {}
}
)
env.Default(prog_app)

View File

@@ -0,0 +1,21 @@
#include "raid/raid.hpp"
#include <imgui.h>
namespace
{
void render()
{
ImGui::Text("hi");
}
}
int main(int argc, char* argv[])
{
return raid::runQuick(argc, argv, {
.callbacks = {
.render = &render
}
});
}

View File

@@ -1,5 +0,0 @@
int main(int, char**)
{
return 0;
}