Compare commits

...

2 Commits

Author SHA1 Message Date
609f7337da created ResourceManager 2025-05-19 03:26:18 +05:00
d700aae02e duplicate files fix 2025-05-19 02:27:39 +05:00
25 changed files with 503 additions and 697 deletions

View File

@ -4,7 +4,7 @@
namespace ougge { namespace ougge {
Engine::Engine() Engine::Engine()
: gameObjectPool(GAMEOBJECTPOOL_SIZE) : gameObjectPool(GAMEOBJECTPOOL_SIZE), textures(&resourceManager)
{ {
} }
@ -17,7 +17,7 @@ void Engine::init(){
} }
void Engine::openMainWindow(const std::string& window_title){ void Engine::openMainWindow(const std::string& window_title){
mainWindow.open(window_title); mainWindow.open(window_title, resourceManager);
} }
void Engine::startLoop(){ void Engine::startLoop(){

View File

@ -1,50 +1,51 @@
#pragma once #pragma once
#include "common/function_shared_ptr.hpp" #include "common/function_shared_ptr.hpp"
#include "mono/mono.hpp" #include "mono/mono.hpp"
#include "game/GameObjectPool.hpp" #include "game/GameObjectPool.hpp"
#include "gui/MainWindow.hpp" #include "gui/MainWindow.hpp"
#include "resources/textures.hpp" #include "resources/textures.hpp"
namespace ougge { namespace ougge {
#define GAMEOBJECTPOOL_SIZE 64*1024 #define GAMEOBJECTPOOL_SIZE 64*1024
using UpdateFunc_t = function_shared_ptr<void(f64)>; using UpdateFunc_t = function_shared_ptr<void(f64)>;
class Engine { class Engine {
bool loop_running = false; bool loop_running = false;
game::GameObjectPool gameObjectPool; game::GameObjectPool gameObjectPool;
u64 obj_id = 0; u64 obj_id = 0;
MonoClass* gameObjectClass; MonoClass* gameObjectClass;
Mono::Method<void(u64, u32)> gameObjectCtor; Mono::Method<void(u64, u32)> gameObjectCtor;
Mono::Method<void(f64)> gameObjectInvokeUpdate; Mono::Method<void(f64)> gameObjectInvokeUpdate;
Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent; Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent;
public: public:
gui::MainWindow mainWindow; gui::MainWindow mainWindow;
UpdateFunc_t updateCallback; UpdateFunc_t updateCallback;
Mono::RuntimeJIT mono; Mono::RuntimeJIT mono;
std::shared_ptr<Mono::Assembly> engineManagedAssembly; std::shared_ptr<Mono::Assembly> engineManagedAssembly;
resources::CacheStorage<resources::Texture> textures; resources::ResourceManager resourceManager;
resources::CacheStorage<resources::Texture> textures;
Engine();
void init(); Engine();
void openMainWindow(const std::string& window_title); void init();
// start game loop on the current thread void openMainWindow(const std::string& window_title);
void startLoop(); // start game loop on the current thread
void stopLoop(); void startLoop();
void stopLoop();
game::GameObject& createGameObject();
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName); game::GameObject& createGameObject();
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName);
private:
void tryDrawFrame(f64 deltaTime); private:
void updateGameObjects(f64 deltaTime); void tryDrawFrame(f64 deltaTime);
}; void updateGameObjects(f64 deltaTime);
};
}
}

View File

@ -4,8 +4,6 @@
#include "MainWindow.hpp" #include "MainWindow.hpp"
#include "gui_exceptions.hpp" #include "gui_exceptions.hpp"
#include "../common/ougge_format.hpp" #include "../common/ougge_format.hpp"
#include "../resources/fonts.hpp"
#include "../resources/textures.hpp"
#include "../common/math.hpp" #include "../common/math.hpp"
namespace ougge::gui { namespace ougge::gui {
@ -21,7 +19,7 @@ f32 MainWindow::getDPI(){
return dpi; return dpi;
} }
void MainWindow::open(const std::string& window_title){ void MainWindow::open(const std::string& window_title, resources::ResourceManager& resourceManager){
SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING)); SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING));
SDL_version v; SDL_version v;
SDL_GetVersion(&v); SDL_GetVersion(&v);
@ -72,8 +70,12 @@ void MainWindow::open(const std::string& window_title){
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
resources::ResourceFactory* font_res = resourceManager.tryGetResource(default_font_path);
if(font_res == nullptr)
throw UsefulException("can't find default font resource");
f32 dpi = getDPI(); f32 dpi = getDPI();
io.FontDefault = resources::ImFont_LoadFromResource(default_font, default_font_size, dpi); io.FontDefault = resources::ImFont_LoadFromResource(font_res, default_font_size, dpi);
} }
void MainWindow::close(){ void MainWindow::close(){

View File

@ -1,45 +1,47 @@
#pragma once #pragma once
#include <SDL.h> #include <SDL.h>
#include <imgui.h> #include <imgui.h>
#include "../common/std.hpp" #include "../common/std.hpp"
#include "../common/time.hpp" #include "../common/time.hpp"
#include "../resources/resources.hpp"
/// converts hex color to float vector #include "../resources/fonts.hpp"
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
/// converts float vector to hex color /// converts hex color to float vector
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)} #define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
/// converts float vector to hex color
namespace ougge::gui { #define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
#define default_font "DroidSans" namespace ougge::gui {
class MainWindow { #define default_font_path "fonts/DroidSans.ttf"
public:
i32 fps_max = 60; class MainWindow {
f32 default_font_size = 14.0f; public:
ImVec4 clear_color = RGBAHexToF(35,35,50,255); i32 fps_max = 60;
SDL_Window* sdl_window = nullptr; f32 default_font_size = 14.0f;
SDL_Renderer* sdl_renderer = nullptr; ImVec4 clear_color = RGBAHexToF(35,35,50,255);
SDL_Window* sdl_window = nullptr;
private: SDL_Renderer* sdl_renderer = nullptr;
bool show_debug_window = true;
bool show_demo_window = false; private:
bool show_metrics_window = false; bool show_debug_window = true;
bool show_demo_window = false;
public: bool show_metrics_window = false;
void open(const std::string& window_title);
void close(); public:
void open(const std::string& window_title, resources::ResourceManager& resourceManager);
/// process io events happened since previous frame void close();
void pollEvents(bool* loopRunning);
void beginFrame(); /// process io events happened since previous frame
void endFrame(); void pollEvents(bool* loopRunning);
void beginFrame();
f32 getDPI(); void endFrame();
private:
void draw_debug_window(); f32 getDPI();
void draw_bg_window(); private:
}; void draw_debug_window();
void draw_bg_window();
} };
}

View File

@ -0,0 +1,40 @@
#include "MemoryStream.hpp"
class MemoryStreamBuf : public std::streambuf {
public:
MemoryStreamBuf(void* p, const std::size_t n);
virtual std::istream::pos_type seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which);
};
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
char* p=(char*)_p;
setg(p, p, p + n);
setp(p, p + n);
}
std::istream::pos_type MemoryStreamBuf::seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which)
{
if (dir == std::ios_base::cur)
gbump(off);
else if (dir == std::ios_base::end)
setg(eback(), egptr() + off, egptr());
else if (dir == std::ios_base::beg)
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
: std::istream(new MemoryStreamBuf((void*)p, n))
{}
MemoryStreamRead::~MemoryStreamRead(){
delete rdbuf();
}

View File

@ -0,0 +1,8 @@
#include <iostream>
class MemoryStreamRead : public std::istream {
public:
MemoryStreamRead(const void* p, const std::size_t n);
virtual ~MemoryStreamRead();
};

View File

@ -1,94 +0,0 @@
#include <fstream>
#include <sstream>
#include "../common/UsefulException.hpp"
#include "../common/ougge_format.hpp"
#include "resources.hpp"
#include "embedded_resources.h"
namespace ougge::resources {
Resource::Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func)
: path(path), size(size), openStream(open_read_steam_func)
{}
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
char* p=(char*)_p;
setg(p, p, p + n);
setp(p, p + n);
}
std::istream::pos_type MemoryStreamBuf::seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which)
{
if (dir == std::ios_base::cur)
gbump(off);
else if (dir == std::ios_base::end)
setg(eback(), egptr() + off, egptr());
else if (dir == std::ios_base::beg)
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
: std::istream(new MemoryStreamBuf((void*)p, n))
{}
MemoryStreamRead::~MemoryStreamRead(){
delete rdbuf();
}
static std::unordered_map<std::string, Resource>* _resourceMap = nullptr;
void loadEmbeddedresources(){
for(int i = 0; i < EmbeddedResource_table_count; i++){
const EmbeddedResource& e = EmbeddedResource_table[i];
std::cout <<"loading resource '" << e.path << "' "
<< formatSizeHumanReadable(e.size) << std::endl;
auto embedded_resource_factory = [e]() -> std::unique_ptr<std::istream> {
return std::make_unique<MemoryStreamRead>(e.data, e.size);
};
auto r = _resourceMap->emplace(e.path,
Resource(e.path, e.size, embedded_resource_factory));
if(!r.second)
throw UsefulException(ougge_format("can't load duplicate resource '%s'", e.path));
}
}
void init(){
if(_resourceMap != nullptr)
throw UsefulException("resource has been initialized already");
_resourceMap = new std::unordered_map<std::string, Resource>();
loadEmbeddedresources();
}
Resource& getResource(const std::string& path){
auto it = _resourceMap->find(path);
if(it == _resourceMap->end())
throw UsefulException(ougge_format("can't find resource '%s'", path.c_str()));
return it->second;
}
std::string formatSizeHumanReadable(std::size_t b){
std::stringstream ss;
ss.precision(3);
std::size_t k = b / 1024;
std::size_t m = k / 1024;
std::size_t g = m / 1024;
if(g)
ss<<m / 1024.0f<<'G';
else if(m)
ss<<k / 1024.0f<<'M';
else if(k)
ss<<b / 1024.0f<<'K';
else ss<<b;
return ss.str();
}
}

View File

@ -1,63 +0,0 @@
#pragma once
#include "../common/std.hpp"
#include <iostream>
#include <functional>
#include <unordered_map>
namespace ougge::resources {
// call this in main()
void init();
std::string formatSizeHumanReadable(std::size_t byte_n);
class Resource {
public:
const std::string path;
const std::size_t size;
using StreamFactoryMethod = std::function< std::unique_ptr<std::istream> () >;
Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func);
const StreamFactoryMethod openStream;
};
class MemoryStreamBuf : public std::streambuf {
public:
MemoryStreamBuf(void* p, const std::size_t n);
virtual std::istream::pos_type seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which);
};
class MemoryStreamRead : public std::istream {
public:
MemoryStreamRead(const void* p, const std::size_t n);
virtual ~MemoryStreamRead();
};
Resource& getResource(const std::string& path);
/// @brief stores requested resources in memory
/// @tparam T must implement constructor `T(const Resource&, ...)`
template<class T>
class CacheStorage {
std::unordered_map<std::string, T> _map;
public:
template<typename... TCtorArgs>
T& getOrCreate(const std::string& name, TCtorArgs&&... ctor_args){
auto it = _map.find(name);
if(it != _map.end())
return it->second;
auto& res = getResource(name);
auto e = _map.emplace(name, T(res, ctor_args...));
return e.first->second;
}
};
}

View File

@ -1,7 +1,4 @@
#include <imgui.h> #include "fonts.hpp"
#include "resources.hpp"
#include <cstdio>
#include <cstring>
namespace ougge::resources { namespace ougge::resources {
@ -16,17 +13,16 @@ ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi
return io.Fonts->AddFontFromFileTTF(file_path.c_str(), font_size, nullptr, glyph_ranges); return io.Fonts->AddFontFromFileTTF(file_path.c_str(), font_size, nullptr, glyph_ranges);
} }
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi){ ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi){
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
font_size *= dpi; font_size *= dpi;
ImFontConfig font_cfg = ImFontConfig(); ImFontConfig font_cfg = ImFontConfig();
std::sprintf(font_cfg.Name, "%s %ipx", font_name.c_str(), (i32)font_size); std::sprintf(font_cfg.Name, "%s %ipx", res->path.c_str(), (i32)font_size);
auto& res = getResource("fonts/" + font_name + ".ttf"); char* font_data = new char[res->size];
char* font_data = new char[res.size]; res->openStream()->read(font_data, res->size);
res.openStream()->read(font_data, res.size);
return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res.size, return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res->size,
font_size, &font_cfg, glyph_ranges); font_size, &font_cfg, glyph_ranges);
} }

View File

@ -1,12 +1,13 @@
#pragma once #pragma once
#include "imgui.h" #include <imgui.h>
#include "../common/std.hpp" #include "../common/std.hpp"
#include "resources.hpp"
namespace ougge::resources { namespace ougge::resources {
ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi); ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi);
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi); ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi);
} }

View File

@ -1,96 +0,0 @@
#include "textures.hpp"
#include <SDL_image.h>
#include "../gui/gui_exceptions.hpp"
namespace ougge::resources {
Texture::Texture(const Resource& r, SDL_Renderer* renderer)
: Texture(*r.openStream(), r.size, renderer)
{}
Texture::Texture(std::istream& s, size_t size, SDL_Renderer* renderer)
: renderer(renderer), texture(nullptr), w(0), h(0)
{
SDL_RWops* sdl_stream = SDL_RWFromIStream(s, size);
if(!sdl_stream)
throw gui::SDLException();
texture = std::shared_ptr<SDL_Texture>(IMG_LoadTexture_RW(renderer, sdl_stream, 1), SDL_DestroyTexture);
if(!texture)
throw gui::IMGException();
SDL_TRY(SDL_QueryTexture(texture.get(), nullptr, nullptr, &w, &h));
}
SDL_RenderCopyExF_Params::SDL_RenderCopyExF_Params()
: rotation_angle(0), flip(SDL_FLIP_NONE)
{}
void Texture::render(const SDL_FRect& target_section){
SDL_TRY(
SDL_RenderCopyF(renderer, texture.get(), nullptr, &target_section)
);
}
void Texture::render(const SDL_FRect& target_section, const SDL_Rect& texture_section){
SDL_TRY(
SDL_RenderCopyF(renderer, texture.get(), &texture_section, &target_section)
);
}
void Texture::render(const SDL_RenderCopyExF_Params& p){
SDL_TRY(
SDL_RenderCopyExF(renderer, texture.get(),
optional_value_ptr_or_null(p.texture_section),
optional_value_ptr_or_null(p.target_section),
-1.0f * angleToDegree(normalizeAngle(p.rotation_angle)),
optional_value_ptr_or_null(p.rotation_center),
p.flip
)
)
}
static Sint64 istream_size(SDL_RWops* context){
return (Sint64)(size_t)context->hidden.unknown.data2;
}
static Sint64 istream_seek(SDL_RWops* context, Sint64 offset, i32 whence){
std::istream* stream = (std::istream*)context->hidden.unknown.data1;
switch(whence){
case SEEK_SET: stream->seekg(offset, std::ios::beg); break;
case SEEK_CUR: stream->seekg(offset, std::ios::cur); break;
case SEEK_END: stream->seekg(offset, std::ios::end); break;
default: break;
}
return stream->fail() ? -1 : (Sint64)stream->tellg();
}
static size_t istream_read(SDL_RWops* context, void *ptr, size_t size, size_t maxnum){
if(size == 0)
return -1;
std::istream* stream = (std::istream*)context->hidden.unknown.data1;
stream->read((char*)ptr, size * maxnum);
return stream->bad() ? -1 : stream->gcount() / size;
}
static i32 istream_close(SDL_RWops* context){
if (context)
SDL_FreeRW(context);
return 0;
}
SDL_RWops* SDL_RWFromIStream(std::istream& stream, size_t size){
SDL_RWops* rwops = SDL_AllocRW();
if(rwops) {
rwops->size = istream_size;
rwops->seek = istream_seek;
rwops->read = istream_read;
rwops->write = nullptr;
rwops->close = istream_close;
rwops->hidden.unknown.data1 = &stream;
rwops->hidden.unknown.data2 = (void*)size;
rwops->type = SDL_RWOPS_UNKNOWN;
}
return rwops;
}
}

View File

@ -1,44 +0,0 @@
#pragma once
#include <iostream>
#include <optional>
#include <SDL.h>
#include "resources.hpp"
#include "../common/math.hpp"
namespace ougge::resources {
#define SDL_RectConstruct(X, Y, W, H) (SDL_Rect){X, Y, W, H}
#define SDL_FRectConstruct(X, Y, W, H) (SDL_FRect){X, Y, W, H}
#define SDL_PointConstruct(X, Y) (SDL_Point){X, Y, W, H}
#define SDL_FPointConstruct(X, Y) (SDL_FPoint){X, Y, W, H}
#define optional_value_ptr_or_null(OPT) (OPT ? &(*OPT) : nullptr)
SDL_RWops* SDL_RWFromIStream(std::istream& stream, size_t size);
struct SDL_RenderCopyExF_Params {
std::optional<SDL_Rect> texture_section;
std::optional<SDL_FRect> target_section;
std::optional<SDL_FPoint> rotation_center;
angle_t rotation_angle;
SDL_RendererFlip flip;
SDL_RenderCopyExF_Params();
};
struct Texture {
SDL_Renderer* renderer;
std::shared_ptr<SDL_Texture> texture;
i32 w;
i32 h;
Texture(const Resource& r, SDL_Renderer* renderer);
Texture(std::istream& s, size_t size, SDL_Renderer* renderer);
void render(const SDL_FRect& target_section);
void render(const SDL_FRect& target_section, const SDL_Rect& texture_section);
void render(const SDL_RenderCopyExF_Params& params);
};
}

View File

@ -1,65 +1,84 @@
#include <sstream> #include <sstream>
#include <stdarg.h> #include <stdarg.h>
#include "ougge_format.hpp" #include "ougge_format.hpp"
#include "UsefulException.hpp" #include "UsefulException.hpp"
std::string _ougge_format(const std::string& format_str, const size_t args_count, ...){ std::string _ougge_format(const std::string& format_str, const size_t args_count, ...){
va_list vl; va_list vl;
va_start(vl, args_count); va_start(vl, args_count);
std::stringstream ss; std::stringstream ss;
for(size_t i = 0; i < format_str.length(); i++){ for(size_t i = 0; i < format_str.length(); i++){
char c = format_str[i]; char c = format_str[i];
// format specifier // format specifier
if(c == '%'){ if(c == '%'){
c = format_str[++i]; c = format_str[++i];
bool l = false; bool l = false;
while(c == 'l'){ while(c == 'l'){
l = true; l = true;
c = format_str[++i]; c = format_str[++i];
} }
switch(c){ switch(c){
case 'u': case 'u':
if(l) ss<<(u64)va_arg(vl, u64); if(l) ss<<(u64)va_arg(vl, u64);
else ss<<(u32)va_arg(vl, u32); else ss<<(u32)va_arg(vl, u32);
break; break;
case 'i': case 'i':
case 'd': case 'd':
if(l) ss<<(i64)va_arg(vl, i64); if(l) ss<<(i64)va_arg(vl, i64);
else ss<<(i32)va_arg(vl, i32); else ss<<(i32)va_arg(vl, i32);
break; break;
case 'f': case 'f':
// f32 is promoted to f64 when passed through '...' // f32 is promoted to f64 when passed through '...'
ss<<(f64)va_arg(vl, f64); ss<<(f64)va_arg(vl, f64);
break; break;
case 'p': case 'p':
ss<<(void*)va_arg(vl, void*); ss<<(void*)va_arg(vl, void*);
break; break;
case 'x': case 'x':
if(l) ss<<std::hex<<(u64)va_arg(vl, u64); if(l) ss<<std::hex<<(u64)va_arg(vl, u64);
else ss<<std::hex<<(u32)va_arg(vl, u32); else ss<<std::hex<<(u32)va_arg(vl, u32);
break; break;
case 's': { case 's': {
const char* cptr = va_arg(vl,char*); const char* cptr = va_arg(vl,char*);
if(cptr != nullptr) if(cptr != nullptr)
ss<<cptr; ss<<cptr;
else ss<<"<nullptr>"; else ss<<"<nullptr>";
break; break;
} }
case 'c': case 'c':
ss<<(char)va_arg(vl,int); ss<<(char)va_arg(vl,int);
break; break;
default: default:
throw UsefulException("invalid format cpecifier"); throw UsefulException("invalid format cpecifier");
} }
} }
// regular character // regular character
else ss<<c; else ss<<c;
} }
va_end(vl); va_end(vl);
return ss.str(); return ss.str();
} }
std::string formatSizeHumanReadable(std::size_t b){
std::stringstream ss;
ss.precision(3);
std::size_t k = b / 1024;
std::size_t m = k / 1024;
std::size_t g = m / 1024;
if(g)
ss<<m / 1024.0f<<'G';
else if(m)
ss<<k / 1024.0f<<'M';
else if(k)
ss<<b / 1024.0f<<'K';
else ss<<b;
return ss.str();
}

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include "std.hpp" #include "std.hpp"
std::string _ougge_format(const std::string& format_str, const size_t args_count, ...); std::string _ougge_format(const std::string& format_str, const size_t args_count, ...);
#define ougge_format(FORMAT_STR, ARGS...) _ougge_format(FORMAT_STR, count_args(ARGS) ,##ARGS) #define ougge_format(FORMAT_STR, ARGS...) _ougge_format(FORMAT_STR, count_args(ARGS) ,##ARGS)
std::string formatSizeHumanReadable(std::size_t byte_n);

View File

@ -4,8 +4,6 @@
#include "MainWindow.hpp" #include "MainWindow.hpp"
#include "gui_exceptions.hpp" #include "gui_exceptions.hpp"
#include "../common/ougge_format.hpp" #include "../common/ougge_format.hpp"
#include "../resources/fonts.hpp"
#include "../resources/textures.hpp"
#include "../common/math.hpp" #include "../common/math.hpp"
namespace ougge::gui { namespace ougge::gui {
@ -21,7 +19,7 @@ f32 MainWindow::getDPI(){
return dpi; return dpi;
} }
void MainWindow::open(const std::string& window_title){ void MainWindow::open(const std::string& window_title, resources::ResourceManager& resourceManager){
SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING)); SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING));
SDL_version v; SDL_version v;
SDL_GetVersion(&v); SDL_GetVersion(&v);
@ -72,8 +70,12 @@ void MainWindow::open(const std::string& window_title){
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
resources::ResourceFactory* font_res = resourceManager.tryGetResource(default_font_path);
if(font_res == nullptr)
throw UsefulException("can't find default font resource");
f32 dpi = getDPI(); f32 dpi = getDPI();
io.FontDefault = resources::ImFont_LoadFromResource(default_font, default_font_size, dpi); io.FontDefault = resources::ImFont_LoadFromResource(font_res, default_font_size, dpi);
} }
void MainWindow::close(){ void MainWindow::close(){

View File

@ -1,45 +1,47 @@
#pragma once #pragma once
#include <SDL.h> #include <SDL.h>
#include <imgui.h> #include <imgui.h>
#include "../common/std.hpp" #include "../common/std.hpp"
#include "../common/time.hpp" #include "../common/time.hpp"
#include "../resources/resources.hpp"
/// converts hex color to float vector #include "../resources/fonts.hpp"
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
/// converts float vector to hex color /// converts hex color to float vector
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)} #define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
/// converts float vector to hex color
namespace ougge::gui { #define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
#define default_font "DroidSans" namespace ougge::gui {
class MainWindow { #define default_font_path "fonts/DroidSans.ttf"
public:
i32 fps_max = 60; class MainWindow {
f32 default_font_size = 14.0f; public:
ImVec4 clear_color = RGBAHexToF(35,35,50,255); i32 fps_max = 60;
SDL_Window* sdl_window = nullptr; f32 default_font_size = 14.0f;
SDL_Renderer* sdl_renderer = nullptr; ImVec4 clear_color = RGBAHexToF(35,35,50,255);
SDL_Window* sdl_window = nullptr;
private: SDL_Renderer* sdl_renderer = nullptr;
bool show_debug_window = true;
bool show_demo_window = false; private:
bool show_metrics_window = false; bool show_debug_window = true;
bool show_demo_window = false;
public: bool show_metrics_window = false;
void open(const std::string& window_title);
void close(); public:
void open(const std::string& window_title, resources::ResourceManager& resourceManager);
/// process io events happened since previous frame void close();
void pollEvents(bool* loopRunning);
void beginFrame(); /// process io events happened since previous frame
void endFrame(); void pollEvents(bool* loopRunning);
void beginFrame();
f32 getDPI(); void endFrame();
private:
void draw_debug_window(); f32 getDPI();
void draw_bg_window(); private:
}; void draw_debug_window();
void draw_bg_window();
} };
}

View File

@ -1,63 +1,65 @@
#define SDL_MAIN_HANDLED #define SDL_MAIN_HANDLED
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include "common/UsefulException.hpp" #include "common/UsefulException.hpp"
#include "common/ougge_format.hpp" #include "common/ougge_format.hpp"
#include "Engine.hpp" #include "Engine.hpp"
#include "gui/gui.hpp" #include "gui/gui.hpp"
using namespace ougge; using namespace ougge;
void drawTutel(Engine& engine){ void drawTutel(Engine& engine){
resources::Texture& tutel = engine.textures.getOrCreate("tutel.png", engine.mainWindow.sdl_renderer); resources::Texture* tutel = engine.textures.tryGetOrCreate("tutel.png", engine.mainWindow.sdl_renderer);
resources::SDL_RenderCopyExF_Params params; if(tutel == nullptr){
params.target_section = SDL_FRectConstruct(100, 100, 400, 400); throw new UsefulException("couldn't find resource 'tutel.png'");
static i32 si = 1; }
params.rotation_angle = M_PI_4 * (si++ / engine.mainWindow.fps_max); resources::SDL_RenderCopyExF_Params params;
tutel.render(params); params.target_section = SDL_FRectConstruct(100, 100, 400, 400);
} static i32 si = 1;
params.rotation_angle = M_PI_4 * (si++ / engine.mainWindow.fps_max);
int main(int argc, const char** argv){ tutel->render(params);
try { }
resources::init();
std::cout<<"initialized resource loader"<<std::endl; int main(int argc, const char** argv){
try {
Engine engine; std::cout<<"initialized resource loader"<<std::endl;
std::cout<<"initialized mono jit runtime"<<std::endl;
engine.init(); Engine engine;
std::cout<<"initialized game engine"<<std::endl; std::cout<<"initialized mono jit runtime"<<std::endl;
engine.init();
game::GameObject& exampleObj = engine.createGameObject(); std::cout<<"initialized game engine"<<std::endl;
std::string componentClassName = "Ougge.ExampleComponent";
if(!engine.tryCreateComponent(exampleObj, componentClassName)) game::GameObject& exampleObj = engine.createGameObject();
throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str())); std::string componentClassName = "Ougge.ExampleComponent";
if(!engine.tryCreateComponent(exampleObj, componentClassName))
std::cout<<"created ExampleObject"<<std::endl; throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str()));
engine.updateCallback = [&engine](f64 deltaTime) -> void { std::cout<<"created ExampleObject"<<std::endl;
drawTutel(engine);
}; engine.updateCallback = [&engine](f64 deltaTime) -> void {
drawTutel(engine);
engine.openMainWindow("ougge"); };
std::cout<<"created sdl window"<<std::endl;
engine.startLoop(); engine.openMainWindow("ougge");
std::cout<<"sdl window has been cosed"<<std::endl; std::cout<<"created sdl window"<<std::endl;
} engine.startLoop();
catch(const std::exception& e){ std::cout<<"sdl window has been cosed"<<std::endl;
std::cerr<<"Catched exception: "<<e.what()<<std::endl; }
return -1; catch(const std::exception& e){
} std::cerr<<"Catched exception: "<<e.what()<<std::endl;
catch(const char* cstr){ return -1;
std::cerr<<"Catched error message (const char*): "<<cstr<<std::endl; }
return -1; catch(const char* cstr){
} std::cerr<<"Catched error message (const char*): "<<cstr<<std::endl;
catch(const std::string& str){ return -1;
std::cerr<<"Catched error message (std::string): "<<str<<std::endl; }
return -1; catch(const std::string& str){
} std::cerr<<"Catched error message (std::string): "<<str<<std::endl;
catch(...){ return -1;
std::cerr<<"Catched unknown error"<<std::endl; }
return -1; catch(...){
} std::cerr<<"Catched unknown error"<<std::endl;
return 0; return -1;
} }
return 0;
}

View File

@ -0,0 +1,40 @@
#include "MemoryStream.hpp"
class MemoryStreamBuf : public std::streambuf {
public:
MemoryStreamBuf(void* p, const std::size_t n);
virtual std::istream::pos_type seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which);
};
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
char* p=(char*)_p;
setg(p, p, p + n);
setp(p, p + n);
}
std::istream::pos_type MemoryStreamBuf::seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which)
{
if (dir == std::ios_base::cur)
gbump(off);
else if (dir == std::ios_base::end)
setg(eback(), egptr() + off, egptr());
else if (dir == std::ios_base::beg)
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
: std::istream(new MemoryStreamBuf((void*)p, n))
{}
MemoryStreamRead::~MemoryStreamRead(){
delete rdbuf();
}

View File

@ -0,0 +1,8 @@
#include <iostream>
class MemoryStreamRead : public std::istream {
public:
MemoryStreamRead(const void* p, const std::size_t n);
virtual ~MemoryStreamRead();
};

View File

@ -1,7 +1,4 @@
#include <imgui.h> #include "fonts.hpp"
#include "resources.hpp"
#include <cstdio>
#include <cstring>
namespace ougge::resources { namespace ougge::resources {
@ -16,17 +13,16 @@ ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi
return io.Fonts->AddFontFromFileTTF(file_path.c_str(), font_size, nullptr, glyph_ranges); return io.Fonts->AddFontFromFileTTF(file_path.c_str(), font_size, nullptr, glyph_ranges);
} }
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi){ ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi){
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
font_size *= dpi; font_size *= dpi;
ImFontConfig font_cfg = ImFontConfig(); ImFontConfig font_cfg = ImFontConfig();
std::sprintf(font_cfg.Name, "%s %ipx", font_name.c_str(), (i32)font_size); std::sprintf(font_cfg.Name, "%s %ipx", res->path.c_str(), (i32)font_size);
auto& res = getResource("fonts/" + font_name + ".ttf"); char* font_data = new char[res->size];
char* font_data = new char[res.size]; res->openStream()->read(font_data, res->size);
res.openStream()->read(font_data, res.size);
return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res.size, return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res->size,
font_size, &font_cfg, glyph_ranges); font_size, &font_cfg, glyph_ranges);
} }

View File

@ -1,12 +1,13 @@
#pragma once #pragma once
#include "imgui.h" #include <imgui.h>
#include "../common/std.hpp" #include "../common/std.hpp"
#include "resources.hpp"
namespace ougge::resources { namespace ougge::resources {
ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi); ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi);
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi); ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi);
} }

View File

@ -4,45 +4,22 @@
#include "../common/ougge_format.hpp" #include "../common/ougge_format.hpp"
#include "resources.hpp" #include "resources.hpp"
#include "embedded_resources.h" #include "embedded_resources.h"
#include "MemoryStream.hpp"
namespace ougge::resources { namespace ougge::resources {
Resource::Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func) ResourceFactory::ResourceFactory(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func)
: path(path), size(size), openStream(open_read_steam_func) : path(path), size(size), openStream(open_read_steam_func)
{} {}
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
char* p=(char*)_p;
setg(p, p, p + n);
setp(p, p + n);
}
std::istream::pos_type MemoryStreamBuf::seekoff( std::shared_ptr<ResourceMap> ResourceManager::_embeddedResourcesMap;
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which)
{
if (dir == std::ios_base::cur)
gbump(off);
else if (dir == std::ios_base::end)
setg(eback(), egptr() + off, egptr());
else if (dir == std::ios_base::beg)
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n) void ResourceManager::loadEmbeddedResources(){
: std::istream(new MemoryStreamBuf((void*)p, n)) if(_embeddedResourcesMap != nullptr)
{} return;
MemoryStreamRead::~MemoryStreamRead(){ _embeddedResourcesMap = std::make_shared<ResourceMap>();
delete rdbuf();
}
static std::unordered_map<std::string, Resource>* _resourceMap = nullptr;
void loadEmbeddedresources(){
for(int i = 0; i < EmbeddedResource_table_count; i++){ for(int i = 0; i < EmbeddedResource_table_count; i++){
const EmbeddedResource& e = EmbeddedResource_table[i]; const EmbeddedResource& e = EmbeddedResource_table[i];
std::cout <<"loading resource '" << e.path << "' " std::cout <<"loading resource '" << e.path << "' "
@ -52,43 +29,36 @@ void loadEmbeddedresources(){
return std::make_unique<MemoryStreamRead>(e.data, e.size); return std::make_unique<MemoryStreamRead>(e.data, e.size);
}; };
auto r = _resourceMap->emplace(e.path, auto r = _embeddedResourcesMap->emplace(e.path,
Resource(e.path, e.size, embedded_resource_factory)); ResourceFactory(e.path, e.size, embedded_resource_factory));
if(!r.second) if(!r.second)
throw UsefulException(ougge_format("can't load duplicate resource '%s'", e.path)); throw UsefulException(ougge_format("can't load duplicate resource '%s'", e.path));
} }
}
void init(){
if(_resourceMap != nullptr)
throw UsefulException("resource has been initialized already");
_resourceMap = new std::unordered_map<std::string, Resource>();
loadEmbeddedresources();
}
Resource& getResource(const std::string& path){
auto it = _resourceMap->find(path);
if(it == _resourceMap->end())
throw UsefulException(ougge_format("can't find resource '%s'", path.c_str()));
return it->second;
}
std::string formatSizeHumanReadable(std::size_t b){
std::stringstream ss;
ss.precision(3);
std::size_t k = b / 1024;
std::size_t m = k / 1024;
std::size_t g = m / 1024;
if(g) _resourceMaps.push_back(_embeddedResourcesMap);
ss<<m / 1024.0f<<'G'; }
else if(m)
ss<<k / 1024.0f<<'M';
else if(k)
ss<<b / 1024.0f<<'K';
else ss<<b;
return ss.str(); ResourceManager::ResourceManager(){
loadEmbeddedResources();
}
ResourceFactory* ResourceManager::tryGetResource(const std::string& path){
// reverse iteration of linked list
auto map_list_iterator = _resourceMaps.end();
while(map_list_iterator != _resourceMaps.begin()){
--map_list_iterator;
auto map = *map_list_iterator;
auto resource_iterator = map->find(path);
// resource not found
if(resource_iterator == map->end())
return nullptr;
return &resource_iterator->second;
}
return nullptr;
} }
} }

View File

@ -4,60 +4,71 @@
#include <iostream> #include <iostream>
#include <functional> #include <functional>
#include <unordered_map> #include <unordered_map>
#include <memory>
#include <list>
namespace ougge::resources { namespace ougge::resources {
// call this in main() class ResourceFactory {
void init();
std::string formatSizeHumanReadable(std::size_t byte_n);
class Resource {
public: public:
const std::string path; const std::string path;
const std::size_t size; const std::size_t size;
using StreamFactoryMethod = std::function< std::unique_ptr<std::istream> () >; using StreamFactoryMethod = std::function< std::unique_ptr<std::istream> () >;
Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func); ResourceFactory(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func);
const StreamFactoryMethod openStream; const StreamFactoryMethod openStream;
}; };
class MemoryStreamBuf : public std::streambuf { using ResourceMap = std::unordered_map<std::string, ResourceFactory>;
class ResourceManager {
std::list<std::shared_ptr<ResourceMap>> _resourceMaps;
static std::shared_ptr<ResourceMap> _embeddedResourcesMap;
void loadEmbeddedResources();
public: public:
MemoryStreamBuf(void* p, const std::size_t n); ResourceManager();
virtual std::istream::pos_type seekoff( void addResourceMap(std::shared_ptr<ResourceMap> m);
std::istream::off_type off,
std::ios_base::seekdir dir, std::shared_ptr<ResourceMap> loadResouceMap();
std::ios_base::openmode which); void removeResourceMap();
ResourceFactory* tryGetResource(const std::string& path);
}; };
class MemoryStreamRead : public std::istream {
public:
MemoryStreamRead(const void* p, const std::size_t n);
virtual ~MemoryStreamRead();
};
Resource& getResource(const std::string& path);
/// @brief stores requested resources in memory /// @brief stores requested resources in memory
/// @tparam T must implement constructor `T(const Resource&, ...)` /// @tparam T must implement constructor `T(ResourceFactory*, ...)`
template<class T> template<class T>
class CacheStorage { class CacheStorage {
std::unordered_map<std::string, T> _map; std::unordered_map<std::string, T> _map;
ResourceManager* _resourceManager;
public: public:
CacheStorage(ResourceManager*);
CacheStorage(CacheStorage&&) = delete;
CacheStorage(const CacheStorage&) = delete;
template<typename... TCtorArgs> template<typename... TCtorArgs>
T& getOrCreate(const std::string& name, TCtorArgs&&... ctor_args){ T* tryGetOrCreate(const std::string& name, TCtorArgs&&... ctor_args){
auto it = _map.find(name); auto it = _map.find(name);
if(it != _map.end()) if(it != _map.end())
return it->second; return &it->second;
auto& res = getResource(name);
ResourceFactory* res = _resourceManager->tryGetResource(name);
if(res == nullptr)
return nullptr;
auto e = _map.emplace(name, T(res, ctor_args...)); auto e = _map.emplace(name, T(res, ctor_args...));
return e.first->second; return &e.first->second;
} }
}; };
template <class T> inline CacheStorage<T>::CacheStorage(ResourceManager* resourceManager)
: _resourceManager(resourceManager)
{}
} }

View File

@ -4,8 +4,8 @@
namespace ougge::resources { namespace ougge::resources {
Texture::Texture(const Resource& r, SDL_Renderer* renderer) Texture::Texture(ResourceFactory* r, SDL_Renderer* renderer)
: Texture(*r.openStream(), r.size, renderer) : Texture(*r->openStream(), r->size, renderer)
{} {}
Texture::Texture(std::istream& s, size_t size, SDL_Renderer* renderer) Texture::Texture(std::istream& s, size_t size, SDL_Renderer* renderer)

View File

@ -33,7 +33,7 @@ struct Texture {
i32 w; i32 w;
i32 h; i32 h;
Texture(const Resource& r, SDL_Renderer* renderer); Texture(ResourceFactory* r, SDL_Renderer* renderer);
Texture(std::istream& s, size_t size, SDL_Renderer* renderer); Texture(std::istream& s, size_t size, SDL_Renderer* renderer);
void render(const SDL_FRect& target_section); void render(const SDL_FRect& target_section);