ougge/src/Engine.hpp

107 lines
3.3 KiB
C++

#pragma once
#include <vector>
#include "common/std.hpp"
#include "common/UsefulException.hpp"
#include "common/ougge_format.hpp"
#include "common/type_name_demangled.hpp"
#include <type_traits>
#include <memory>
#include <iostream>
namespace ougge {
class Engine;
class IEngineModule {
public:
IEngineModule() = delete;
IEngineModule(const IEngineModule&) = delete;
IEngineModule& operator=(const IEngineModule&) = delete;
IEngineModule(IEngineModule&&) = delete;
IEngineModule& operator=(IEngineModule&&) = delete;
Engine& engine;
virtual const std::string& getName() = 0;
virtual void beginFrame();
virtual void endFrame();
protected:
IEngineModule(Engine& engine);
};
class Engine {
std::vector<std::unique_ptr<IEngineModule>> modules;
bool loop_running = false;
public:
u32 fps_max = 60;
f64 deltaTime;
std::vector<std::string> error_messages;
Engine() = default;
Engine(const Engine&) = delete;
Engine& operator=(const Engine&) = delete;
Engine(Engine&&) = delete;
Engine& operator=(Engine&&) = delete;
// start game loop on the current thread
void startLoop();
void stopLoop();
//TODO: add std::enable_if
template<typename ModuleT, typename... ConstructorArgsT>
ModuleT& createModule(ConstructorArgsT&&... args){
static_assert(std::is_base_of<IEngineModule, ModuleT>::value);
auto& module_type_name = ougge_type_name<ModuleT>();
//TODO: replace with some logger call
std::cout<<"Initializing module '"<<module_type_name<<"'"<<std::endl;
size_t module_index;
bool module_exists;
getOrCreateModuleIndex<ModuleT>(&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<ModuleT>(*this, args...));
return *static_cast<ModuleT*>(modules[module_index].get());
}
//TODO: add std::enable_if
template<typename ModuleT>
ModuleT& getModule(){
static_assert(std::is_base_of<IEngineModule, ModuleT>::value);
size_t module_index;
bool module_exists;
getOrCreateModuleIndex<ModuleT>(&module_index, &module_exists);
if(!module_exists){
auto& module_type_name = ougge_type_name<ModuleT>();
throw UsefulException(ougge_format("engine has no module '%s'",
module_type_name.c_str()));
}
return *static_cast<ModuleT*>(modules[module_index].get());
}
private:
void tryDrawFrame();
void handleModuleError(IEngineModule& module, const char *type, const char *method, const char *error);
//TODO: add std::enable_if
template<typename ModuleT>
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();
}
};
}