raid/public/raid/raid.hpp

231 lines
6.3 KiB
C++

#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 <imgui.h>
#include <mijin/async/coroutine.hpp>
#include <mijin/util/bitflags.hpp>
#include <mijin/virtual_filesystem/memory.hpp>
#include <mijin/virtual_filesystem/stacked.hpp>
#include <SDL3/SDL.h>
namespace raid
{
inline constexpr int ERR_INIT_FAILED = 100;
inline constexpr ImGuiWindowFlags DEFAULT_MAIN_WINDOW_FLAGS = 0
| ImGuiWindowFlags_NoBackground
| ImGuiWindowFlags_NoDecoration
| ImGuiWindowFlags_NoBringToFrontOnFocus
| ImGuiWindowFlags_NoNav;
inline constexpr const char* DEFAULT_FONT_PATH = "/data/fonts/NotoSans-Regular.ttf";
enum class MessageSeverity : unsigned char
{
INFO,
WARNING,
ERROR
};
struct Message
{
MessageSeverity severity;
const char* text;
};
struct FontFlags : mijin::BitFlags<FontFlags>
{
bool pixelSnapH : 1 = false;
};
struct FontConfig
{
fs::path path;
std::vector<std::pair<ImWchar, ImWchar>> glyphRanges;
float size = 20.f;
FontFlags flags;
};
class Application
{
private:
SDL_Window* mWindow = nullptr;
SDL_GLContext mGLContext = nullptr;
mijin::StackedFileSystemAdapter mFS;
mijin::MemoryFileSystemAdapter* mMemoryFS = nullptr;
mijin::SimpleTaskLoop mTaskLoop;
std::unordered_map<fs::path, ImTextureID> mTextures;
bool mRunning = true;
ImGuiWindowFlags mMainWindowFlags = DEFAULT_MAIN_WINDOW_FLAGS;
using GLbitfield = std::uint32_t;
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;
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:
virtual ~Application() = default;
[[nodiscard]]
mijin::StackedFileSystemAdapter& getFS() { return mFS; }
[[nodiscard]]
mijin::MemoryFileSystemAdapter& getMemoryFS()
{
MIJIN_ASSERT_FATAL(mMemoryFS != nullptr, "Memory FS has not been initialized yet.");
return *mMemoryFS;
}
[[nodiscard]]
mijin::SimpleTaskLoop& getLoop() { return mTaskLoop; }
[[nodiscard]]
ImGuiWindowFlags getMainWindowFlags() const { return mMainWindowFlags; }
void setMainWindowFlags(ImGuiWindowFlags flags) { mMainWindowFlags = flags; }
void requestQuit() { mRunning = false; }
[[nodiscard]]
int run(int argc, char* argv[]);
[[nodiscard]]
bool loadFonts(std::span<const FontConfig> fonts);
[[nodiscard]]
bool loadFont(const FontConfig& font)
{
return loadFonts({&font, 1});
}
[[nodiscard]]
ImTextureID getOrLoadTexture(fs::path path);
protected:
virtual void render() = 0;
virtual std::string getFolderName() = 0;
virtual std::string getWindowTitle() = 0;
virtual void configureImgui();
virtual std::vector<FontConfig> getDefaultFonts();
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);
}
virtual bool init();
virtual void cleanup();
private:
bool initSDL();
bool initGL();
bool initImGui();
void handleSDLEvents();
void loadImGuiConfig();
void saveImGuiConfig();
};
using render_cb_t = std::function<void()>;
struct QuickAppOptions
{
struct
{
render_cb_t render;
} callbacks;
std::string folderName = "raid";
std::string windowTitle = "RAID";
ImGuiWindowFlags mainWindowFlags = DEFAULT_MAIN_WINDOW_FLAGS;
};
class QuickApp : public Application
{
private:
render_cb_t mRenderCallback;
std::string mFolderName;
std::string mWindowTitle;
public:
void preInit(QuickAppOptions options);
void render() override;
std::string getFolderName() override;
std::string getWindowTitle() override;
static QuickApp& get();
};
[[nodiscard]]
int runQuick(int argc, char* argv[], QuickAppOptions options);
} // namespace raid
#endif // !defined(RAID_PUBLIC_RAID_RAID_HPP_INCLUDED)