Compare commits
7 Commits
851e1ee122
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e7454278d | |||
| 346779060e | |||
| 175fe61e5c | |||
| f7a8d32865 | |||
| 9a283a2904 | |||
| a288d0961f | |||
| 8fd6cee223 |
2
dependencies/cimgui
vendored
2
dependencies/cimgui
vendored
Submodule dependencies/cimgui updated: 5ba6ea3fc0...d94ad1b162
@@ -14,6 +14,14 @@ public class ExampleComponent : Component
|
|||||||
Console.WriteLine($"C# deltaTime {deltaTime} object id {Owner.Id}");
|
Console.WriteLine($"C# deltaTime {deltaTime} object id {Owner.Id}");
|
||||||
ImGui.Begin("C# WINDOW");
|
ImGui.Begin("C# WINDOW");
|
||||||
ImGui.Text("Hello from ExampleComponent!");
|
ImGui.Text("Hello from ExampleComponent!");
|
||||||
|
if (ImGui.Button("create GameObject"))
|
||||||
|
{
|
||||||
|
GameObject.Create();
|
||||||
|
}
|
||||||
|
if (ImGui.Button("GC Collect"))
|
||||||
|
{
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,8 +39,9 @@ public class GameObject
|
|||||||
|
|
||||||
static public GameObject Create()
|
static public GameObject Create()
|
||||||
{
|
{
|
||||||
NativeMethods.createGameObject(out ulong id, out uint index);
|
NativeFunctions.createGameObject(out ulong id, out uint index);
|
||||||
var o = new GameObject(id, index);
|
var o = new GameObject(id, index);
|
||||||
|
Console.WriteLine($"C# created object with id {id}, index {index}");
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,23 +50,29 @@ public class GameObject
|
|||||||
if(_isDestroyed)
|
if(_isDestroyed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isDestroyed = NativeMethods.destroyGameObject(_index);
|
_isDestroyed = NativeFunctions.freeGameObject(_index);
|
||||||
if(!_isDestroyed)
|
if(!_isDestroyed)
|
||||||
throw new Exception($"Can't destroy GameObject({_id})");
|
throw new Exception($"Can't destroy GameObject({_id})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~GameObject()
|
||||||
|
{
|
||||||
|
// destroys object native part when managed part is garbage-collected
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
/// <param name="t">type derived from Component</param>
|
/// <param name="t">type derived from Component</param>
|
||||||
/// <returns>true if new component instance was created, false if component of the same tipe is already added to GameObject</returns>
|
/// <returns>true if new component instance was created, false if component of the same tipe is already added to GameObject</returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
public bool TryCreateComponent(Type t)
|
public bool TryCreateComponent(Type t)
|
||||||
{
|
{
|
||||||
if(!t.IsSubclassOf(typeof(Component)))
|
if (!t.IsSubclassOf(typeof(Component)))
|
||||||
throw new Exception($"type {t.FullName} is not a derived class of {typeof(Component).FullName}");
|
throw new Exception($"type {t.FullName} is not a derived class of {typeof(Component).FullName}");
|
||||||
|
|
||||||
if(Components.ContainsKey(t))
|
if (Components.ContainsKey(t))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Component component = (Component?)Activator.CreateInstance(t, this)
|
Component component = (Component?)Activator.CreateInstance(t, this)
|
||||||
?? throw new Exception($"can't create instance of class {t.FullName}");
|
?? throw new Exception($"can't create instance of class {t.FullName}");
|
||||||
Components.Add(t, component);
|
Components.Add(t, component);
|
||||||
return true;
|
return true;
|
||||||
@@ -78,7 +85,9 @@ public class GameObject
|
|||||||
|
|
||||||
private void InvokeUpdate(double deltaTime)
|
private void InvokeUpdate(double deltaTime)
|
||||||
{
|
{
|
||||||
foreach(var p in Components)
|
Console.WriteLine("C# InvokeUpdate");
|
||||||
|
Console.WriteLine($"id {_id}, index {_index}, destroyed {_isDestroyed}");
|
||||||
|
foreach (var p in Components)
|
||||||
{
|
{
|
||||||
p.Value.Update(deltaTime);
|
p.Value.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|||||||
12
src-csharp/NativeFunctions.cs
Normal file
12
src-csharp/NativeFunctions.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Ougge;
|
||||||
|
|
||||||
|
internal static class NativeFunctions
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static void createGameObject(out ulong id, out uint index);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
internal extern static bool freeGameObject(uint index);
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ougge;
|
|
||||||
|
|
||||||
internal static class NativeMethods
|
|
||||||
{
|
|
||||||
[DllImport("__Internal")]
|
|
||||||
internal extern static bool destroyGameObject(uint index);
|
|
||||||
|
|
||||||
[DllImport("__Internal")]
|
|
||||||
internal extern static void createGameObject(out ulong id, out uint index);
|
|
||||||
}
|
|
||||||
146
src/Engine.cpp
146
src/Engine.cpp
@@ -1,26 +1,22 @@
|
|||||||
#include "Engine.hpp"
|
#include "Engine.hpp"
|
||||||
#include "gui/gui.hpp"
|
#include "common/UsefulException.hpp"
|
||||||
|
#include "common/ougge_format.hpp"
|
||||||
|
#include "common/time.hpp"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ougge {
|
namespace ougge {
|
||||||
|
|
||||||
Engine::Engine()
|
IEngineModule::IEngineModule(Engine& engine)
|
||||||
: gameObjectPool(GAMEOBJECTPOOL_SIZE), textures(&resourceManager)
|
: engine(engine)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void IEngineModule::beginFrame() {}
|
||||||
|
void IEngineModule::endFrame() {}
|
||||||
|
|
||||||
|
|
||||||
|
void Engine::startLoop()
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::init(){
|
|
||||||
engineManagedAssembly = mono.loadAssembly("Ougge.dll");
|
|
||||||
gameObjectClass = engineManagedAssembly->getClass("Ougge", "GameObject");
|
|
||||||
gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
|
|
||||||
gameObjectInvokeUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate");
|
|
||||||
gameObjectTryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::openMainWindow(const std::string& window_title){
|
|
||||||
mainWindow.open(window_title, resourceManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::startLoop(){
|
|
||||||
if(loop_running)
|
if(loop_running)
|
||||||
throw UsefulException("loop is running already");
|
throw UsefulException("loop is running already");
|
||||||
|
|
||||||
@@ -28,87 +24,79 @@ void Engine::startLoop(){
|
|||||||
loop_running=true;
|
loop_running=true;
|
||||||
// main loop
|
// main loop
|
||||||
while(loop_running){
|
while(loop_running){
|
||||||
mainWindow.pollEvents(&loop_running);
|
|
||||||
if(!loop_running)
|
|
||||||
break;
|
|
||||||
|
|
||||||
nsec_t update_time_ns = getMonotonicTimeNsec();
|
nsec_t update_time_ns = getMonotonicTimeNsec();
|
||||||
if(update_time_ns < prev_update_time_ns)
|
if(update_time_ns < prev_update_time_ns)
|
||||||
throw UsefulException("monotonic clock returned unexpected value");
|
throw UsefulException("monotonic clock returned unexpected value");
|
||||||
f64 delta_time_s = (f64)(update_time_ns - prev_update_time_ns) / 1e9;
|
f64 delta_time_s = (f64)(update_time_ns - prev_update_time_ns) / 1e9;
|
||||||
prev_update_time_ns = update_time_ns;
|
prev_update_time_ns = update_time_ns;
|
||||||
|
deltaTime = delta_time_s;
|
||||||
tryDrawFrame(delta_time_s);
|
|
||||||
|
tryDrawFrame();
|
||||||
|
|
||||||
nsec_t after_update_time_ns = getMonotonicTimeNsec();
|
nsec_t after_update_time_ns = getMonotonicTimeNsec();
|
||||||
nsec_t frame_delay_ns = (nsec_t)1e9 / mainWindow.fps_max - (after_update_time_ns - update_time_ns);
|
nsec_t frame_delay_ns = (nsec_t)1e9 / fps_max - (after_update_time_ns - update_time_ns);
|
||||||
if(frame_delay_ns > 0){
|
if(frame_delay_ns > 0){
|
||||||
SDL_Delay(frame_delay_ns / 1e6);
|
SDL_Delay(frame_delay_ns / 1e6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::stopLoop(){
|
void Engine::stopLoop(){
|
||||||
loop_running = false;
|
loop_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::tryDrawFrame(f64 deltaTime){
|
void Engine::handleModuleError(IEngineModule& module, const char* type, const char* method, const char* error){
|
||||||
static std::string error_message;
|
std::string error_message = ougge_format(
|
||||||
static bool draw_error_window = false;
|
"Catched %s at %s.%s(): %s",
|
||||||
try {
|
type, module.getName().c_str(), method, error);
|
||||||
mainWindow.beginFrame();
|
std::cerr<<error_message<<std::endl;
|
||||||
|
error_messages.push_back(error_message);
|
||||||
if(draw_error_window)
|
}
|
||||||
gui::drawErrorWindow(error_message, &draw_error_window);
|
|
||||||
else {
|
void Engine::tryDrawFrame(){
|
||||||
updateGameObjects(deltaTime);
|
auto it = modules.begin();
|
||||||
if(!updateCallback.isNull())
|
while(it != modules.end())
|
||||||
updateCallback(deltaTime);
|
{
|
||||||
|
IEngineModule& module = **it;
|
||||||
|
it++;
|
||||||
|
try {
|
||||||
|
module.beginFrame();
|
||||||
|
}
|
||||||
|
catch(const std::exception& e){
|
||||||
|
handleModuleError(module, "exception", "beginFrame", e.what());
|
||||||
|
}
|
||||||
|
catch(const char* cstr){
|
||||||
|
handleModuleError(module, "error message (const char*)", "beginFrame", cstr);
|
||||||
|
}
|
||||||
|
catch(const std::string& str){
|
||||||
|
handleModuleError(module, "error message (std::string)", "beginFrame", str.c_str());
|
||||||
|
}
|
||||||
|
catch(...){
|
||||||
|
handleModuleError(module, "unknown", "beginFrame", "unknown");
|
||||||
}
|
}
|
||||||
mainWindow.endFrame();
|
|
||||||
}
|
}
|
||||||
catch(const std::exception& e){
|
|
||||||
error_message = "Catched exception: " + std::string(e.what());
|
it = modules.end();
|
||||||
draw_error_window = true;
|
while(it != modules.begin())
|
||||||
std::cerr<<error_message<<std::endl;
|
{
|
||||||
}
|
it--;
|
||||||
catch(const char* cstr){
|
IEngineModule& module = **it;
|
||||||
error_message = "Catched error message (const char*): " + std::string(cstr);
|
try {
|
||||||
draw_error_window = true;
|
module.endFrame();
|
||||||
std::cerr<<error_message<<std::endl;
|
}
|
||||||
}
|
catch(const std::exception& e){
|
||||||
catch(const std::string& str){
|
handleModuleError(module, "exception", "endFrame", e.what());
|
||||||
error_message = "Catched error message (std::string): " + str;
|
}
|
||||||
draw_error_window = true;
|
catch(const char* cstr){
|
||||||
std::cerr<<error_message<<std::endl;
|
handleModuleError(module, "error message (const char*)", "endFrame", cstr);
|
||||||
}
|
}
|
||||||
catch(...){
|
catch(const std::string& str){
|
||||||
error_message = "Catched unknown error";
|
handleModuleError(module, "error message (std::string)", "endFrame", str.c_str());
|
||||||
draw_error_window = true;
|
}
|
||||||
std::cerr<<error_message<<std::endl;
|
catch(...){
|
||||||
|
handleModuleError(module, "unknown", "endFrame", "unknown");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Engine::updateGameObjects(f64 deltaTime){
|
|
||||||
for(auto pair : gameObjectPool){
|
|
||||||
gameObjectInvokeUpdate(pair.second.getObjectHandle().getObject(), deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
game::GameObject& Engine::createGameObject(){
|
|
||||||
auto pair = gameObjectPool.emplace(game::GameObject(mono.createObject(gameObjectClass)));
|
|
||||||
game::GameObject& obj = pair.second;
|
|
||||||
gameObjectCtor(obj.getObjectHandle().getObject(), ++obj_id, pair.first);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Engine::tryCreateComponent(game::GameObject& obj, const std::string& componentClassName){
|
|
||||||
Mono::String componentClassNameManaged = mono.createString(componentClassName);
|
|
||||||
Mono::Bool created = gameObjectTryCreateComponent(obj.getObjectHandle().getObject(), componentClassNameManaged);
|
|
||||||
return created.wide_bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
117
src/Engine.hpp
117
src/Engine.hpp
@@ -1,51 +1,106 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/function_shared_ptr.hpp"
|
#include <vector>
|
||||||
#include "mono/mono.hpp"
|
#include "common/std.hpp"
|
||||||
#include "game/GameObjectPool.hpp"
|
#include "common/UsefulException.hpp"
|
||||||
#include "gui/MainWindow.hpp"
|
#include "common/ougge_format.hpp"
|
||||||
#include "resources/textures.hpp"
|
#include "common/type_name_demangled.hpp"
|
||||||
|
#include <type_traits>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ougge {
|
namespace ougge {
|
||||||
|
|
||||||
#define GAMEOBJECTPOOL_SIZE 64*1024
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
using UpdateFunc_t = function_shared_ptr<void(f64)>;
|
|
||||||
|
|
||||||
class Engine {
|
class Engine {
|
||||||
|
std::vector<std::unique_ptr<IEngineModule>> modules;
|
||||||
bool loop_running = false;
|
bool loop_running = false;
|
||||||
|
|
||||||
game::GameObjectPool gameObjectPool;
|
|
||||||
u64 obj_id = 0;
|
|
||||||
MonoClass* gameObjectClass;
|
|
||||||
Mono::Method<void(u64, u32)> gameObjectCtor;
|
|
||||||
Mono::Method<void(f64)> gameObjectInvokeUpdate;
|
|
||||||
Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
gui::MainWindow mainWindow;
|
u32 fps_max = 60;
|
||||||
UpdateFunc_t updateCallback;
|
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;
|
||||||
|
|
||||||
Mono::RuntimeJIT mono;
|
|
||||||
std::shared_ptr<Mono::Assembly> engineManagedAssembly;
|
|
||||||
|
|
||||||
resources::ResourceManager resourceManager;
|
|
||||||
resources::CacheStorage<resources::Texture> textures;
|
|
||||||
|
|
||||||
Engine();
|
|
||||||
void init();
|
|
||||||
void openMainWindow(const std::string& window_title);
|
|
||||||
// start game loop on the current thread
|
// start game loop on the current thread
|
||||||
void startLoop();
|
void startLoop();
|
||||||
void stopLoop();
|
void stopLoop();
|
||||||
|
|
||||||
game::GameObject& createGameObject();
|
//TODO: add std::enable_if
|
||||||
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName);
|
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:
|
private:
|
||||||
void tryDrawFrame(f64 deltaTime);
|
void tryDrawFrame();
|
||||||
void updateGameObjects(f64 deltaTime);
|
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();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class UsefulException_ : public std::exception {
|
|||||||
public:
|
public:
|
||||||
UsefulException_(const std::string& msg, const std::string& _file, const std::string& _func, int line_n);
|
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);
|
#define useful_assert(EXPR, ERRMSG) if(!(EXPR)) throw UsefulException(ERRMSG);
|
||||||
|
|||||||
@@ -30,13 +30,12 @@ public:
|
|||||||
|
|
||||||
bool isNull() const { return func_ptr == nullptr; }
|
bool isNull() const { return func_ptr == nullptr; }
|
||||||
|
|
||||||
//TODO: make inline
|
|
||||||
|
|
||||||
// ReturnT is not void
|
// ReturnT is not void
|
||||||
template<typename RT = ReturnT>
|
template<typename RT = ReturnT>
|
||||||
std::enable_if_t<!std::is_void<RT>::value, RT> operator()(ArgTypes... args){
|
std::enable_if_t<!std::is_void<RT>::value, RT> operator()(ArgTypes... args){
|
||||||
if(func_ptr == nullptr)
|
if(func_ptr == nullptr)
|
||||||
throw UsefulException("function_shared_ptr is null");
|
throw UsefulException("function_shared_ptr is null");
|
||||||
|
//TODO: think about std::forward(args)...
|
||||||
return func_ptr->operator()(args...);
|
return func_ptr->operator()(args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ typedef double f64;
|
|||||||
/// anonymous pointer without specified freeMembers() func
|
/// anonymous pointer without specified freeMembers() func
|
||||||
typedef void* Pointer;
|
typedef void* Pointer;
|
||||||
|
|
||||||
#define nameof(V) #V
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma comment(lib, "mincore_downlevel.lib") // Support OS older than SDK
|
#pragma comment(lib, "mincore_downlevel.lib") // Support OS older than SDK
|
||||||
|
|||||||
44
src/common/type_name_demangled.hpp
Normal file
44
src/common/type_name_demangled.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// https://stackoverflow.com/a/53865723
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#endif
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::string _ougge_type_name_demangled()
|
||||||
|
{
|
||||||
|
typedef typename std::remove_reference<T>::type TR;
|
||||||
|
const char* type_name_mangled = typeid(TR).name();
|
||||||
|
std::unique_ptr<char, void(*)(void*)> 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<TR>::value)
|
||||||
|
r += " const";
|
||||||
|
if (std::is_volatile<TR>::value)
|
||||||
|
r += " volatile";
|
||||||
|
if (std::is_lvalue_reference<T>::value)
|
||||||
|
r += "&";
|
||||||
|
else if (std::is_rvalue_reference<T>::value)
|
||||||
|
r += "&&";
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @return human-readable type name
|
||||||
|
template <class T>
|
||||||
|
const std::string& ougge_type_name(){
|
||||||
|
static std::string name = _ougge_type_name_demangled<T>();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
@@ -94,17 +94,20 @@ std::pair<u32, GameObject&> GameObjectPool::emplace(GameObject&& new_obj)
|
|||||||
return std::pair<u32, GameObject&>(i, r);
|
return std::pair<u32, GameObject&>(i, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObjectPool::erase(u32 index)
|
bool GameObjectPool::erase(u32 index)
|
||||||
{
|
{
|
||||||
if(index >= size)
|
if(index >= size)
|
||||||
throw UsefulException(ougge_format("index %i is out of size %i", index, size));
|
throw UsefulException(ougge_format("index %i is out of size %i", index, size));
|
||||||
if(!isIndexUsed(index))
|
if(!isIndexUsed(index)){
|
||||||
throw UsefulException(ougge_format("there is no object at index %i", index));
|
// throw UsefulException(ougge_format("there is no object at index %i", index));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
buffer[index] = GameObject();
|
buffer[index] = GameObject();
|
||||||
used_indices[index/64] &= ~(u64(1)<<(index%64)); // mark index bit as unused
|
used_indices[index/64] &= ~(u64(1)<<(index%64)); // mark index bit as unused
|
||||||
if(index < first_unused_index)
|
if(index < first_unused_index)
|
||||||
first_unused_index = index;
|
first_unused_index = index;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObjectPool::iterator::iterator(GameObjectPool* pool, u32 index)
|
GameObjectPool::iterator::iterator(GameObjectPool* pool, u32 index)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
~GameObjectPool();
|
~GameObjectPool();
|
||||||
GameObject& get(u32 index);
|
GameObject& get(u32 index);
|
||||||
std::pair<u32, GameObject&> emplace(GameObject&& new_obj);
|
std::pair<u32, GameObject&> emplace(GameObject&& new_obj);
|
||||||
void erase(u32 index);
|
bool erase(u32 index);
|
||||||
|
|
||||||
#pragma region iterator class
|
#pragma region iterator class
|
||||||
class iterator {
|
class iterator {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
#include "gui.hpp"
|
|
||||||
|
|
||||||
namespace ougge::gui {
|
|
||||||
|
|
||||||
void drawErrorWindow(const std::string& msg, bool* draw_error_window){
|
|
||||||
ImGui::Begin("ERROR", draw_error_window);
|
|
||||||
ImGui::Text("%s", msg.c_str());
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <imgui.h>
|
|
||||||
#include "gui_exceptions.hpp"
|
|
||||||
|
|
||||||
namespace ougge::gui {
|
|
||||||
|
|
||||||
void drawErrorWindow(const std::string& msg, bool* draw_error_window);
|
|
||||||
|
|
||||||
}
|
|
||||||
80
src/main.cpp
80
src/main.cpp
@@ -1,49 +1,67 @@
|
|||||||
#define SDL_MAIN_HANDLED
|
#define SDL_MAIN_HANDLED
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include "common/UsefulException.hpp"
|
|
||||||
#include "common/ougge_format.hpp"
|
|
||||||
#include "Engine.hpp"
|
#include "Engine.hpp"
|
||||||
#include "gui/gui.hpp"
|
#include "modules/MainWindowSDL2.hpp"
|
||||||
|
#include "modules/MonoGameObjectSystem.hpp"
|
||||||
|
#include "resources/textures.hpp"
|
||||||
|
|
||||||
using namespace ougge;
|
using namespace ougge;
|
||||||
|
|
||||||
void drawTutel(Engine& engine){
|
class TutelModule : public IEngineModule {
|
||||||
resources::Texture* tutel = engine.textures.tryGetOrCreate("tutel.png", engine.mainWindow.sdl_renderer);
|
resources::CacheStorage<resources::Texture> textures;
|
||||||
if(tutel == nullptr){
|
public:
|
||||||
throw new UsefulException("couldn't find resource 'tutel.png'");
|
TutelModule(Engine& engine, resources::ResourceManager& resourceManager) :
|
||||||
|
IEngineModule(engine),
|
||||||
|
textures(&resourceManager)
|
||||||
|
{
|
||||||
|
//TODO: add something like `assert(requireModule(MainWindow))`
|
||||||
}
|
}
|
||||||
resources::SDL_RenderCopyExF_Params params;
|
|
||||||
params.target_section = SDL_FRectConstruct(100, 100, 400, 400);
|
const std::string& getName() override {
|
||||||
static i32 si = 1;
|
return ougge_type_name<TutelModule>();
|
||||||
params.rotation_angle = M_PI_4 * (si++ / engine.mainWindow.fps_max);
|
}
|
||||||
tutel->render(params);
|
|
||||||
|
void beginFrame() override {
|
||||||
|
auto& mainWindow = engine.getModule<modules::MainWindowSDL2>();
|
||||||
|
resources::Texture* tutel = textures.tryGetOrCreate("tutel.png", mainWindow.sdl_renderer);
|
||||||
|
if(tutel == nullptr){
|
||||||
|
throw new UsefulException("couldn't find resource 'tutel.png'");
|
||||||
|
}
|
||||||
|
resources::SDL_RenderCopyExF_Params params;
|
||||||
|
params.target_section = SDL_FRectConstruct(100, 100, 400, 400);
|
||||||
|
static i32 si = 1;
|
||||||
|
params.rotation_angle = M_PI_4 * (si++ / engine.fps_max);
|
||||||
|
tutel->render(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void createExampleObject(Engine& engine){
|
||||||
|
std::cout<<"creating ExampleObject"<<std::endl;
|
||||||
|
auto& monoSystem = engine.getModule<modules::MonoGameObjectSystem>();
|
||||||
|
game::GameObject& exampleObj = monoSystem.createAndConstructGameObject();
|
||||||
|
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){
|
int main(int argc, const char** argv){
|
||||||
try {
|
try {
|
||||||
std::cout<<"initialized resource loader"<<std::endl;
|
std::cout<<"Initializing Engine"<<std::endl;
|
||||||
|
|
||||||
Engine engine;
|
Engine engine;
|
||||||
std::cout<<"initialized mono jit runtime"<<std::endl;
|
|
||||||
engine.init();
|
std::cout<<"Initializing ResourceManager"<<std::endl;
|
||||||
std::cout<<"initialized game engine"<<std::endl;
|
resources::ResourceManager resourceManager;
|
||||||
|
|
||||||
|
engine.createModule<modules::MainWindowSDL2>("ougge", resourceManager);
|
||||||
|
engine.createModule<modules::MonoGameObjectSystem>(64*1024);
|
||||||
|
createExampleObject(engine);
|
||||||
|
engine.createModule<TutelModule>(resourceManager);
|
||||||
|
|
||||||
game::GameObject& exampleObj = engine.createGameObject();
|
std::cout<<"main loop start"<<std::endl;
|
||||||
std::string componentClassName = "Ougge.ExampleComponent";
|
|
||||||
if(!engine.tryCreateComponent(exampleObj, componentClassName))
|
|
||||||
throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str()));
|
|
||||||
|
|
||||||
std::cout<<"created ExampleObject"<<std::endl;
|
|
||||||
|
|
||||||
engine.updateCallback = [&engine](f64 deltaTime) -> void {
|
|
||||||
drawTutel(engine);
|
|
||||||
};
|
|
||||||
|
|
||||||
engine.openMainWindow("ougge");
|
|
||||||
std::cout<<"created sdl window"<<std::endl;
|
|
||||||
engine.startLoop();
|
engine.startLoop();
|
||||||
std::cout<<"sdl window has been cosed"<<std::endl;
|
std::cout<<"main loop stop"<<std::endl;
|
||||||
}
|
}
|
||||||
catch(const std::exception& e){
|
catch(const std::exception& e){
|
||||||
std::cerr<<"Catched exception: "<<e.what()<<std::endl;
|
std::cerr<<"Catched exception: "<<e.what()<<std::endl;
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
#include <backends/imgui_impl_sdl2.h>
|
#include <backends/imgui_impl_sdl2.h>
|
||||||
#include <backends/imgui_impl_sdlrenderer2.h>
|
#include <backends/imgui_impl_sdlrenderer2.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "MainWindow.hpp"
|
#include "MainWindowSDL2.hpp"
|
||||||
#include "gui_exceptions.hpp"
|
#include "../gui/gui_exceptions.hpp"
|
||||||
#include "../common/ougge_format.hpp"
|
#include "../common/ougge_format.hpp"
|
||||||
#include "../common/math.hpp"
|
#include "../common/math.hpp"
|
||||||
|
|
||||||
namespace ougge::gui {
|
using namespace ougge::gui;
|
||||||
|
|
||||||
f32 MainWindow::getDPI(){
|
namespace ougge::modules {
|
||||||
|
|
||||||
|
const std::string& MainWindowSDL2::getName() {
|
||||||
|
return ougge_type_name<MainWindowSDL2>();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 MainWindowSDL2::getDPI(){
|
||||||
i32 w=0, h=0;
|
i32 w=0, h=0;
|
||||||
SDL_GetRendererOutputSize(sdl_renderer, &w, &h);
|
SDL_GetRendererOutputSize(sdl_renderer, &w, &h);
|
||||||
i32 sim_w=0, sim_h=0;
|
i32 sim_w=0, sim_h=0;
|
||||||
@@ -19,7 +25,11 @@ f32 MainWindow::getDPI(){
|
|||||||
return dpi;
|
return dpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::open(const std::string& window_title, resources::ResourceManager& resourceManager){
|
MainWindowSDL2::MainWindowSDL2(Engine& engine,
|
||||||
|
const std::string& window_title,
|
||||||
|
resources::ResourceManager& resourceManager)
|
||||||
|
: IEngineModule(engine)
|
||||||
|
{
|
||||||
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);
|
||||||
@@ -78,7 +88,7 @@ void MainWindow::open(const std::string& window_title, resources::ResourceManage
|
|||||||
io.FontDefault = resources::ImFont_LoadFromResource(font_res, default_font_size, dpi);
|
io.FontDefault = resources::ImFont_LoadFromResource(font_res, default_font_size, dpi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::close(){
|
MainWindowSDL2::~MainWindowSDL2(){
|
||||||
ImGui_ImplSDLRenderer2_Shutdown();
|
ImGui_ImplSDLRenderer2_Shutdown();
|
||||||
ImGui_ImplSDL2_Shutdown();
|
ImGui_ImplSDL2_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
@@ -87,20 +97,22 @@ void MainWindow::close(){
|
|||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::pollEvents(bool* loopRunning){
|
void MainWindowSDL2::pollEvents(){
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
switch(event.type){
|
switch(event.type){
|
||||||
case SDL_QUIT: {
|
case SDL_QUIT: {
|
||||||
*loopRunning = false;
|
//TODO: log SDL_QUIT event
|
||||||
|
engine.stopLoop();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_WINDOWEVENT: {
|
case SDL_WINDOWEVENT: {
|
||||||
if(event.window.event == SDL_WINDOWEVENT_CLOSE
|
if(event.window.event == SDL_WINDOWEVENT_CLOSE
|
||||||
&& event.window.windowID == SDL_GetWindowID(sdl_window))
|
&& event.window.windowID == SDL_GetWindowID(sdl_window))
|
||||||
{
|
{
|
||||||
*loopRunning = false;
|
//TODO: log SDL_WINDOWEVENT event
|
||||||
|
engine.stopLoop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -108,8 +120,10 @@ void MainWindow::pollEvents(bool* loopRunning){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindowSDL2::beginFrame(){
|
||||||
|
// process events happend since previous frame
|
||||||
|
pollEvents();
|
||||||
|
|
||||||
void MainWindow::beginFrame(){
|
|
||||||
// Start the Dear ImGui frame
|
// Start the Dear ImGui frame
|
||||||
ImGui_ImplSDLRenderer2_NewFrame();
|
ImGui_ImplSDLRenderer2_NewFrame();
|
||||||
ImGui_ImplSDL2_NewFrame();
|
ImGui_ImplSDL2_NewFrame();
|
||||||
@@ -126,16 +140,17 @@ void MainWindow::beginFrame(){
|
|||||||
|
|
||||||
draw_bg_window();
|
draw_bg_window();
|
||||||
draw_debug_window();
|
draw_debug_window();
|
||||||
|
drawErrorWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::endFrame(){
|
void MainWindowSDL2::endFrame(){
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), sdl_renderer);
|
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), sdl_renderer);
|
||||||
// Swap buffers
|
// Swap buffers
|
||||||
SDL_RenderPresent(sdl_renderer);
|
SDL_RenderPresent(sdl_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::draw_bg_window(){
|
void MainWindowSDL2::draw_bg_window(){
|
||||||
const ImGuiDockNodeFlags dockspace_flags =
|
const ImGuiDockNodeFlags dockspace_flags =
|
||||||
ImGuiDockNodeFlags_PassthruCentralNode;
|
ImGuiDockNodeFlags_PassthruCentralNode;
|
||||||
const ImGuiWindowFlags window_flags =
|
const ImGuiWindowFlags window_flags =
|
||||||
@@ -199,11 +214,11 @@ void MainWindow::draw_bg_window(){
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::draw_debug_window(){
|
void MainWindowSDL2::draw_debug_window(){
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
if(ImGui::Begin("Debug Options", &show_debug_window)){
|
if(ImGui::Begin("Debug Options", &show_debug_window)){
|
||||||
ImGui::ColorEdit3("clear_color", (float*)&clear_color);
|
ImGui::ColorEdit3("clear_color", (float*)&clear_color);
|
||||||
ImGui::InputInt("fps_max", &fps_max);
|
ImGui::InputInt("fps_max", (int*)&engine.fps_max);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.2f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
ImGui::Text("Application average %.3f ms/frame (%.2f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||||
ImGui::Checkbox("Demo Window", &show_demo_window);
|
ImGui::Checkbox("Demo Window", &show_demo_window);
|
||||||
ImGui::Checkbox("Metrics/Debug Window", &show_metrics_window);
|
ImGui::Checkbox("Metrics/Debug Window", &show_metrics_window);
|
||||||
@@ -217,4 +232,16 @@ void MainWindow::draw_debug_window(){
|
|||||||
ImGui::ShowMetricsWindow(&show_metrics_window);
|
ImGui::ShowMetricsWindow(&show_metrics_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindowSDL2::drawErrorWindow(){
|
||||||
|
if(engine.error_messages.size() < 1)
|
||||||
|
return;
|
||||||
|
ImGui::Begin("ERRORS");
|
||||||
|
if(ImGui::Button("Clear"))
|
||||||
|
engine.error_messages.clear();
|
||||||
|
for(auto& msg : engine.error_messages){
|
||||||
|
ImGui::TextWrapped("%s", msg.c_str());
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,23 +2,23 @@
|
|||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
#include <vector>
|
||||||
#include "../common/std.hpp"
|
#include "../common/std.hpp"
|
||||||
#include "../common/time.hpp"
|
|
||||||
#include "../resources/resources.hpp"
|
#include "../resources/resources.hpp"
|
||||||
#include "../resources/fonts.hpp"
|
#include "../resources/fonts.hpp"
|
||||||
|
#include "../Engine.hpp"
|
||||||
|
|
||||||
|
namespace ougge::modules {
|
||||||
|
|
||||||
/// converts hex color to float vector
|
/// converts hex color to float vector
|
||||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
#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 float vector to hex color
|
||||||
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
|
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
|
||||||
|
|
||||||
namespace ougge::gui {
|
|
||||||
|
|
||||||
#define default_font_path "fonts/DroidSans.ttf"
|
#define default_font_path "fonts/DroidSans.ttf"
|
||||||
|
|
||||||
class MainWindow {
|
class MainWindowSDL2 : public IEngineModule {
|
||||||
public:
|
public:
|
||||||
i32 fps_max = 60;
|
|
||||||
f32 default_font_size = 14.0f;
|
f32 default_font_size = 14.0f;
|
||||||
ImVec4 clear_color = RGBAHexToF(35,35,50,255);
|
ImVec4 clear_color = RGBAHexToF(35,35,50,255);
|
||||||
SDL_Window* sdl_window = nullptr;
|
SDL_Window* sdl_window = nullptr;
|
||||||
@@ -30,18 +30,20 @@ private:
|
|||||||
bool show_metrics_window = false;
|
bool show_metrics_window = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void open(const std::string& window_title, resources::ResourceManager& resourceManager);
|
MainWindowSDL2(Engine& engine, const std::string& window_title,
|
||||||
void close();
|
resources::ResourceManager& resourceManager);
|
||||||
|
~MainWindowSDL2();
|
||||||
|
|
||||||
/// process io events happened since previous frame
|
const std::string& getName() override;
|
||||||
void pollEvents(bool* loopRunning);
|
void beginFrame() override;
|
||||||
void beginFrame();
|
void endFrame() override;
|
||||||
void endFrame();
|
|
||||||
|
|
||||||
f32 getDPI();
|
f32 getDPI();
|
||||||
private:
|
private:
|
||||||
|
void pollEvents();
|
||||||
void draw_debug_window();
|
void draw_debug_window();
|
||||||
void draw_bg_window();
|
void draw_bg_window();
|
||||||
|
void drawErrorWindow();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
76
src/modules/MonoGameObjectSystem.cpp
Normal file
76
src/modules/MonoGameObjectSystem.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "MonoGameObjectSystem.hpp"
|
||||||
|
|
||||||
|
namespace ougge::modules {
|
||||||
|
|
||||||
|
const std::string& MonoGameObjectSystem::getName() {
|
||||||
|
return ougge_type_name<MonoGameObjectSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoGameObjectSystem::MonoGameObjectSystem(Engine& engine, u32 max_game_objects) :
|
||||||
|
IEngineModule(engine),
|
||||||
|
gameObjectPool(max_game_objects)
|
||||||
|
{
|
||||||
|
engineManagedAssembly = mono.loadAssembly("Ougge.dll");
|
||||||
|
gameObjectClass = engineManagedAssembly->getClass("Ougge", "GameObject");
|
||||||
|
gameObjectCtor = Mono::Method<void(u64, u32)>(gameObjectClass, ".ctor");
|
||||||
|
gameObjectInvokeUpdate = Mono::Method<void(f64)>(gameObjectClass, "InvokeUpdate");
|
||||||
|
gameObjectTryCreateComponent = Mono::Method<Mono::Bool(Mono::String)>(gameObjectClass, "TryCreateComponent_internal");
|
||||||
|
registerNativeCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets implementations for extern functions from src-csharp/NativeFunctions.cs
|
||||||
|
void MonoGameObjectSystem::registerNativeCallbacks(){
|
||||||
|
static MonoGameObjectSystem* this_static = this;
|
||||||
|
if(this_static != this)
|
||||||
|
throw new UsefulException("creation of more than one instance of MonoGameObjectSystem is not allowed");
|
||||||
|
|
||||||
|
auto createGameObject_callback = static_cast<void(*)(u64*, u32*)> (
|
||||||
|
[](u64* id_out, u32* index_out) -> void {
|
||||||
|
std::cout<<"createGameObject_callback"<<std::endl;
|
||||||
|
this_static->createGameObjectInPool(id_out, index_out);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
mono_add_internal_call("Ougge.NativeFunctions::createGameObject", (void*)createGameObject_callback);
|
||||||
|
|
||||||
|
auto freeGameObject_callback = static_cast<bool(*)(u32)>(
|
||||||
|
[](u32 index) -> bool {
|
||||||
|
std::cout<<"freeGameObject_callback"<<std::endl;
|
||||||
|
return this_static->gameObjectPool.erase(index);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
mono_add_internal_call("Ougge.NativeFunctions::freeGameObject", (void*)freeGameObject_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MonoGameObjectSystem::beginFrame(){
|
||||||
|
for(auto pair : gameObjectPool){
|
||||||
|
|
||||||
|
auto obj = pair.second.getObjectHandle().getObject();
|
||||||
|
std::cout<<"updating obj: "<<obj<<std::endl;
|
||||||
|
gameObjectInvokeUpdate(obj, engine.deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// is used in NativeFunctions.cs
|
||||||
|
game::GameObject& MonoGameObjectSystem::createGameObjectInPool(u64* id_out, u32* index_out){
|
||||||
|
auto pair = gameObjectPool.emplace(game::GameObject(mono.createObject(gameObjectClass)));
|
||||||
|
*id_out = ++obj_id;
|
||||||
|
*index_out = pair.first;
|
||||||
|
game::GameObject& obj = pair.second;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
game::GameObject& MonoGameObjectSystem::createAndConstructGameObject(){
|
||||||
|
u64 obj_id;
|
||||||
|
u32 obj_index;
|
||||||
|
game::GameObject& obj = createGameObjectInPool(&obj_id, &obj_index);
|
||||||
|
gameObjectCtor(obj.getObjectHandle().getObject(), obj_id, obj_index);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MonoGameObjectSystem::tryCreateComponent(game::GameObject& obj, const std::string& componentClassName){
|
||||||
|
Mono::String componentClassNameManaged = mono.createString(componentClassName);
|
||||||
|
Mono::Bool created = gameObjectTryCreateComponent(obj.getObjectHandle().getObject(), componentClassNameManaged);
|
||||||
|
return created.wide_bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
src/modules/MonoGameObjectSystem.hpp
Normal file
35
src/modules/MonoGameObjectSystem.hpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Engine.hpp"
|
||||||
|
#include "../common/function_shared_ptr.hpp"
|
||||||
|
#include "../mono/mono.hpp"
|
||||||
|
#include "../game/GameObjectPool.hpp"
|
||||||
|
|
||||||
|
namespace ougge::modules {
|
||||||
|
|
||||||
|
class MonoGameObjectSystem : public IEngineModule {
|
||||||
|
Mono::RuntimeJIT mono;
|
||||||
|
game::GameObjectPool gameObjectPool;
|
||||||
|
u64 obj_id = 0;
|
||||||
|
MonoClass* gameObjectClass;
|
||||||
|
Mono::Method<void(u64, u32)> gameObjectCtor;
|
||||||
|
Mono::Method<void(f64)> gameObjectInvokeUpdate;
|
||||||
|
Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<Mono::Assembly> engineManagedAssembly;
|
||||||
|
|
||||||
|
MonoGameObjectSystem(Engine& engine, u32 max_game_objects);
|
||||||
|
|
||||||
|
const std::string& getName() override;
|
||||||
|
void beginFrame() override;
|
||||||
|
|
||||||
|
game::GameObject& createAndConstructGameObject();
|
||||||
|
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void registerNativeCallbacks();
|
||||||
|
game::GameObject& createGameObjectInPool(u64* id_out, u32* index_out);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,10 +4,10 @@ class MemoryStreamBuf : public std::streambuf {
|
|||||||
public:
|
public:
|
||||||
MemoryStreamBuf(void* p, const std::size_t n);
|
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::istream::off_type off,
|
||||||
std::ios_base::seekdir dir,
|
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){
|
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public:
|
|||||||
|
|
||||||
using ResourceMap = std::unordered_map<std::string, ResourceFactory>;
|
using ResourceMap = std::unordered_map<std::string, ResourceFactory>;
|
||||||
|
|
||||||
|
//TODO: rewrite ResourceManager as a module
|
||||||
class ResourceManager {
|
class ResourceManager {
|
||||||
std::list<std::shared_ptr<ResourceMap>> _resourceMaps;
|
std::list<std::shared_ptr<ResourceMap>> _resourceMaps;
|
||||||
static std::shared_ptr<ResourceMap> _embeddedResourcesMap;
|
static std::shared_ptr<ResourceMap> _embeddedResourcesMap;
|
||||||
|
|||||||
Reference in New Issue
Block a user