Initial implementation.
This commit is contained in:
parent
1aa4656eb0
commit
f51dd5b437
66
.clang-format
Normal file
66
.clang-format
Normal file
@ -0,0 +1,66 @@
|
||||
# Generated from CLion C/C++ Code Style settings
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Always
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 0
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 8
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 0
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
10
SConstruct
10
SConstruct
@ -1,10 +1,14 @@
|
||||
config = {
|
||||
'PROJECT_NAME': 'spp_template'
|
||||
'PROJECT_NAME': 'RAID Framework',
|
||||
'CXX_NO_EXCEPTIONS': True
|
||||
}
|
||||
env = SConscript('external/scons-plus-plus/SConscript', exports = ['config'])
|
||||
env.Append(CPPPATH = [Dir('private'), Dir('public')])
|
||||
|
||||
# app
|
||||
env = env.Module('private/spp_template/SModule')
|
||||
# library
|
||||
env = env.Module('private/raid/SModule')
|
||||
|
||||
# test app
|
||||
env = env.Module('private/raid_test/SModule')
|
||||
|
||||
env.Finalize()
|
||||
|
2
external/scons-plus-plus
vendored
2
external/scons-plus-plus
vendored
@ -1 +1 @@
|
||||
Subproject commit c883f3c1c777357957e30fc44cf987e8bb62c818
|
||||
Subproject commit c994752c3244fdf9835b1d3a5238094d2a799855
|
31
private/raid/SModule
Normal file
31
private/raid/SModule
Normal 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')
|
240
private/raid/application.cpp
Normal file
240
private/raid/application.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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)
|
21
private/raid_test/main.cpp
Normal file
21
private/raid_test/main.cpp
Normal 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
|
||||
}
|
||||
});
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
return 0;
|
||||
}
|
133
public/raid/raid.hpp
Normal file
133
public/raid/raid.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RAID_PUBLIC_RAID_RAID_HPP_INCLUDED)
|
||||
#define RAID_PUBLIC_RAID_RAID_HPP_INCLUDED 1
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <fmt/format.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace raid
|
||||
{
|
||||
inline constexpr int ERR_INIT_FAILED = 100;
|
||||
|
||||
enum class MessageSeverity : unsigned char
|
||||
{
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR
|
||||
};
|
||||
|
||||
struct Message
|
||||
{
|
||||
MessageSeverity severity;
|
||||
const char* text;
|
||||
};
|
||||
|
||||
class Application
|
||||
{
|
||||
private:
|
||||
bool mRunning = true;
|
||||
SDL_Window* mWindow = nullptr;
|
||||
SDL_GLContext mGLContext = nullptr;
|
||||
|
||||
using glClear_fn_t = void (*)(std::uint32_t);
|
||||
using glClearColor_fn_t = void (*)(float, float, float, float);
|
||||
|
||||
glClear_fn_t glClear;
|
||||
glClearColor_fn_t glClearColor;
|
||||
public:
|
||||
virtual ~Application() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
int run(int argc, char* argv[]);
|
||||
|
||||
protected:
|
||||
virtual void render() = 0;
|
||||
virtual void handleMessage(const Message& message);
|
||||
virtual void handleSDLEvent(const SDL_Event& event);
|
||||
|
||||
void msgInfo(const char* text)
|
||||
{
|
||||
handleMessage({
|
||||
.severity = MessageSeverity::INFO,
|
||||
.text = text
|
||||
});
|
||||
}
|
||||
void msgWarning(const char* text)
|
||||
{
|
||||
handleMessage({
|
||||
.severity = MessageSeverity::WARNING,
|
||||
.text = text
|
||||
});
|
||||
}
|
||||
void msgError(const char* text)
|
||||
{
|
||||
handleMessage({
|
||||
.severity = MessageSeverity::ERROR,
|
||||
.text = text
|
||||
});
|
||||
}
|
||||
void msgInfo(const std::string& text)
|
||||
{
|
||||
msgInfo(text.c_str());
|
||||
}
|
||||
void msgWarning(const std::string& text)
|
||||
{
|
||||
msgWarning(text.c_str());
|
||||
}
|
||||
void msgError(const std::string& text)
|
||||
{
|
||||
msgError(text.c_str());
|
||||
}
|
||||
template<typename TArg, typename... TArgs>
|
||||
void msgInfo(fmt::format_string<TArg, TArgs...> format, TArg&& arg, TArgs&&... args)
|
||||
{
|
||||
std::string text = fmt::format(format, std::forward<TArg>(arg), std::forward<TArgs>(args)...);
|
||||
msgInfo(text);
|
||||
}
|
||||
template<typename TArg, typename... TArgs>
|
||||
void msgWarning(fmt::format_string<TArg, TArgs...> format, TArg&& arg, TArgs&&... args)
|
||||
{
|
||||
std::string text = fmt::format(format, std::forward<TArg>(arg), std::forward<TArgs>(args)...);
|
||||
msgWarning(text);
|
||||
}
|
||||
template<typename TArg, typename... TArgs>
|
||||
void msgError(fmt::format_string<TArg, TArgs...> format, TArg&& arg, TArgs&&... args)
|
||||
{
|
||||
std::string text = fmt::format(format, std::forward<TArg>(arg), std::forward<TArgs>(args)...);
|
||||
msgError(text);
|
||||
}
|
||||
private:
|
||||
bool initSDL();
|
||||
bool initGL();
|
||||
bool initImGui();
|
||||
void cleanup();
|
||||
void handleSDLEvents();
|
||||
};
|
||||
|
||||
using render_cb_t = std::function<void()>;
|
||||
struct QuickAppOptions
|
||||
{
|
||||
struct
|
||||
{
|
||||
render_cb_t render;
|
||||
} callbacks;
|
||||
};
|
||||
|
||||
class QuickApp : public Application
|
||||
{
|
||||
private:
|
||||
QuickAppOptions mOptions;
|
||||
public:
|
||||
void init(QuickAppOptions options);
|
||||
void render() override;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
int runQuick(int argc, char* argv[], QuickAppOptions options);
|
||||
} // namespace raid
|
||||
|
||||
#endif // !defined(RAID_PUBLIC_RAID_RAID_HPP_INCLUDED)
|
Loading…
x
Reference in New Issue
Block a user