Implement Component Manager

Implement Conan Package Manager
This commit is contained in:
Daniel Ramírez 2025-04-21 04:28:54 +02:00
parent 4841e4b7a0
commit 911d61ce0f
17 changed files with 195 additions and 34 deletions

3
.gitignore vendored
View File

@ -39,3 +39,6 @@ build/
*.exe
*.out
*.app
# CMake files
CMakeUserPresets.json

View File

@ -15,4 +15,10 @@ add_library(xrbds
${SOURCES}
)
list(APPEND CMAKE_PREFIX_PATH "build")
find_package(glm REQUIRED)
target_link_libraries(xrbds PRIVATE glm::glm)
add_subdirectory(samples/hello_world)

8
conanfile.py Normal file
View File

@ -0,0 +1,8 @@
from conan import ConanFile
class XrbdsRecipe(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeToolchain", "CMakeDeps"
def requirements(self):
self.requires("glm/1.0.1")

View File

@ -0,0 +1,10 @@
#include "component_manager.h"
std::unique_ptr<ComponentManager> ComponentManager::Instance;
std::unique_ptr<ComponentManager> &ComponentManager::GetInstance() {
if (!Instance)
Instance = std::unique_ptr<ComponentManager>(new ComponentManager());
return Instance;
}

View File

@ -0,0 +1,108 @@
#ifndef COMPONENT_MANAGER_H
#define COMPONENT_MANAGER_H
#include <unordered_map>
#include <typeindex>
#include <memory>
#include <vector>
#include <stdexcept>
#include <unordered_set>
#include <cstdint>
#include <calico/types.h>
#define Entity u32
class ComponentManager {
public:
~ComponentManager() = default;
static std::unique_ptr<ComponentManager> &GetInstance();
Entity newEntity() {
Entity entityID = nextEntityID++;
activeEntities.insert(entityID);
return entityID;
}
void removeEntity(Entity entityID) {
if (activeEntities.erase(entityID) > 0) {
removeAllComponents(entityID);
}
}
template <typename ComponentType>
void addComponent(Entity entityID, const ComponentType &component) {
auto &componentMap = getComponentMap<ComponentType>();
componentMap[entityID] =
std::make_shared<ComponentType>(std::move(component));
}
template <typename ComponentType>
std::shared_ptr<ComponentType> getComponent(Entity entityID) {
auto &componentMap = getComponentMap<ComponentType>();
auto it = componentMap.find(entityID);
if (it != componentMap.end()) {
return it->second;
}
return nullptr;
}
template <typename ComponentType> void removeComponent(Entity entityID) {
auto &componentMap = getComponentMap<ComponentType>();
componentMap.erase(entityID);
}
void removeAllComponents(Entity entityID) {
for (auto &pair : componentPools) {
pair.second->remove(entityID);
}
}
template <typename ComponentType> auto begin() {
return getComponentMap<ComponentType>().begin();
}
template <typename ComponentType> auto end() {
return getComponentMap<ComponentType>().end();
}
private:
ComponentManager() = default;
ComponentManager(const ComponentManager &) = delete;
ComponentManager &operator=(const ComponentManager &) = delete;
static std::unique_ptr<ComponentManager> Instance;
struct IComponentPool {
virtual ~IComponentPool() = default;
virtual void remove(Entity entityID) = 0;
};
template <typename ComponentType> struct ComponentPool : IComponentPool {
std::unordered_map<Entity, std::shared_ptr<ComponentType>> components;
void remove(Entity entityID) override { components.erase(entityID); }
};
template <typename ComponentType>
std::unordered_map<Entity, std::shared_ptr<ComponentType>> &
getComponentMap() {
std::type_index typeIndex(typeid(ComponentType));
if (componentPools.find(typeIndex) == componentPools.end()) {
componentPools[typeIndex] =
std::make_unique<ComponentPool<ComponentType>>();
}
return static_cast<ComponentPool<ComponentType> *>(
componentPools[typeIndex].get())
->components;
}
std::unordered_map<std::type_index, std::unique_ptr<IComponentPool>>
componentPools;
std::unordered_set<Entity> activeEntities;
Entity nextEntityID = 0;
};
#endif // COMPONENT_MANAGER_H

View File

@ -6,6 +6,9 @@
#include <stdio.h>
#include "input/input.h"
#include "component_manager.h"
#include "object.h"
#include "components/transform.h"
/////////////////////////////////////////////////////////
// Main function
@ -37,7 +40,15 @@ std::unique_ptr<Engine> &Engine::GetInstance() {
void Engine::run() {
// Initialize the main loop
// - VBlank IRQ
irqSet(IRQ_VBLANK, Engine::VblankCallback);
VblankCallback();
// TEST - Create an entity and add a component
Entity entity = ComponentManager::GetInstance()->newEntity();
Transform transform({0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f},
{1.0f, 1.0f, 1.0f});
ComponentManager::GetInstance()->addComponent(entity, transform);
while (pmMainLoop()) {
processInput();

View File

@ -9,6 +9,8 @@ public:
virtual void update();
virtual void render();
virtual void test() { iprintf("Object::test\n"); };
protected:
int id;
};

View File

@ -3,10 +3,7 @@
#include <nds.h>
#include <stdio.h>
#include "input/input.h"
std::unique_ptr<Renderer> Renderer::Instance;
float Renderer::pos = -4.0f;
std::unique_ptr<Renderer> &Renderer::GetInstance() {
if (!Instance)
@ -21,9 +18,9 @@ void Renderer::render() {
glLoadIdentity(); // Load the identity matrix
// Render scene
glTranslatef(0.0f, 0.0f, pos); // Move the camera back
glRotatef(45, 1, 1, 0); // Rotation
drawCube(1.0f); // Draw a cube
glTranslatef(0.f, 0.f, -4.f); // Move the camera back
glRotatef(45, 1, 1, 0); // Rotation
drawCube(1.0f); // Draw a cube
endFrame(); // Finish rendering
}

View File

@ -34,8 +34,6 @@
*/
class Renderer {
public:
static float pos;
/**
* @brief Virtual destructor for the Renderer class.
*

View File

@ -0,0 +1 @@
#include "scene/3d/node_3d.h"

1
engine/scene/node.cpp Normal file
View File

@ -0,0 +1 @@
#include "scene/node.h"

View File

@ -0,0 +1,20 @@
#ifndef XRBDS_COMPONENTS_TRANSFORM_H
#define XRBDS_COMPONENTS_TRANSFORM_H
#include <glm/glm.hpp>
using Vector3 = glm::vec3;
using Vector2 = glm::vec2;
struct Transform {
Vector3 position{0.0f, 0.0f, 0.0f};
Vector3 rotation{0.0f, 0.0f, 0.0f}; // Euler angles in radians
Vector3 scale{1.0f, 1.0f, 1.0f};
Transform() = default;
Transform(const Vector3 &pos, const Vector3 &rot, const Vector3 &scl)
: position(pos), rotation(rot), scale(scl) {}
};
#endif // XRBDS_COMPONENTS_TRANSFORM_H

View File

@ -24,10 +24,6 @@
#include "graphics/renderer.h"
class Input;
class MainLoop;
class Renderer;
/**
* @class Engine
* @brief Core engine class responsible for managing the game loop and

View File

View File

View File

@ -1,9 +1,12 @@
project(hello_world)
add_executable(hello_world
hello_world.cpp
)
target_link_libraries(hello_world
xrbds
glm::glm
)
# Project specific settings

View File

@ -1,28 +1,25 @@
#!/bin/bash
DIR="../build"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
BUILD_DIR="$PROJECT_ROOT/build"
if [ ! -d $DIR ]; then
mkdir $DIR
WORKING_DIR_NAME="$(basename "$SCRIPT_DIR")"
if [ ! -d "$BUILD_DIR" ]; then
mkdir "$BUILD_DIR" || {
echo "build/ directory could not be created. Exiting..."
exit 3
}
fi
if [ ! -d $DIR ]; then
echo "Failed to create build directory"
exit 3
fi
echo "Installing Conan dependencies..."
conan install "$PROJECT_ROOT" \
--profile:host=nds \
--profile:build=nds \
--build=missing \
--output-folder="$BUILD_DIR"
if [ ! -d $DEVKITPRO ]; then
echo "Please set DEVKITPRO environment variable"
exit 2
fi
working_dir_name="$(basename "$PWD")"
if [ "$working_dir_name" = "tools" ]; then
echo "Creating solution..."
else
echo "Please run this script from the tools directory"
exit 1
fi
$DEVKITPRO/portlibs/nds/bin/arm-none-eabi-cmake -S .. -B $DIR
echo "Generating CMake solution..."
cd "$PROJECT_ROOT" || exit 1
cmake --preset conan-release