diff --git a/src/Engine.cpp b/src/Engine.cpp index 322287b..81ef37e 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -7,19 +7,14 @@ namespace ougge { -EngineModule::EngineModule(Engine& engine, const std::string& name) - : engine(engine), name(name) +IEngineModule::IEngineModule(Engine& engine) + : engine(engine) {} -void EngineModule::beginFrame() {} -void EngineModule::endFrame() {} +void IEngineModule::beginFrame() {} +void IEngineModule::endFrame() {} - -void Engine::addModule(EngineModule* m){ - modules.push_back(m); -} - void Engine::startLoop() { if(loop_running) @@ -50,10 +45,10 @@ void Engine::stopLoop(){ loop_running = false; } -void Engine::handleModuleError(EngineModule* module, const char* type, const char* method, const char* error){ +void Engine::handleModuleError(IEngineModule& module, const char* type, const char* method, const char* error){ std::string error_message = ougge_format( "Catched %s at %s.%s(): %s", - type, module->name.c_str(), method, error); + type, module.getName(), method, error); std::cerr<beginFrame(); + module.beginFrame(); } catch(const std::exception& e){ handleModuleError(module, "exception", "beginFrame", e.what()); @@ -81,17 +76,13 @@ void Engine::tryDrawFrame(){ } } - //TODO: frame expeption display - // if(draw_error_window) - // gui::drawErrorWindow(error_message, &draw_error_window); - it = modules.end(); while(it != modules.begin()) { it--; - EngineModule* module = *it; + IEngineModule& module = **it; try { - module->endFrame(); + module.endFrame(); } catch(const std::exception& e){ handleModuleError(module, "exception", "endFrame", e.what()); diff --git a/src/Engine.hpp b/src/Engine.hpp index ac1f07c..9be9d60 100644 --- a/src/Engine.hpp +++ b/src/Engine.hpp @@ -4,32 +4,36 @@ #include "common/std.hpp" #include "common/UsefulException.hpp" #include "common/ougge_format.hpp" +#include "common/type_name_demangled.hpp" +#include +#include +#include namespace ougge { class Engine; -class EngineModule { +class IEngineModule { public: - EngineModule() = delete; - EngineModule(const EngineModule&) = delete; - EngineModule& operator=(const EngineModule&) = delete; - EngineModule(EngineModule&&) = delete; - EngineModule& operator=(EngineModule&&) = delete; + IEngineModule() = delete; + IEngineModule(const IEngineModule&) = delete; + IEngineModule& operator=(const IEngineModule&) = delete; + IEngineModule(IEngineModule&&) = delete; + IEngineModule& operator=(IEngineModule&&) = delete; Engine& engine; - const std::string name; + virtual const std::string& getName() = 0; virtual void beginFrame(); virtual void endFrame(); protected: - EngineModule(Engine& engine, const std::string& name); + IEngineModule(Engine& engine); }; class Engine { - std::vector modules; + std::vector> modules; bool loop_running = false; public: @@ -43,14 +47,60 @@ public: Engine(Engine&&) = delete; Engine& operator=(Engine&&) = delete; - void addModule(EngineModule* m); - // start game loop on the current thread void startLoop(); void stopLoop(); + //TODO: add std::enable_if + template + ModuleT& createModule(ConstructorArgsT&&... args){ + static_assert(std::is_base_of::value); + + auto& module_type_name = ougge_type_name(); + //TODO: replace with some logger call + std::cout<<"Initializing module '"<(&module_index, &module_exists); + + if(module_exists){ + throw UsefulException(ougge_format("can't create second instance of module '%s'", + module_type_name.c_str())); + } + + //TODO: std::forward(args)... + modules.push_back(std::make_unique(*this, args...)); + return *static_cast(modules[module_index].get()); + } + + //TODO: add std::enable_if + template + ModuleT& getModule(){ + static_assert(std::is_base_of::value); + + size_t module_index; + bool module_exists; + getOrCreateModuleIndex(&module_index, &module_exists); + if(!module_exists){ + auto& module_type_name = ougge_type_name(); + throw UsefulException(ougge_format("engine has no module '%s'", + module_type_name.c_str())); + } + return *static_cast(modules[module_index].get()); + } + private: void tryDrawFrame(); - void handleModuleError(EngineModule *module, const char *type, const char *method, const char *error); + void handleModuleError(IEngineModule& module, const char *type, const char *method, const char *error); + + //TODO: add std::enable_if + template + void getOrCreateModuleIndex(size_t* out_index, bool* out_module_exists){ + static size_t module_index = modules.size(); + *out_index = module_index; + // if module_index == modules.size(), then the module hasn't been pushed to the vector yet + *out_module_exists = module_index != modules.size(); + } }; } diff --git a/src/common/UsefulException.hpp b/src/common/UsefulException.hpp index d925ae7..2deab2e 100644 --- a/src/common/UsefulException.hpp +++ b/src/common/UsefulException.hpp @@ -15,7 +15,7 @@ class UsefulException_ : public std::exception { public: UsefulException_(const std::string& msg, const std::string& _file, const std::string& _func, int line_n); - virtual char const* what() const noexcept; + char const* what() const noexcept override; }; #define useful_assert(EXPR, ERRMSG) if(!(EXPR)) throw UsefulException(ERRMSG); diff --git a/src/common/function_shared_ptr.hpp b/src/common/function_shared_ptr.hpp index ffd7159..f4863ac 100644 --- a/src/common/function_shared_ptr.hpp +++ b/src/common/function_shared_ptr.hpp @@ -35,6 +35,7 @@ public: std::enable_if_t::value, RT> operator()(ArgTypes... args){ if(func_ptr == nullptr) throw UsefulException("function_shared_ptr is null"); + //TODO: think about std::forward(args)... return func_ptr->operator()(args...); } diff --git a/src/common/std.hpp b/src/common/std.hpp index bf7acb5..9ee74c2 100644 --- a/src/common/std.hpp +++ b/src/common/std.hpp @@ -17,7 +17,6 @@ typedef double f64; /// anonymous pointer without specified freeMembers() func typedef void* Pointer; -#define nameof(V) #V #ifdef _MSC_VER #pragma comment(lib, "mincore_downlevel.lib") // Support OS older than SDK diff --git a/src/common/type_name_demangled.hpp b/src/common/type_name_demangled.hpp new file mode 100644 index 0000000..31ebab9 --- /dev/null +++ b/src/common/type_name_demangled.hpp @@ -0,0 +1,44 @@ +// https://stackoverflow.com/a/53865723 + +#pragma once +#ifndef _MSC_VER + #include +#endif +#include +#include +#include + +template +std::string _ougge_type_name_demangled() +{ + typedef typename std::remove_reference::type TR; + const char* type_name_mangled = typeid(TR).name(); + std::unique_ptr own + ( +#ifndef _MSC_VER + abi::__cxa_demangle(type_name_mangled, nullptr, nullptr, nullptr), +#else + nullptr, +#endif + std::free + ); + std::string r = own ? own.get() : type_name_mangled; + + if (std::is_const::value) + r += " const"; + if (std::is_volatile::value) + r += " volatile"; + if (std::is_lvalue_reference::value) + r += "&"; + else if (std::is_rvalue_reference::value) + r += "&&"; + + return r; +} + +/// @return human-readable type name +template +const std::string& ougge_type_name(){ + static std::string name = _ougge_type_name_demangled(); + return name; +} diff --git a/src/main.cpp b/src/main.cpp index f2e6ab8..091d9ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,18 +8,22 @@ using namespace ougge; -class TutelModule : public EngineModule { +class TutelModule : public IEngineModule { resources::CacheStorage textures; - modules::MainWindowSDL2& mainWindow; public: - TutelModule(Engine& engine, resources::ResourceManager& resourceManager, modules::MainWindowSDL2& mainWindow) : - EngineModule(engine, nameof(TutelModule)), - textures(&resourceManager), - mainWindow(mainWindow) + TutelModule(Engine& engine, resources::ResourceManager& resourceManager) : + IEngineModule(engine), + textures(&resourceManager) { + //TODO: add something like `assert(requireModule(MainWindow))` } - virtual void beginFrame(){ + const std::string& getName() override { + return ougge_type_name(); + } + + void beginFrame() override { + auto& mainWindow = engine.getModule(); resources::Texture* tutel = textures.tryGetOrCreate("tutel.png", mainWindow.sdl_renderer); if(tutel == nullptr){ throw new UsefulException("couldn't find resource 'tutel.png'"); @@ -33,31 +37,27 @@ public: }; +void createExampleObject(Engine& engine){ + std::cout<<"creating ExampleObject"<(); + game::GameObject& exampleObj = monoSystem.createGameObject(); + std::string componentClassName = "Ougge.ExampleComponent"; + if(!monoSystem.tryCreateComponent(exampleObj, componentClassName)) + throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str())); +} + int main(int argc, const char** argv){ try { - std::cout<<"initializing ResourceManager"; + std::cout<<"Initializing Engine"<("ougge", resourceManager); + engine.createModule(64*1024); + createExampleObject(engine); + engine.createModule(resourceManager); std::cout<<"main loop start"<(); +} + f32 MainWindowSDL2::getDPI(){ i32 w=0, h=0; SDL_GetRendererOutputSize(sdl_renderer, &w, &h); @@ -24,7 +28,7 @@ f32 MainWindowSDL2::getDPI(){ MainWindowSDL2::MainWindowSDL2(Engine& engine, const std::string& window_title, resources::ResourceManager& resourceManager) - : EngineModule(engine, nameof(MainWindowSDL2)) + : IEngineModule(engine) { SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING)); SDL_version v; diff --git a/src/modules/MainWindowSDL2.hpp b/src/modules/MainWindowSDL2.hpp index 7de172a..6bce842 100644 --- a/src/modules/MainWindowSDL2.hpp +++ b/src/modules/MainWindowSDL2.hpp @@ -17,7 +17,7 @@ namespace ougge::modules { #define default_font_path "fonts/DroidSans.ttf" -class MainWindowSDL2 : public EngineModule { +class MainWindowSDL2 : public IEngineModule { public: f32 default_font_size = 14.0f; ImVec4 clear_color = RGBAHexToF(35,35,50,255); @@ -34,8 +34,9 @@ public: resources::ResourceManager& resourceManager); ~MainWindowSDL2(); - virtual void beginFrame(); - virtual void endFrame(); + const std::string& getName() override; + void beginFrame() override; + void endFrame() override; f32 getDPI(); private: diff --git a/src/modules/MonoGameObjectSystem.cpp b/src/modules/MonoGameObjectSystem.cpp index abfe4e9..2f8e21e 100644 --- a/src/modules/MonoGameObjectSystem.cpp +++ b/src/modules/MonoGameObjectSystem.cpp @@ -2,8 +2,12 @@ namespace ougge::modules { +const std::string& MonoGameObjectSystem::getName() { + return ougge_type_name(); +} + MonoGameObjectSystem::MonoGameObjectSystem(Engine& engine, u32 max_game_objects) : - EngineModule(engine, nameof(MonoGameObjectSystem)), + IEngineModule(engine), gameObjectPool(max_game_objects) { engineManagedAssembly = mono.loadAssembly("Ougge.dll"); diff --git a/src/modules/MonoGameObjectSystem.hpp b/src/modules/MonoGameObjectSystem.hpp index 6f7b82f..2257adb 100644 --- a/src/modules/MonoGameObjectSystem.hpp +++ b/src/modules/MonoGameObjectSystem.hpp @@ -7,7 +7,7 @@ namespace ougge::modules { -class MonoGameObjectSystem : public EngineModule { +class MonoGameObjectSystem : public IEngineModule { Mono::RuntimeJIT mono; game::GameObjectPool gameObjectPool; u64 obj_id = 0; @@ -21,7 +21,8 @@ public: MonoGameObjectSystem(Engine& engine, u32 max_game_objects); - virtual void beginFrame(); + const std::string& getName() override; + void beginFrame() override; game::GameObject& createGameObject(); bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName); diff --git a/src/resources/MemorySteam.cpp b/src/resources/MemorySteam.cpp index fea56e5..6f10ad0 100644 --- a/src/resources/MemorySteam.cpp +++ b/src/resources/MemorySteam.cpp @@ -4,10 +4,10 @@ class MemoryStreamBuf : public std::streambuf { public: MemoryStreamBuf(void* p, const std::size_t n); - virtual std::istream::pos_type seekoff( + std::istream::pos_type seekoff( std::istream::off_type off, std::ios_base::seekdir dir, - std::ios_base::openmode which); + std::ios_base::openmode which) override; }; MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){ diff --git a/src/resources/resources.hpp b/src/resources/resources.hpp index 2e6d8e6..e3beb21 100644 --- a/src/resources/resources.hpp +++ b/src/resources/resources.hpp @@ -23,6 +23,7 @@ public: using ResourceMap = std::unordered_map; +//TODO: rewrite ResourceManager as a module class ResourceManager { std::list> _resourceMaps; static std::shared_ptr _embeddedResourcesMap;