diff --git a/Editor/EditorCamera.h b/Editor/EditorCamera.h index 7313d855..8c4833dd 100644 --- a/Editor/EditorCamera.h +++ b/Editor/EditorCamera.h @@ -35,6 +35,8 @@ namespace DT using BaseCamera::BaseCamera; + EditorCamera(Context *ctx) : BaseCamera(ctx), transform(ctx) {} + void Recalculate(Window *window) { PROFILE(); @@ -42,7 +44,7 @@ namespace DT view = glm::lookAtLH(transform.translation, transform.translation + transform.Forward(), transform.Up()); glm::vec2 winSize = window->GetWindowSize(); - float aspect = (float)winSize.x/winSize.y; + float aspect = (float)winSize.x / winSize.y; if (isOrthographic) projection = glm::orthoLH(-aspect, aspect, -1.0f, 1.0f, nearPlane, farPlane); else diff --git a/Editor/Panels/Inspector.h b/Editor/Panels/Inspector.h index 4f6f7cfd..a6628ffa 100644 --- a/Editor/Panels/Inspector.h +++ b/Editor/Panels/Inspector.h @@ -49,7 +49,7 @@ namespace DT { auto components = sceneManager->activeScene.View(worldOutliner->GetSelectedEntity()).Fatal("InspectorPanel::Fatal()"); for (auto component : components) - component.second->InspectorMenu(ctx, dt); + component.second->InspectorMenu(&ctx, dt); } ImGui::End(); diff --git a/Editor/Panels/WorldView.h b/Editor/Panels/WorldView.h index 2d73a104..3a4d97d9 100644 --- a/Editor/Panels/WorldView.h +++ b/Editor/Panels/WorldView.h @@ -35,7 +35,7 @@ namespace DT public: EditorCamera editorCamera; - WorldViewPanel(Context &ctx) : editorCamera(ctx), + WorldViewPanel(Context &ctx) : editorCamera(&ctx), translateIcon(Texture::Load(ctx.projectPath / "Engine" / "Icons" / "translate.png").Fatal("WorldViewPanel::WorldViewPanel()")), rotateIcon(Texture::Load(ctx.projectPath / "Engine" / "Icons" / "rotate.png").Fatal("WorldViewPanel::WorldViewPanel()")), scaleIcon(Texture::Load(ctx.projectPath / "Engine" / "Icons" / "scale.png").Fatal("WorldViewPanel::WorldViewPanel()")) {} diff --git a/Engine/Components/Camera.cpp b/Engine/Components/Camera.cpp index 837b6fef..b7912abf 100644 --- a/Engine/Components/Camera.cpp +++ b/Engine/Components/Camera.cpp @@ -26,15 +26,15 @@ SOFTWARE. namespace DT { - void Camera::Init(Context &ctx) + void Camera::Init(Context *ctx) { PROFILE(); transform = scene->Require(entity).Fatal("Camera::Init()"); - window = ctx.GetService().Fatal("Camera::Init()"); + window = ctx->GetService().Fatal("Camera::Init()"); } - void Camera::Tick(Context &ctx, const float &dt) + void Camera::Tick(Context *ctx, const float &dt) { PROFILE(); @@ -48,7 +48,7 @@ namespace DT projection = glm::perspectiveLH(glm::radians(fieldOfView), window->GetWindowSize().x / window->GetWindowSize().y, nearPlane, farPlane); } - void Camera::InspectorMenu(Context &ctx, const float &dt) + void Camera::InspectorMenu(Context *ctx, const float &dt) { if (ImGui::CollapsingHeader("Camera")) { diff --git a/Engine/Components/Camera.h b/Engine/Components/Camera.h index 65d05d83..2cc5aa2f 100644 --- a/Engine/Components/Camera.h +++ b/Engine/Components/Camera.h @@ -36,14 +36,14 @@ namespace DT class Camera : public Component, public BaseCamera { public: - Camera(Context &ctx) : BaseCamera(ctx) + Camera(Context *ctx) : BaseCamera(ctx) { activeCamera = std::shared_ptr(this); } - void Init(Context &ctx) override; - void Tick(Context &ctx, const float &dt) override; - void InspectorMenu(Context &ctx, const float &dt) override; + void Init(Context *ctx) override; + void Tick(Context *ctx, const float &dt) override; + void InspectorMenu(Context *ctx, const float &dt) override; glm::vec3 GetPosition() override { diff --git a/Engine/Components/ComponentRegister.h b/Engine/Components/ComponentRegister.h new file mode 100644 index 00000000..029dea9b --- /dev/null +++ b/Engine/Components/ComponentRegister.h @@ -0,0 +1,49 @@ +/* +MIT License + +Copyright (c) 2021 - 2023 Aryan Baburajan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#define REGISTER_COMPONENT(component) \ + DT_DLL_EXPORT std::shared_ptr GetInstanceOf##component(Context *ctx) \ + { \ + return std::make_shared(ctx); \ + } \ + DT_DLL_EXPORT std::type_index GetTypeIndexOf##component() \ + { \ + return std::type_index(typeid(component)); \ + } + +namespace DT +{ + REGISTER_COMPONENT(Camera); + REGISTER_COMPONENT(SpriteRenderer); + REGISTER_COMPONENT(Tag); + REGISTER_COMPONENT(Transform); +} \ No newline at end of file diff --git a/Engine/Components/SpriteRenderer.cpp b/Engine/Components/SpriteRenderer.cpp index b337fe10..422e10c2 100644 --- a/Engine/Components/SpriteRenderer.cpp +++ b/Engine/Components/SpriteRenderer.cpp @@ -31,33 +31,40 @@ SOFTWARE. namespace DT { - SpriteRenderer::SpriteRenderer(Context *ctx, const std::filesystem::path &texturePath) : + SpriteRenderer::SpriteRenderer(Context *ctx) : material(Shader::Default(*ctx)) { PROFILE(); - material.diffuseMap = Texture::Load(texturePath).Fatal("SpriteRenderer::SpriteRenderer()"); renderer = ctx->GetService().Fatal("SpriteRenderer::SpriteRenderer()"); } - void SpriteRenderer::Init(Context &ctx) + void SpriteRenderer::SetSprite(const std::filesystem::path &texturePath) { PROFILE(); - transform = scene->Require(entity).Fatal("SpriteRenderer::SpriteRenderer()"); + material.diffuseMap = Texture::Load(texturePath).Fatal("SpriteRenderer::SetSprite()"); } - void SpriteRenderer::Tick(Context &ctx, const float &dt) + void SpriteRenderer::Init(Context *ctx) { PROFILE(); - mesh.Draw(*renderer, transform->GetModelMatrix(), material); + transform = scene->Require(entity).Fatal("SpriteRenderer::Init()"); } - void SpriteRenderer::EditorTick(Context &ctx, const float &dt) + void SpriteRenderer::Tick(Context *ctx, const float &dt) { PROFILE(); - mesh.Draw(*renderer, transform->GetModelMatrix(), material); + if (material.diffuseMap.has_value()) + mesh.Draw(*renderer, transform->GetModelMatrix(), material); + } + + void SpriteRenderer::EditorTick(Context *ctx, const float &dt) + { + PROFILE(); + + Tick(ctx, dt); } } \ No newline at end of file diff --git a/Engine/Components/SpriteRenderer.h b/Engine/Components/SpriteRenderer.h index 96cb7a15..672baca9 100644 --- a/Engine/Components/SpriteRenderer.h +++ b/Engine/Components/SpriteRenderer.h @@ -36,11 +36,13 @@ namespace DT class SpriteRenderer : public Component { public: - SpriteRenderer(Context *ctx, const std::filesystem::path &texturePath); + SpriteRenderer(Context *ctx); + + void SetSprite(const std::filesystem::path &texturePath); - void Init(Context &ctx) override; - void Tick(Context &ctx, const float &dt) override; - void EditorTick(Context &ctx, const float &dt) override; + void Init(Context *ctx) override; + void Tick(Context *ctx, const float &dt) override; + void EditorTick(Context *ctx, const float &dt) override; private: Mesh &mesh = Mesh::Quad(); diff --git a/Engine/Components/Tag.h b/Engine/Components/Tag.h index 39ff0b96..f2cf1942 100644 --- a/Engine/Components/Tag.h +++ b/Engine/Components/Tag.h @@ -24,7 +24,6 @@ SOFTWARE. #pragma once -#include #include namespace DT @@ -34,12 +33,9 @@ namespace DT public: std::string name = "Untitled Entity"; - Tag(const std::string &_name) : name(_name) - { - PROFILE(); - } + Tag(Context *ctx) {} - void InspectorMenu(Context &ctx, const float &dt) override + void InspectorMenu(Context *ctx, const float &dt) override { if (ImGui::CollapsingHeader("Tag")) { diff --git a/Engine/Components/Transform.cpp b/Engine/Components/Transform.cpp index 440a5e92..f01f2276 100644 --- a/Engine/Components/Transform.cpp +++ b/Engine/Components/Transform.cpp @@ -89,7 +89,7 @@ namespace DT rotation = glm::quatLookAtLH(glm::normalize(at - translation), {0.f, 1.f, 0.f}); } - void Transform::InspectorMenu(Context &ctx, const float &dt) + void Transform::InspectorMenu(Context *ctx, const float &dt) { if (ImGui::CollapsingHeader("Transform")) { diff --git a/Engine/Components/Transform.h b/Engine/Components/Transform.h index 0f3f8988..51206db0 100644 --- a/Engine/Components/Transform.h +++ b/Engine/Components/Transform.h @@ -36,6 +36,8 @@ namespace DT glm::quat rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f); glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); + Transform(Context *ctx) {} + glm::mat4 GetModelMatrix(); void SetModelMatrix(glm::mat4 model); glm::vec3 Right(); @@ -45,6 +47,6 @@ namespace DT void SetEulerRotation(glm::vec3 eulerRotation); void LookAt(const glm::vec3 &at); - void InspectorMenu(Context &ctx, const float &dt) override; + void InspectorMenu(Context *ctx, const float &dt) override; }; } \ No newline at end of file diff --git a/Engine/Core/Error.h b/Engine/Core/Error.h index c9484698..48710258 100644 --- a/Engine/Core/Error.h +++ b/Engine/Core/Error.h @@ -69,6 +69,14 @@ namespace DT std::cout << "[FATAL] Unhandled error: " + error.value() << ".\n"; abort(); } + + T GetValue() + { + PROFILE(); + + handled = true; + return value.value(); + } bool HasError() { @@ -92,7 +100,7 @@ namespace DT PROFILE(); handled = true; - if (!HasError()) return Value(); + if (!HasError()) return GetValue(); std::cout << "[LOG] " << (errorContext != "" ? errorContext + "\n " : "") << error.value(); } @@ -101,7 +109,7 @@ namespace DT PROFILE(); handled = true; - if (!HasError()) return Value(); + if (!HasError()) return GetValue(); std::cout << "[ERR] " << (errorContext != "" ? errorContext + "\n " : "") << error.value(); } @@ -110,7 +118,7 @@ namespace DT PROFILE(); handled = true; - if (!HasError()) return Value(); + if (!HasError()) return GetValue(); std::cout << "[FATAL] " << (errorContext != "" ? errorContext + "\n " : "") << error.value(); abort(); } @@ -119,13 +127,5 @@ namespace DT std::optional error; std::optional value; bool handled = true; - - T Value() - { - PROFILE(); - - handled = true; - return value.value(); - } }; } \ No newline at end of file diff --git a/Engine/Core/InputManager.cpp b/Engine/Core/InputManager.cpp index e037b966..71bb3044 100644 --- a/Engine/Core/InputManager.cpp +++ b/Engine/Core/InputManager.cpp @@ -27,7 +27,7 @@ SOFTWARE. namespace DT { - InputManager::InputManager(Context &ctx, const json &data) + InputManager::InputManager(Context &ctx) { PROFILE(); diff --git a/Engine/Core/InputManager.h b/Engine/Core/InputManager.h index 7fc54b0c..a9366143 100644 --- a/Engine/Core/InputManager.h +++ b/Engine/Core/InputManager.h @@ -156,9 +156,9 @@ SOFTWARE. #define KEY_MENU 348 #define KEY_LAST 348 -#define MOD_SHIFT 0x0001 +#define DT_MOD_SHIFT 0x0001 #define MOD_CONTROL 0x0002 -#define MOD_ALT 0x0004 +#define DT_MOD_ALT 0x0004 #define MOD_SUPER 0x0008 #define MOD_CAPS_LOCK 0x0010 #define MOD_NUM_LOCK 0x0020 @@ -231,7 +231,7 @@ namespace DT class InputManager { public: - InputManager(Context &ctx, const json &data); + InputManager(Context &ctx); void Process(); diff --git a/Engine/Core/Module.cpp b/Engine/Core/Module.cpp new file mode 100644 index 00000000..4c037b0e --- /dev/null +++ b/Engine/Core/Module.cpp @@ -0,0 +1,54 @@ +/* +MIT License + +Copyright (c) 2021 - 2023 Aryan Baburajan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include +#include + +namespace DT +{ + Module::Module(std::filesystem::path path, Error *err) + { +#ifdef _WIN32 + module = LoadLibrary(path.string().c_str()); +#endif +#ifdef __linux__ + module = dlopen(path.string().c_str(), RTLD_LAZY); +#endif + + if (!module) + *err = Error("Error loading GameModule at " + path.string() + ".\nError: " + Platform::GetLastErrorAsString()); + else + std::cout << "[LOG] Loaded GameModule at " << path << ".\n"; + } + + Module::~Module() + { +#ifdef _WIN32 + FreeLibrary(module); +#endif +#ifdef __linux__ + dlclose(module); +#endif + } +} \ No newline at end of file diff --git a/Engine/Core/Module.h b/Engine/Core/Module.h new file mode 100644 index 00000000..93a08341 --- /dev/null +++ b/Engine/Core/Module.h @@ -0,0 +1,62 @@ +/* +MIT License + +Copyright (c) 2021 - 2023 Aryan Baburajan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +#include +#include +#include + +namespace DT +{ + class Module + { + public: +#ifdef _WIN32 + HMODULE module; +#endif +#ifdef __linux__ + void *module; +#endif + + Module(std::filesystem::path path, Error *err); + ~Module(); + + template + ErrorOr GetSymbolAddress(const std::string &symbolName) + { +#ifdef _WIN32 + T address = (T)GetProcAddress(module, symbolName.c_str()); +#endif +#ifdef __linux__ + T address = (T)dlsym(module, symbolName.c_str()); +#endif + std::string lastError = Platform::GetLastErrorAsString(); + if (lastError.size() == 0) + return address; + else + return ErrorOr(lastError); + } + }; +} \ No newline at end of file diff --git a/Engine/Core/Platform.cpp b/Engine/Core/Platform.cpp new file mode 100644 index 00000000..e8f57917 --- /dev/null +++ b/Engine/Core/Platform.cpp @@ -0,0 +1,57 @@ +/* +MIT License + +Copyright (c) 2021 - 2023 Aryan Baburajan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include + +namespace DT +{ + void Platform::Execute(const std::string command) + { +#ifdef _WIN32 + ShellExecute(NULL, NULL, command.c_str(), NULL, NULL, SW_SHOWDEFAULT); +#endif +#ifdef __linux__ + system(command.c_str()); +#endif + } + + std::string Platform::GetLastErrorAsString() + { +#ifdef _WIN32 + DWORD errorMessageID = ::GetLastError(); + if (errorMessageID == 0) + return std::string(); + + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + std::string message(messageBuffer, size); + + LocalFree(messageBuffer); + return message; +#endif +#ifdef __linux__ + // Write Linux specific code here +#endif + } +} \ No newline at end of file diff --git a/Engine/Core/Platform.h b/Engine/Core/Platform.h new file mode 100644 index 00000000..66a8853d --- /dev/null +++ b/Engine/Core/Platform.h @@ -0,0 +1,36 @@ +/* +MIT License + +Copyright (c) 2021 - 2023 Aryan Baburajan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +#include + +namespace DT +{ + namespace Platform + { + std::string GetLastErrorAsString(); + void Execute(const std::string command); + } +} \ No newline at end of file diff --git a/Engine/ECS/Component.h b/Engine/ECS/Component.h index bf1a9214..08b75ae7 100644 --- a/Engine/ECS/Component.h +++ b/Engine/ECS/Component.h @@ -27,6 +27,11 @@ SOFTWARE. #include #include +namespace DT +{ + class Component; +} + namespace DT { class Scene; @@ -37,9 +42,9 @@ namespace DT Entity entity; Scene *scene; - virtual void Init(Context &ctx) {} - virtual void Tick(Context &ctx, const float &dt) {} - virtual void EditorTick(Context &ctx, const float &dt) {} - virtual void InspectorMenu(Context &ctx, const float &dt) {} + virtual void Init(Context *ctx) {} + virtual void Tick(Context *ctx, const float &dt) {} + virtual void EditorTick(Context *ctx, const float &dt) {} + virtual void InspectorMenu(Context *ctx, const float &dt) {} }; } \ No newline at end of file diff --git a/Engine/ECS/Scene.cpp b/Engine/ECS/Scene.cpp index 2ab8c101..1690da45 100644 --- a/Engine/ECS/Scene.cpp +++ b/Engine/ECS/Scene.cpp @@ -24,15 +24,67 @@ SOFTWARE. #include #include +#include + +typedef std::shared_ptr(*GetInstanceOfFunc)(DT::Context *ctx); +typedef std::type_index(*GetTypeIndexOfFunc)(); namespace DT { + Scene::Scene(Context &ctx) : context(ctx) + { + PROFILE(); + + gameModule = context.GetService().Fatal("Scene::Scene()"); + } + + ErrorOr Scene::Has(const std::string &type, Entity entity) + { + PROFILE(); + + ErrorOr typeId = GetTypeIndexOfComponent(type); + if (typeId.HasError()) + return ErrorOr(typeId.GetError()); + + return components.at(entity).find(typeId.GetValue()) != components.at(entity).end(); + } + + ErrorOr> Scene::Assign(const std::string &type, Entity entity) + { + PROFILE(); + + if (!IsValid(entity)) + return ErrorOr>("Invalid entity.\n"); + + ErrorOr hasComponent = Has(type, entity); + if (hasComponent.HasError()) + return ErrorOr>(hasComponent.GetError()); + if (hasComponent.GetValue()) + return ErrorOr>("Entity has already been assigned " + type + ".\n"); + + ErrorOr getInstanceFunc = gameModule->GetSymbolAddress("GetInstanceOf" + type); + if (getInstanceFunc.HasError()) + return ErrorOr>(getInstanceFunc.GetError()); + std::shared_ptr component = getInstanceFunc.GetValue()(&context); + + ErrorOr typeId = GetTypeIndexOfComponent(type); + if (typeId.HasError()) + return ErrorOr>(typeId.GetError()); + + component->entity = entity; + component->scene = this; + components.at(entity)[typeId.GetValue()].reset(component.get()); + + return component; + } + std::unordered_set Scene::GetEntities() { PROFILE(); std::unordered_set entities; - for (std::pair>> &entity : components) { + for (std::pair>> &entity : components) + { entities.insert(entity.first); } return entities; @@ -46,7 +98,7 @@ namespace DT return ErrorOr>>("Invalid entity.\n"); return components.at(entity); } - + ErrorOr Scene::GetEntityNamed(const std::string &name) { for (Entity entity : GetEntities()) @@ -55,4 +107,12 @@ namespace DT return entity; return ErrorOr("No entity named " + name + ".\n"); } + + ErrorOr Scene::GetTypeIndexOfComponent(const std::string &type) + { + ErrorOr getTypeIdFunc = gameModule->GetSymbolAddress("GetTypeIndexOf" + type); + if (getTypeIdFunc.HasError()) + return ErrorOr(getTypeIdFunc.GetError()); + return getTypeIdFunc.GetValue()(); + } } \ No newline at end of file diff --git a/Engine/ECS/Scene.h b/Engine/ECS/Scene.h index a35c34e0..1db85326 100644 --- a/Engine/ECS/Scene.h +++ b/Engine/ECS/Scene.h @@ -30,9 +30,13 @@ SOFTWARE. namespace DT { + class Module; + class Scene { public: + Scene(Context &ctx); + std::unordered_set GetEntities(); ErrorOr>> View(Entity entity); ErrorOr GetEntityNamed(const std::string &name); @@ -66,6 +70,9 @@ namespace DT return Error(); } + + ErrorOr Has(const std::string &type, Entity entity); + ErrorOr> Assign(const std::string &type, Entity entity); template bool Has(Entity entity) @@ -85,18 +92,18 @@ namespace DT return componentMap.find(typeIndex) != componentMap.end(); } - template - ErrorOr> Require(Entity entity, Args &&...args) + template + ErrorOr> Require(Entity entity) { PROFILE(); if (Has(entity)) return Get(entity); - return Assign(entity, std::forward(args)...); + return Assign(entity); } - template - ErrorOr> Assign(Entity entity, Args &&...args) + template + ErrorOr> Assign(Entity entity) { PROFILE(); @@ -104,19 +111,11 @@ namespace DT return ErrorOr>("Invalid entity.\n"); if (Has(entity)) return ErrorOr>("Entity has already been assigned " + std::string(typeid(T).name()) + ".\n"); - - auto entityComponentsItr = components.find(entity); - if (entityComponentsItr == components.end()) - { - std::unordered_map> newEntityComponents; - entityComponentsItr = components.emplace(entity, std::move(newEntityComponents)).first; - } - - std::shared_ptr component = std::make_shared(std::forward(args)...); + + std::shared_ptr component = std::make_shared(&context); component->entity = entity; component->scene = this; - - entityComponentsItr->second[std::type_index(typeid(T))] = component; + components.at(entity)[std::type_index(typeid(T))] = component; return component; } @@ -152,5 +151,9 @@ namespace DT Entity entityCounter = 1; std::unordered_set tombStones; std::unordered_map>> components; + Module *gameModule; + Context &context; + + ErrorOr GetTypeIndexOfComponent(const std::string &type); }; } diff --git a/Engine/ECS/SceneManager.cpp b/Engine/ECS/SceneManager.cpp index 6ab53d6f..20831366 100644 --- a/Engine/ECS/SceneManager.cpp +++ b/Engine/ECS/SceneManager.cpp @@ -26,7 +26,7 @@ SOFTWARE. namespace DT { - SceneManager::SceneManager(const json &sceneManagerData) + SceneManager::SceneManager(Context &ctx, const json &sceneManagerData) : activeScene(ctx) { PROFILE(); @@ -45,16 +45,20 @@ namespace DT PROFILE(); } - void SceneManager::Init(Context &ctx) + void SceneManager::Init(Context *ctx) { PROFILE(); for (Entity entity : activeScene.GetEntities()) + { for (std::pair> &component : activeScene.View(entity).Fatal("SceneManager::Init()")) - component.second->Init(ctx); + { + component.second.get()->Init(ctx); + } + } } - void SceneManager::Tick(Context &ctx, const float &deltaTime) + void SceneManager::Tick(Context *ctx, const float &deltaTime) { PROFILE(); @@ -63,7 +67,7 @@ namespace DT component.second->Tick(ctx, deltaTime); } - void SceneManager::EditorTick(Context &ctx, const float &deltaTime) + void SceneManager::EditorTick(Context *ctx, const float &deltaTime) { PROFILE(); diff --git a/Engine/ECS/SceneManager.h b/Engine/ECS/SceneManager.h index de6c1399..2ada8ad9 100644 --- a/Engine/ECS/SceneManager.h +++ b/Engine/ECS/SceneManager.h @@ -36,13 +36,13 @@ namespace DT public: Scene activeScene; - SceneManager(const json &sceneManagerData); + SceneManager(Context &ctx, const json &sceneManagerData); void LoadDemoScene(); void LoadScene(); - void Init(Context &ctx); - void Tick(Context &ctx, const float &deltaTime); - void EditorTick(Context &ctx, const float &deltaTime); + void Init(Context *ctx); + void Tick(Context *ctx, const float &deltaTime); + void EditorTick(Context *ctx, const float &deltaTime); }; } \ No newline at end of file diff --git a/Engine/Renderer/BaseCamera.h b/Engine/Renderer/BaseCamera.h index 3d80dad1..ba6b2414 100644 --- a/Engine/Renderer/BaseCamera.h +++ b/Engine/Renderer/BaseCamera.h @@ -41,9 +41,9 @@ namespace DT static std::unordered_set cameras; - BaseCamera(Context &ctx) + BaseCamera(Context *ctx) { - Window *window = ctx.GetService().Fatal("BaseCamera::BaseCamera()"); + Window *window = ctx->GetService().Fatal("BaseCamera::BaseCamera()"); // FBO glGenFramebuffers(1, &FBO); diff --git a/Engine/dtpch.h b/Engine/dtpch.h index 504396ca..b602a275 100644 --- a/Engine/dtpch.h +++ b/Engine/dtpch.h @@ -24,10 +24,13 @@ SOFTWARE. #pragma once -#ifdef DLL_EXPORT -#define API __declspec(dllexport) -#else -#define API __declspec(dllimport) +#ifdef _WIN32 +#include +#define DT_DLL_EXPORT extern "C" __declspec(dllexport) +#endif +#ifdef __linux__ +#include +#define DT_DLL_EXPORT extern "C" __attribute__((visibility("default"))) #endif #include diff --git a/Runtime/Main.cpp b/Runtime/Main.cpp index 5b938e6e..eee76870 100644 --- a/Runtime/Main.cpp +++ b/Runtime/Main.cpp @@ -33,6 +33,7 @@ SOFTWARE. #include #include #include +#include #include #include @@ -42,12 +43,11 @@ SOFTWARE. #include #include -#include - using namespace DT; class FreeLookCamera : public Component { +public: std::shared_ptr transform; std::shared_ptr camera; Window *window; @@ -58,17 +58,19 @@ class FreeLookCamera : public Component float lastx; - void Init(Context &ctx) override + FreeLookCamera(Context *ctx) {} + + void Init(Context *ctx) override { PROFILE(); transform = scene->Require(entity).Fatal("FreeLookCamera::Init()"); - camera = scene->Require(entity, ctx).Fatal("FreeLookCamera::Init()"); - window = ctx.GetService().Fatal("FreeLookCamera::Init()"); - input = ctx.GetService().Fatal("FreeLookCamera::Init()"); + camera = scene->Require(entity).Fatal("FreeLookCamera::Init()"); + window = ctx->GetService().Fatal("FreeLookCamera::Init()"); + input = ctx->GetService().Fatal("FreeLookCamera::Init()"); } - void Tick(Context &ctx, const float &dt) override + void Tick(Context *ctx, const float &dt) override { PROFILE(); @@ -121,40 +123,6 @@ class FreeLookCamera : public Component } }; -class TransformInspector : public Component -{ -public: - std::shared_ptr transform; - float speed = 2.5f, sensitivity = 75.f; - glm::vec3 orientation; - char dir; - - TransformInspector(char _d) : dir(_d) - { - PROFILE(); - } - - void Init(Context &ctx) override - { - PROFILE(); - - transform = scene->Require(entity).Fatal("FreeLookCamera::Init()"); - } - - void Tick(Context &ctx, const float &dt) override - { - PROFILE(); - - if (dir == 'x') - orientation.x += sensitivity * dt; - if (dir == 'y') - orientation.y += sensitivity * dt; - if (dir == 'z') - orientation.z += sensitivity * dt; - transform->SetEulerRotation(orientation); - } -}; - int main(int argc, char* argv[]) { PROFILE(); @@ -184,50 +152,53 @@ int main(int argc, char* argv[]) Error err; Window window(context, projectData.value("window", json::object()), &err); err.Fatal("main()"); - context.AttachService(&window).Fatal("main()"); + context.AttachService(&window).Fatal("main()"); + + // Module + Module gameModule(std::filesystem::current_path() / "DucktapeProject.dll", &err); + err.Fatal("main()"); + context.AttachService(&gameModule).Fatal("main()"); // SceneManager - SceneManager sceneManager(projectData.value("sceneManager", json::object())); - context.AttachService(&sceneManager).Fatal("main()"); + SceneManager sceneManager(context, projectData.value("sceneManager", json::object())); + context.AttachService(&sceneManager).Fatal("main()"); // Renderer Renderer renderer(context, projectData.value("renderer", json::object())); - context.AttachService(&renderer).Fatal("main()"); + context.AttachService(&renderer).Fatal("main()"); #ifdef DT_EXPORT renderer.SetRenderFrameBuffer(true); #endif - // Renderer - InputManager input(context, projectData.value("input", json::object())); - context.AttachService(&input).Fatal("main()"); - + // Input + InputManager input(context); + context.AttachService(&input).Fatal("main()"); + // Scene Entity logo = sceneManager.activeScene.CreateEntity(); - sceneManager.activeScene.Require(logo, "Logo").Fatal("main()"); - sceneManager.activeScene.Require(logo, &context, projectPath / "User" / "Textures" / "logo.png").Fatal("main()"); - sceneManager.activeScene.Require(logo, 'x').Fatal("main()"); + sceneManager.activeScene.Require(logo).Fatal("main()")->name = "Logo"; + sceneManager.activeScene.Require(logo).Fatal("main()")->SetSprite(projectPath / "User" / "Textures" / "logo.png"); + // sceneManager.activeScene.Assign("TransformInspector", logo).Fatal("main()"); Entity nyan = sceneManager.activeScene.CreateEntity(); - sceneManager.activeScene.Require(nyan, "Nyan").Fatal("main()"); + sceneManager.activeScene.Require(nyan).Fatal("main()")->name = "Nyan"; sceneManager.activeScene.Require(nyan).Fatal("main()")->translation = glm::vec3(1.f, 0.f, 0.f); - sceneManager.activeScene.Require(nyan, &context, projectPath / "User" / "Textures" / "nyan.png").Fatal("main()"); - sceneManager.activeScene.Require(nyan, 'y').Fatal("main()"); + sceneManager.activeScene.Require(nyan).Fatal("main()")->SetSprite(projectPath / "User" / "Textures" / "nyan.png"); + // sceneManager.activeScene.Assign("TransformInspector", nyan).Fatal("main()"); Entity logo2 = sceneManager.activeScene.CreateEntity(); - sceneManager.activeScene.Require(logo2, "Logo 2").Fatal("main()"); + sceneManager.activeScene.Require(logo2).Fatal("main()")->name = "Logo2"; sceneManager.activeScene.Require(logo2).Fatal("main()")->translation = glm::vec3(2.f, 0.f, 0.f); - sceneManager.activeScene.Require(logo2, &context, projectPath / "User" / "Textures" / "logo.png").Fatal("main()"); - sceneManager.activeScene.Require(logo2, 'z').Fatal("main()"); + sceneManager.activeScene.Require(logo2).Fatal("main()")->SetSprite(projectPath / "User" / "Textures" / "logo.png"); + // sceneManager.activeScene.Assign("TransformInspector", logo2).Fatal("main()"); Entity camera = sceneManager.activeScene.CreateEntity(); - sceneManager.activeScene.Require(camera, "Main Camera").Fatal("main()"); - sceneManager.activeScene.Require(camera, context).Fatal("main()"); + sceneManager.activeScene.Require(camera).Fatal("main()")->name = "Main Camera"; + sceneManager.activeScene.Require(camera).Fatal("main()"); sceneManager.activeScene.Require(camera).Fatal("main()")->translation = glm::vec3(0.f, 0.f, -3.f); sceneManager.activeScene.Get(camera).Fatal("main()")->LookAt(glm::vec3(1.f, 0.f, 0.f)); sceneManager.activeScene.Require(camera).Fatal("main()"); - sceneManager.Init(context); - // Editor #ifndef DT_EXPORT Editor editor(context); @@ -250,6 +221,8 @@ int main(int argc, char* argv[]) editor.Init(context); #endif + sceneManager.Init(&context); + // Game Loop float lastTime = 0.0f; while (window.IsOpen()) @@ -273,13 +246,13 @@ int main(int argc, char* argv[]) #endif renderer.BeginScene(Camera::GetActiveCamera().get()); #ifdef DT_EXPORT - sceneManager.Tick(context, deltaTime); + sceneManager.Tick(&context, deltaTime); #endif renderer.EndScene(); #ifndef DT_EXPORT renderer.BeginScene(&worldView.editorCamera); worldView.editorCamera.Recalculate(&window); - sceneManager.EditorTick(context, deltaTime); + sceneManager.EditorTick(&context, deltaTime); renderer.EndScene(); editor.EndFrame(); #endif diff --git a/Sandbox/User/Scripts/Main.cpp b/Sandbox/User/Scripts/Main.cpp index 3d956ba2..6865be35 100644 --- a/Sandbox/User/Scripts/Main.cpp +++ b/Sandbox/User/Scripts/Main.cpp @@ -1,7 +1,34 @@ -// extern void DucktapeProjectLoader(Context &ctx) -// { -// GenericSystem playerControllerSystem; -// ctx.GetModule().AddSystem(&playerControllerSystem); -// } +#include +#include +#include +#include +using namespace DT; -// REGISTER(PlayerController); \ No newline at end of file +class TransformInspector : public Component +{ +public: + std::shared_ptr transform; + float speed = 2.5f, sensitivity = 75.f; + glm::vec3 orientation; + char dir = 'x'; + + TransformInspector(Context *ctx) {} + + void Init(Context *ctx) override + { + transform = scene->Require(entity).Fatal("TransformInspector::Init()"); + } + + void Tick(Context *ctx, const float &dt) override + { + if (dir == 'x') + orientation.x += sensitivity * dt; + if (dir == 'y') + orientation.y += sensitivity * dt; + if (dir == 'z') + orientation.z += sensitivity * dt; + transform->SetEulerRotation(orientation); + } +}; + +REGISTER_COMPONENT(TransformInspector); \ No newline at end of file