Compare commits

...

2 Commits

Author SHA1 Message Date
3df4361779 GameObjectPool 2024-09-13 22:58:31 +05:00
bff2182ff0 chmod +x 2024-09-13 21:01:35 +05:00
18 changed files with 306 additions and 20 deletions

View File

@ -11,7 +11,8 @@
"dependencies/include/SDL2",
"dependencies/imgui",
"${default}"
]
],
"cppStandard": "c++20"
}
],
"version": 4

0
dependencies/compile_resources.sh vendored Normal file → Executable file
View File

0
dependencies/imgui.config vendored Normal file → Executable file
View File

0
dependencies/imgui.project.config vendored Normal file → Executable file
View File

0
dependencies/precompiled.config vendored Normal file → Executable file
View File

0
dependencies/resources.config vendored Normal file → Executable file
View File

9
dependencies/src-csharp.config vendored Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
DEP_WORKING_DIR='src-csharp'
if [[ "$TASK" = *_dbg ]]; then
DEP_BUILD_COMMAND='dotnet build src-csharp.sln -o bin -c Debug'
else
DEP_BUILD_COMMAND='dotnet build src-csharp.sln -o bin -c Release'
fi
DEP_CLEAN_COMMAND='rm -rf bin obj'
DEP_OTHER_OUT_FILES='bin/Ougge.dll'

4
project.config Normal file → Executable file
View File

@ -6,7 +6,7 @@ PROJECT="ougge"
CMP_C="gcc"
CMP_CPP="g++"
STD_C="c11"
STD_CPP="c++17"
STD_CPP="c++20"
WARN_C="-Wall -Wno-discarded-qualifiers -Wextra -Wno-unused-parameter"
WARN_CPP="-Wall -Wextra -Wno-unused-parameter"
SRC_C="$(find src -name '*.c')"
@ -16,7 +16,7 @@ SRC_CPP="$(find src -name '*.cpp')"
# See cbuild/example_dependency_configs
DEPENDENCY_CONFIGS_DIR='dependencies'
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
ENABLED_DEPENDENCIES='precompiled resources imgui'
ENABLED_DEPENDENCIES='precompiled resources imgui src-csharp'
# OBJDIR structure:
# ├── objects/ - Compiled object files. Cleans on each call of build task

24
src-csharp/GameObject.cs Normal file
View File

@ -0,0 +1,24 @@
using System.Management.Instrumentation;
using System.Numerics;
using System.Runtime.InteropServices;
namespace Ougge;
[StructLayout(LayoutKind.Sequential)]
public struct Transform
{
Vector2 scale;
Vector2 position;
float rotation;
}
public class Component
{
GameObject owner;
}
public class GameObject
{
Transform transform { get; }
GameObject? parent;
}

View File

@ -1,5 +1,4 @@
using System;
using System.Data;
namespace Ougge;

29
src/Game/GameObject.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "GameObject.hpp"
std::ostream& operator<<(std::ostream& s, Transform& t){
s<<"{ position: {x: "<<t.position.x<<", y: "<<t.position.y;
s<<"}, rotation: "<<t.rotation;
s<<", scale {x: "<<t.scale.x<<", y: "<<t.scale.y<<"} }";
return s;
}
GameObject::GameObject(Mono::Object managed_obj, GameObject *parent)
: object_handle(managed_obj), parent(parent)
{}
GameObject &GameObject::operator=(GameObject &&o){
transform = o.transform;
components = std::move(o.components);
object_handle = std::move(o.object_handle);
return *this;
}
bool GameObject::tryGetComponent(const std::u16string &name, Component **out_component)
{
return false;
}
bool GameObject::tryAddComponent(const std::u16string &name, Component &&component)
{
return false;
}

View File

@ -1,15 +1,41 @@
#pragma once
#include <map>
#include <iostream>
#include "../math.hpp"
#include <set>
#include "../UsefulException.hpp"
#include "../Mono/Mono.hpp"
class GameObject {
class GameObject;
class Component {
Mono::ObjectHandle object_handle;
GameObject* owner;
public:
Vec2 scale = { 1, 1 };
Vec2 position;
angle_t rotation;
private:
// std::set<Component> components;
inline Component(Mono::Object managed_obj, GameObject* owner)
: object_handle(managed_obj), owner(owner) {}
};
struct Transform {
Vec2 scale = { 1, 1 };
Vec2 position = { 0, 0 };
angle_t rotation = 0;
};
std::ostream& operator<<(std::ostream& s, Transform& t);
class GameObject {
Transform transform;
std::map<std::u16string, Component> components;
Mono::ObjectHandle object_handle;
GameObject* parent;
public:
GameObject(Mono::Object managed_obj, GameObject* parent);
GameObject& operator=(GameObject&& o);
inline Transform& getTransform(){ return transform; }
bool tryGetComponent(const std::u16string& name, Component** out_component);
bool tryAddComponent(const std::u16string& name, Component&& component);
};

127
src/Game/GameObjectPool.cpp Normal file
View File

@ -0,0 +1,127 @@
#include "GameObjectPool.hpp"
#include <bit>
#include <cstring>
GameObjectPool::GameObjectPool(u32 size)
{
useful_assert(size % 64 == 0, "size of GameObjectPool must be a multiple of 64");
this->size = size;
first_unused_index = 0;
buffer = new char[size*sizeof(GameObject)];
used_indices = new u64[size/64];
std::memset(buffer, 0, size*sizeof(GameObject));
std::memset(used_indices, 0, size/8);
}
GameObjectPool::~GameObjectPool()
{
// int i = 0;
for(auto&& p : *this){
// std::cout<<"~GameObjectPool i="<<i++<<std::endl;
p.second.~GameObject();
}
delete (char*)buffer;
delete used_indices;
}
bool GameObjectPool::isIndexUsed(u32 index)
{
return ( used_indices[index/64] & (1<<(index%64)) ) != 0;
}
u32 GameObjectPool::getNearestUnusedIndex(u32 startIndex)
{
if(startIndex >= size)
return -1;
if(!isIndexUsed(startIndex))
return startIndex;
u32 i = startIndex/64;
// mark previous bits as used
u64 u = used_indices[i] | ( (1<<startIndex%64) -1 );
while(u == u64(-1)){
i++;
if(i == size/64)
return -1;
u = used_indices[i];
}
u32 bitpos = std::countr_one(u);
if(bitpos == 64)
return -1;
u32 index = i*64 + bitpos;
return index;
}
u32 GameObjectPool::getNearestUsedIndex(u32 startIndex)
{
if(startIndex >= size)
return -1;
if(isIndexUsed(startIndex))
return startIndex;
u32 i = startIndex/64;
// mark previous bits as unused
u64 u = used_indices[i] & !( (1<<startIndex%64) -1 );
while(u == 0){
i++;
if(i == size/64)
return -1;
u = used_indices[i];
}
u32 bitpos = std::countr_zero(u);
if(bitpos == 64)
return -1;
u32 index = i*64 + bitpos;
return index;
}
GameObject& GameObjectPool::get(u32 index)
{
if(index >= size)
throw UsefulException(format("index %i is out of size %i", index, size));
if(!isIndexUsed(index))
throw UsefulException(format("there is no object at index %i", index));
return ((GameObject*)buffer)[index];
}
std::pair<u32, GameObject&> GameObjectPool::put_new(GameObject&& new_obj)
{
u32 i = first_unused_index;
if(i == (u32)-1)
throw UsefulException("can't put new GameObject to GameObjectPool because it's full");
GameObject& r = ( ((GameObject*)buffer)[i] = std::move(new_obj) );
used_indices[i] |= 1<<(i%64); // mark index bit as used
first_unused_index = getNearestUnusedIndex(i+1);
return std::pair<u32, GameObject&>(i, r);
}
void GameObjectPool::remove(u32 index)
{
if(index >= size)
throw UsefulException(format("index %i is out of size %i", index, size));
if(!isIndexUsed(index))
throw UsefulException(format("there is no object at index %i", index));
((GameObject*)buffer)[index].~GameObject();
used_indices[index/64] ^= ~(1<<(index%64)); // mark index bit as unused
if(index < first_unused_index)
first_unused_index = index;
}
GameObjectPool::iterator::iterator(GameObjectPool* p, u32 index)
: p(p), index(index)
{
}
std::pair<u32, GameObject&> GameObjectPool::iterator::operator*()
{
if(index >= p->size)
throw UsefulException("can't get value of end() iterator");
GameObject& r = ((GameObject*)p->buffer)[index];
return std::pair<u32, GameObject&>(index, r);
}
GameObjectPool::iterator& GameObjectPool::iterator::operator++()
{
index = p->getNearestUsedIndex(index+1);
return *this;
}

View File

@ -0,0 +1,37 @@
#include "GameObject.hpp"
class GameObjectPool {
void* buffer;
u64* used_indices;
u32 size;
u32 first_unused_index;
bool isIndexUsed(u32 index);
u32 getNearestUnusedIndex(u32 startIndex);
u32 getNearestUsedIndex(u32 startIndex);
friend class iterator;
public:
///@param size must be a multiple of 64
GameObjectPool(u32 size);
~GameObjectPool();
GameObject& get(u32 index);
std::pair<u32, GameObject&> put_new(GameObject&& new_obj);
void remove(u32 index);
class iterator {
GameObjectPool* p;
u32 index = 0;
public:
iterator(GameObjectPool* p, u32 index);
std::pair<u32, GameObject&> operator*();
iterator& operator++();
inline bool operator!=(const iterator& o) const { return index != o.index; };
inline bool operator==(const iterator& o) const { return index == o.index; };
};
inline iterator begin() { return iterator(this, 0); }
inline iterator end() { return iterator(this, -1); }
};

View File

@ -124,4 +124,25 @@ public:
std::shared_ptr<Assembly> loadAssembly(const std::string& name);
};
class ObjectHandle {
Object object;
u32 gc_handle;
public:
inline ObjectHandle(Object obj) : object(obj) { gc_handle = mono_gchandle_new(obj, false); }
inline ObjectHandle(const ObjectHandle& o) = delete;
inline ObjectHandle(ObjectHandle&& o) {
object = o.object;
gc_handle = o.gc_handle;
o.gc_handle = 0;
};
inline ObjectHandle& operator=(ObjectHandle&& o) {
object = o.object;
gc_handle = o.gc_handle;
o.gc_handle = 0;
return *this;
};
inline ~ObjectHandle() { if(gc_handle) mono_gchandle_free(gc_handle); }
inline Object getObject() { return object; }
};
}

View File

@ -18,4 +18,4 @@ public:
virtual char const* what() const noexcept;
};
#define useful_assert(EXPR, ERRMSG) if(!EXPR) throw UsefulException(ERRMSG);
#define useful_assert(EXPR, ERRMSG) if(!(EXPR)) throw UsefulException(ERRMSG);

View File

@ -1,11 +1,15 @@
#define SDL_MAIN_HANDLED
#include <iostream>
#include <iomanip>
#include "GUI/MainWindow.hpp"
#include "Resources/Resources.hpp"
#include "Game/Scene.hpp"
#include "format.hpp"
#include "UsefulException.hpp"
#include "Mono/Mono.hpp"
#include "Game/GameObjectPool.hpp"
#include <bitset>
#include <bit>
using namespace ougge;
@ -24,15 +28,24 @@ int main(int argc, const char** argv){
Mono::RuntimeJIT mono;
std::cout<<"initialized mono jit runtime"<<std::endl;
GameObjectPool p(64*512);
auto a = mono.loadAssembly("Ougge.dll");
auto c = a->getClass("Ougge", "ExampleScript");
auto scriptInstance = mono_object_new(mono.getDomain(), c);
mono_runtime_object_init(scriptInstance);
auto scriptUpdate = Mono::Method<void(f64)>(c, "Update");
updateCallbacks.push_back([scriptInstance, scriptUpdate](f64 deltaTime) -> void {
scriptUpdate(scriptInstance, deltaTime);
});
auto gameObjectClass = a->getClass("Ougge", "GameObject");
for(int i = 0; i < 32*1024; i++){
Mono::Object gameObjectManaged = mono_object_new(mono.getDomain(), gameObjectClass);
p.put_new(GameObject(gameObjectManaged, nullptr));
GameObject& o = p.get(0);
std::cout<<'['<<i<<"] "<<o.getTransform()<<std::endl;
}
return 0;
// mono_runtime_object_init(scriptInstance);
// auto scriptUpdate = Mono::Method<void(f64)>(c, "Update");
// updateCallbacks.push_back([scriptInstance, scriptUpdate](f64 deltaTime) -> void {
// scriptUpdate(scriptInstance, deltaTime);
// });
GUI::MainWindow w;
w.open("ougge", update);

0
tasks/get_mono_files_from.sh Normal file → Executable file
View File