Added texture managment and overridable init/cleanup functions.
This commit is contained in:
parent
53efca4729
commit
08ea619a8e
@ -12,5 +12,6 @@
|
|||||||
},
|
},
|
||||||
"SDL": {
|
"SDL": {
|
||||||
"min": [3,0,0]
|
"min": [3,0,0]
|
||||||
}
|
},
|
||||||
|
"stb": {}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ Import('env')
|
|||||||
|
|
||||||
src_files = Split("""
|
src_files = Split("""
|
||||||
application.cpp
|
application.cpp
|
||||||
|
stb_image.cpp
|
||||||
""")
|
""")
|
||||||
|
|
||||||
with open('../../dependencies.json', 'r') as f:
|
with open('../../dependencies.json', 'r') as f:
|
||||||
|
@ -13,14 +13,51 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <backends/imgui_impl_opengl3.h>
|
#include <backends/imgui_impl_opengl3.h>
|
||||||
#include <backends/imgui_impl_sdl3.h>
|
#include <backends/imgui_impl_sdl3.h>
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
namespace raid
|
namespace raid
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr int GL_COLOR_BUFFER_BIT = 0x00004000;
|
constexpr std::uint32_t GL_COLOR_BUFFER_BIT = 0x00004000;
|
||||||
|
constexpr std::uint32_t GL_TEXTURE_2D = 0x0DE1;
|
||||||
|
constexpr std::uint32_t GL_TEXTURE_MIN_FILTER = 0x2801;
|
||||||
|
constexpr std::uint32_t GL_TEXTURE_MAG_FILTER = 0x2800;
|
||||||
|
constexpr std::uint32_t GL_LINEAR = 0x2601;
|
||||||
|
constexpr std::uint32_t GL_UNPACK_ROW_LENGTH = 0x0CF2;
|
||||||
|
constexpr std::uint32_t GL_RGBA = 0x1908;
|
||||||
|
constexpr std::uint32_t GL_UNSIGNED_BYTE = 0x1401;
|
||||||
|
|
||||||
const char* IMGUI_GLSL_VERSION = "#version 130";
|
const char* IMGUI_GLSL_VERSION = "#version 130";
|
||||||
QuickApp* gAppInstance = nullptr;
|
QuickApp* gAppInstance = nullptr;
|
||||||
|
|
||||||
|
int stbiRead(void* user, char* data, int size)
|
||||||
|
{
|
||||||
|
mijin::Stream& stream = *static_cast<mijin::Stream*>(user);
|
||||||
|
std::size_t read = 0;
|
||||||
|
if (const mijin::StreamError error = stream.readRaw(data, size, {.partial = true}, &read); error != mijin::StreamError::SUCCESS)
|
||||||
|
{
|
||||||
|
MIJIN_ERROR("IO error.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return static_cast<int>(read);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stbiSkip(void* user, int diff)
|
||||||
|
{
|
||||||
|
mijin::Stream& stream = *static_cast<mijin::Stream*>(user);
|
||||||
|
if (const mijin::StreamError error = stream.seek(diff, mijin::SeekMode::RELATIVE); error != mijin::StreamError::SUCCESS)
|
||||||
|
{
|
||||||
|
MIJIN_ERROR("IO error.");
|
||||||
|
// not much we can do :/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int stbiEof(void* user)
|
||||||
|
{
|
||||||
|
mijin::Stream& stream = *static_cast<mijin::Stream*>(user);
|
||||||
|
return stream.isAtEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Application::run(int argc, char** argv)
|
int Application::run(int argc, char** argv)
|
||||||
@ -32,90 +69,7 @@ int Application::run(int argc, char** argv)
|
|||||||
cleanup();
|
cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto addConfigDir = [&](const fs::path path)
|
if (!init())
|
||||||
{
|
|
||||||
using namespace mijin::vfs_pipe;
|
|
||||||
mFS.addAdapter(os()
|
|
||||||
| relative_to(path)
|
|
||||||
| map_to("/config")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto addDataDir = [&](const fs::path path)
|
|
||||||
{
|
|
||||||
using namespace mijin::vfs_pipe;
|
|
||||||
mFS.addAdapter(os()
|
|
||||||
| relative_to(path)
|
|
||||||
| map_to("/data")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
addConfigDir(mijin::getKnownFolder(mijin::KnownFolder::USER_CONFIG_ROOT) / getFolderName());
|
|
||||||
addDataDir(mijin::getKnownFolder(mijin::KnownFolder::USER_DATA_ROOT) / getFolderName());
|
|
||||||
|
|
||||||
auto createUserDir = [&](const fs::path& virtualPath)
|
|
||||||
{
|
|
||||||
mijin::Optional<fs::path> pathOpt = mFS.getNativePath(virtualPath);
|
|
||||||
if (!pathOpt.empty())
|
|
||||||
{
|
|
||||||
const fs::path path = std::move(*pathOpt);
|
|
||||||
if (!fs::exists(path))
|
|
||||||
{
|
|
||||||
const bool result = fs::create_directories(path);
|
|
||||||
MIJIN_ASSERT(result, "Error creating user folder.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MIJIN_ERROR("User folder path shouldn't be empty.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
createUserDir("/config");
|
|
||||||
createUserDir("/data");
|
|
||||||
|
|
||||||
// in development builds, also add the development folders
|
|
||||||
#if !defined(RAID_RELEASE)
|
|
||||||
addConfigDir(fs::current_path() / "data/config");
|
|
||||||
addDataDir(fs::current_path() / "data/data");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// now also add the system folders
|
|
||||||
for (const fs::path& path : mijin::getAllConfigFolders(mijin::IncludeUser::NO))
|
|
||||||
{
|
|
||||||
addConfigDir(path / getFolderName());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const fs::path& path : mijin::getAllDataFolders(mijin::IncludeUser::NO))
|
|
||||||
{
|
|
||||||
addDataDir(path / getFolderName());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(RAID_RELEASE)
|
|
||||||
for (const mijin::PathReference& reference : mFS.getAllPaths("/config"))
|
|
||||||
{
|
|
||||||
reference.getNativePath().then([&](const fs::path& path)
|
|
||||||
{
|
|
||||||
msgInfo("Config folder: {}", path.generic_string());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (const mijin::PathReference& reference : mFS.getAllPaths("/data"))
|
|
||||||
{
|
|
||||||
reference.getNativePath().then([&](const fs::path& path)
|
|
||||||
{
|
|
||||||
msgInfo("Data folder: {}", path.generic_string());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!initSDL())
|
|
||||||
{
|
|
||||||
return ERR_INIT_FAILED;
|
|
||||||
}
|
|
||||||
if (!initGL())
|
|
||||||
{
|
|
||||||
return ERR_INIT_FAILED;
|
|
||||||
}
|
|
||||||
if (!initImGui())
|
|
||||||
{
|
{
|
||||||
return ERR_INIT_FAILED;
|
return ERR_INIT_FAILED;
|
||||||
}
|
}
|
||||||
@ -198,6 +152,52 @@ bool Application::loadFont(const fs::path& path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImTextureID Application::getOrLoadTexture(fs::path path)
|
||||||
|
{
|
||||||
|
if (auto it = mTextures.find(path); it != mTextures.end())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stbi_io_callbacks callbacks = {
|
||||||
|
.read = &stbiRead,
|
||||||
|
.skip = &stbiSkip,
|
||||||
|
.eof = &stbiEof
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<mijin::Stream> stream;
|
||||||
|
if (const mijin::StreamError error = mFS.open(path, mijin::FileOpenMode::READ, stream); error != mijin::StreamError::SUCCESS)
|
||||||
|
{
|
||||||
|
msgError("Error opening file {} for reading: {}.", path.generic_string(), mijin::errorName(error));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
unsigned char* imageData = stbi_load_from_callbacks(&callbacks, stream.get(), &width, &height, nullptr, 4);
|
||||||
|
if (imageData == nullptr)
|
||||||
|
{
|
||||||
|
msgError("Error parsing image at {}.", path.generic_string());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create texture
|
||||||
|
GLuint texture = 0;
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
|
||||||
|
// setup texture
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// upload image
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||||
|
|
||||||
|
mTextures.emplace(std::move(path), texture);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
void Application::configureImgui()
|
void Application::configureImgui()
|
||||||
{
|
{
|
||||||
ImGuiIO& imguiIO = ImGui::GetIO();
|
ImGuiIO& imguiIO = ImGui::GetIO();
|
||||||
@ -236,6 +236,131 @@ void Application::handleSDLEvent(const SDL_Event& event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Application::init()
|
||||||
|
{
|
||||||
|
auto addConfigDir = [&](const fs::path& path)
|
||||||
|
{
|
||||||
|
using namespace mijin::vfs_pipe;
|
||||||
|
mFS.addAdapter(os()
|
||||||
|
| relative_to(path)
|
||||||
|
| map_to("/config")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto addDataDir = [&](const fs::path& path)
|
||||||
|
{
|
||||||
|
using namespace mijin::vfs_pipe;
|
||||||
|
mFS.addAdapter(os()
|
||||||
|
| relative_to(path)
|
||||||
|
| map_to("/data")
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
addConfigDir(mijin::getKnownFolder(mijin::KnownFolder::USER_CONFIG_ROOT) / getFolderName());
|
||||||
|
addDataDir(mijin::getKnownFolder(mijin::KnownFolder::USER_DATA_ROOT) / getFolderName());
|
||||||
|
|
||||||
|
auto createUserDir = [&](const fs::path& virtualPath)
|
||||||
|
{
|
||||||
|
mijin::Optional<fs::path> pathOpt = mFS.getNativePath(virtualPath);
|
||||||
|
if (!pathOpt.empty())
|
||||||
|
{
|
||||||
|
const fs::path path = std::move(*pathOpt);
|
||||||
|
if (!fs::exists(path))
|
||||||
|
{
|
||||||
|
const bool result = fs::create_directories(path);
|
||||||
|
MIJIN_ASSERT(result, "Error creating user folder.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MIJIN_ERROR("User folder path shouldn't be empty.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
createUserDir("/config");
|
||||||
|
createUserDir("/data");
|
||||||
|
|
||||||
|
// in development builds, also add the development folders
|
||||||
|
#if !defined(RAID_RELEASE)
|
||||||
|
addConfigDir(fs::current_path() / "data/config");
|
||||||
|
addDataDir(fs::current_path() / "data/data");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// now also add the system folders
|
||||||
|
for (const fs::path& path : mijin::getAllConfigFolders(mijin::IncludeUser::NO))
|
||||||
|
{
|
||||||
|
addConfigDir(path / getFolderName());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const fs::path& path : mijin::getAllDataFolders(mijin::IncludeUser::NO))
|
||||||
|
{
|
||||||
|
addDataDir(path / getFolderName());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(RAID_RELEASE)
|
||||||
|
for (const mijin::PathReference& reference : mFS.getAllPaths("/config"))
|
||||||
|
{
|
||||||
|
reference.getNativePath().then([&](const fs::path& path)
|
||||||
|
{
|
||||||
|
msgInfo("Config folder: {}", path.generic_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (const mijin::PathReference& reference : mFS.getAllPaths("/data"))
|
||||||
|
{
|
||||||
|
reference.getNativePath().then([&](const fs::path& path)
|
||||||
|
{
|
||||||
|
msgInfo("Data folder: {}", path.generic_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!initSDL())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!initGL())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!initImGui())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::cleanup()
|
||||||
|
{
|
||||||
|
if (ImGui::GetCurrentContext() != nullptr)
|
||||||
|
{
|
||||||
|
saveImGuiConfig();
|
||||||
|
|
||||||
|
const ImGuiIO& imguiIO = ImGui::GetIO();
|
||||||
|
if (imguiIO.BackendRendererUserData != nullptr)
|
||||||
|
{
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
}
|
||||||
|
if (imguiIO.BackendPlatformUserData != nullptr)
|
||||||
|
{
|
||||||
|
ImGui_ImplSDL3_Shutdown();
|
||||||
|
}
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
}
|
||||||
|
for (const auto& [path, texture] : mTextures)
|
||||||
|
{
|
||||||
|
const GLuint asUint = static_cast<GLuint>(texture);
|
||||||
|
glDeleteTextures(1, &asUint);
|
||||||
|
}
|
||||||
|
if (mGLContext != nullptr)
|
||||||
|
{
|
||||||
|
SDL_GL_DestroyContext(mGLContext);
|
||||||
|
}
|
||||||
|
if (mWindow != nullptr)
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(mWindow);
|
||||||
|
}
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
bool Application::initSDL()
|
bool Application::initSDL()
|
||||||
{
|
{
|
||||||
if (!SDL_Init(0))
|
if (!SDL_Init(0))
|
||||||
@ -280,6 +405,12 @@ bool Application::initGL()
|
|||||||
|
|
||||||
glClear = reinterpret_cast<glClear_fn_t>(SDL_GL_GetProcAddress("glClear"));
|
glClear = reinterpret_cast<glClear_fn_t>(SDL_GL_GetProcAddress("glClear"));
|
||||||
glClearColor = reinterpret_cast<glClearColor_fn_t>(SDL_GL_GetProcAddress("glClearColor"));
|
glClearColor = reinterpret_cast<glClearColor_fn_t>(SDL_GL_GetProcAddress("glClearColor"));
|
||||||
|
glGenTextures = reinterpret_cast<glGenTextures_fn_t>(SDL_GL_GetProcAddress("glGenTextures"));
|
||||||
|
glBindTexture = reinterpret_cast<glBindTexture_fn_t>(SDL_GL_GetProcAddress("glBindTexture"));
|
||||||
|
glTexParameteri = reinterpret_cast<glTexParameteri_fn_t>(SDL_GL_GetProcAddress("glTexParameteri"));
|
||||||
|
glPixelStorei = reinterpret_cast<glPixelStorei_fn_t>(SDL_GL_GetProcAddress("glPixelStorei"));
|
||||||
|
glTexImage2D = reinterpret_cast<glTexImage2D_fn_t>(SDL_GL_GetProcAddress("glTexImage2D"));
|
||||||
|
glDeleteTextures = reinterpret_cast<glDeleteTextures_fn_t>(SDL_GL_GetProcAddress("glDeleteTextures"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -330,34 +461,6 @@ bool Application::initImGui()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::cleanup()
|
|
||||||
{
|
|
||||||
if (ImGui::GetCurrentContext() != nullptr)
|
|
||||||
{
|
|
||||||
saveImGuiConfig();
|
|
||||||
|
|
||||||
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()
|
void Application::handleSDLEvents()
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
@ -401,7 +504,7 @@ void Application::saveImGuiConfig()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickApp::init(QuickAppOptions options)
|
void QuickApp::preInit(QuickAppOptions options)
|
||||||
{
|
{
|
||||||
MIJIN_ASSERT_FATAL(options.callbacks.render, "Missing render callback.");
|
MIJIN_ASSERT_FATAL(options.callbacks.render, "Missing render callback.");
|
||||||
mRenderCallback = std::move(options.callbacks.render);
|
mRenderCallback = std::move(options.callbacks.render);
|
||||||
@ -435,7 +538,7 @@ int runQuick(int argc, char* argv[], QuickAppOptions options)
|
|||||||
{
|
{
|
||||||
QuickApp app;
|
QuickApp app;
|
||||||
gAppInstance = &app;
|
gAppInstance = &app;
|
||||||
app.init(std::move(options));
|
app.preInit(std::move(options));
|
||||||
return app.run(argc, argv);
|
return app.run(argc, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
private/raid/stb_image.cpp
Normal file
4
private/raid/stb_image.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include <stb_image.h>
|
||||||
|
#undef STB_IMAGE_IMPLEMENTATION
|
@ -40,15 +40,35 @@ private:
|
|||||||
SDL_GLContext mGLContext = nullptr;
|
SDL_GLContext mGLContext = nullptr;
|
||||||
|
|
||||||
mijin::StackedFileSystemAdapter mFS;
|
mijin::StackedFileSystemAdapter mFS;
|
||||||
|
std::unordered_map<fs::path, ImTextureID> mTextures;
|
||||||
|
|
||||||
bool mRunning = true;
|
bool mRunning = true;
|
||||||
ImGuiWindowFlags mMainWindowFlags = DEFAULT_MAIN_WINDOW_FLAGS;
|
ImGuiWindowFlags mMainWindowFlags = DEFAULT_MAIN_WINDOW_FLAGS;
|
||||||
|
|
||||||
using glClear_fn_t = void (*)(std::uint32_t);
|
using GLbitfield = std::uint32_t;
|
||||||
using glClearColor_fn_t = void (*)(float, float, float, float);
|
using GLint = std::int32_t;
|
||||||
|
using GLuint = std::uint32_t;
|
||||||
|
using GLsizei = std::int32_t;
|
||||||
|
using GLenum = std::uint32_t;
|
||||||
|
using GLfloat = float;
|
||||||
|
|
||||||
|
using glClear_fn_t = void (*)(GLbitfield);
|
||||||
|
using glClearColor_fn_t = void (*)(GLfloat, GLfloat, GLfloat, GLfloat);
|
||||||
|
using glGenTextures_fn_t = void (*)(GLsizei, GLuint*);
|
||||||
|
using glBindTexture_fn_t = void (*)(GLenum, GLuint);
|
||||||
|
using glTexParameteri_fn_t = void (*)(GLenum, GLenum, GLint);
|
||||||
|
using glPixelStorei_fn_t = void (*)(GLenum, GLint);
|
||||||
|
using glTexImage2D_fn_t = void (*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void*);
|
||||||
|
using glDeleteTextures_fn_t = void (*)(GLsizei, const GLuint*);
|
||||||
|
|
||||||
glClear_fn_t glClear;
|
glClear_fn_t glClear;
|
||||||
glClearColor_fn_t glClearColor;
|
glClearColor_fn_t glClearColor;
|
||||||
|
glGenTextures_fn_t glGenTextures;
|
||||||
|
glBindTexture_fn_t glBindTexture;
|
||||||
|
glTexParameteri_fn_t glTexParameteri;
|
||||||
|
glPixelStorei_fn_t glPixelStorei;
|
||||||
|
glTexImage2D_fn_t glTexImage2D;
|
||||||
|
glDeleteTextures_fn_t glDeleteTextures;
|
||||||
public:
|
public:
|
||||||
virtual ~Application() = default;
|
virtual ~Application() = default;
|
||||||
|
|
||||||
@ -64,6 +84,9 @@ public:
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool loadFont(const fs::path& path);
|
bool loadFont(const fs::path& path);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
ImTextureID getOrLoadTexture(fs::path path);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void render() = 0;
|
virtual void render() = 0;
|
||||||
virtual std::string getFolderName() = 0;
|
virtual std::string getFolderName() = 0;
|
||||||
@ -123,11 +146,12 @@ protected:
|
|||||||
std::string text = fmt::format(format, std::forward<TArg>(arg), std::forward<TArgs>(args)...);
|
std::string text = fmt::format(format, std::forward<TArg>(arg), std::forward<TArgs>(args)...);
|
||||||
msgError(text);
|
msgError(text);
|
||||||
}
|
}
|
||||||
|
virtual bool init();
|
||||||
|
virtual void cleanup();
|
||||||
private:
|
private:
|
||||||
bool initSDL();
|
bool initSDL();
|
||||||
bool initGL();
|
bool initGL();
|
||||||
bool initImGui();
|
bool initImGui();
|
||||||
void cleanup();
|
|
||||||
void handleSDLEvents();
|
void handleSDLEvents();
|
||||||
void loadImGuiConfig();
|
void loadImGuiConfig();
|
||||||
void saveImGuiConfig();
|
void saveImGuiConfig();
|
||||||
@ -152,7 +176,7 @@ private:
|
|||||||
std::string mFolderName;
|
std::string mFolderName;
|
||||||
std::string mWindowTitle;
|
std::string mWindowTitle;
|
||||||
public:
|
public:
|
||||||
void init(QuickAppOptions options);
|
void preInit(QuickAppOptions options);
|
||||||
void render() override;
|
void render() override;
|
||||||
std::string getFolderName() override;
|
std::string getFolderName() override;
|
||||||
std::string getWindowTitle() override;
|
std::string getWindowTitle() override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user