diff --git a/include/Engine/Collision/CollidableOctreeSystem.h b/include/Engine/Collision/CollidableOctreeSystem.h index c61e774c..0dcf5829 100644 --- a/include/Engine/Collision/CollidableOctreeSystem.h +++ b/include/Engine/Collision/CollidableOctreeSystem.h @@ -8,14 +8,14 @@ class CollidableOctreeSystem : public ImpureSystem, public PureSystem { public: - CollidableOctreeSystem(EventBroker* eventBroker, Octree* octree) - : System(eventBroker) + CollidableOctreeSystem(World* world, EventBroker* eventBroker, Octree* octree) + : System(world, eventBroker) , PureSystem("Collidable") , m_Octree(octree) { } - virtual void Update(World* world, double dt) override; - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; + virtual void Update(double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: Octree* m_Octree; diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index 7815254d..5f15a3d5 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -13,8 +13,8 @@ class CollisionSystem : public PureSystem { public: - CollisionSystem(EventBroker* eventBroker, Octree* octree) - : System(eventBroker) + CollisionSystem(World* world, EventBroker* eventBroker, Octree* octree) + : System(world, eventBroker) , PureSystem("Collidable") , m_Octree(octree) , zPress(false) @@ -23,7 +23,7 @@ public: EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &CollisionSystem::OnKeyUp); } - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: Octree* m_Octree; diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index 1b423e76..648c8585 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -14,8 +14,8 @@ class AABB; class TriggerSystem : public PureSystem { public: - TriggerSystem(EventBroker* eventBroker, Octree* octree) - : System(eventBroker) + TriggerSystem(World* world, EventBroker* eventBroker, Octree* octree) + : System(world, eventBroker) , PureSystem("Trigger") , m_Octree(octree) { @@ -24,7 +24,7 @@ public: EVENT_SUBSCRIBE_MEMBER(m_ELeave, &TriggerSystem::OnLeave); } - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: Octree* m_Octree; diff --git a/include/Engine/Common.h b/include/Engine/Common.h index 7d6f520d..8038b8af 100644 --- a/include/Engine/Common.h +++ b/include/Engine/Common.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "Core/Util/Logging.h" #include "Core/Util/IfDebug.h" \ No newline at end of file diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index def2a323..49ed2a3f 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -5,12 +5,14 @@ struct ComponentInfo { + typedef int EnumType; + struct Meta_t { std::string Annotation; unsigned int Allocation = 0; std::map FieldAnnotations; - std::map> FieldEnumDefinitions; + std::map> FieldEnumDefinitions; }; struct Field_t diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index b017a7eb..f09bbfe3 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -18,7 +18,7 @@ struct ComponentWrapper const ::EntityID EntityID; char* Data; - int Enum(const char* fieldName, const char* enumKey) + ComponentInfo::EnumType Enum(const char* fieldName, const char* enumKey) { return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey); } @@ -58,7 +58,7 @@ struct ComponentWrapper public: // Return the integer value of an enum type key for this field - int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); } + ComponentInfo::EnumType Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); } template operator T&() { return m_Component->Field(m_PropertyName); } diff --git a/include/Engine/Core/EKeyDown.h b/include/Engine/Core/EKeyDown.h index 3a506bf4..2745fdef 100644 --- a/include/Engine/Core/EKeyDown.h +++ b/include/Engine/Core/EKeyDown.h @@ -11,6 +11,9 @@ struct KeyDown : Event { /** GLFW key code */ int KeyCode; + bool ModCtrl; + bool ModAlt; + bool ModShift; }; } diff --git a/include/Engine/Core/EKeyUp.h b/include/Engine/Core/EKeyUp.h index c7531a01..2d34f04e 100644 --- a/include/Engine/Core/EKeyUp.h +++ b/include/Engine/Core/EKeyUp.h @@ -11,6 +11,9 @@ struct KeyUp : Event { /** GLFW key code */ int KeyCode; + bool ModCtrl; + bool ModAlt; + bool ModShift; }; } diff --git a/include/Engine/Core/EPause.h b/include/Engine/Core/EPause.h new file mode 100644 index 00000000..5aca36d8 --- /dev/null +++ b/include/Engine/Core/EPause.h @@ -0,0 +1,22 @@ +#ifndef EPause_h__ +#define EPause_h__ + +#include "EventBroker.h" +#include "World.h" + +namespace Events +{ + +struct Pause : Event +{ + ::World* World; +}; + +struct Resume : Event +{ + ::World* World; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 55b64c6f..3ba4e087 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -2,6 +2,7 @@ #define EntityWrapper_h__ #include +#include #include "ComponentWrapper.h" class World; @@ -23,10 +24,28 @@ struct EntityWrapper static const EntityWrapper Invalid; bool HasComponent(const std::string& componentName); + EntityWrapper Parent(); + bool Valid(); - ComponentWrapper operator[](const std::string& componentName); - bool operator==(const EntityWrapper& e); - explicit operator EntityID(); + ComponentWrapper operator[](const char* componentName); + bool operator==(const EntityWrapper& e) const; + bool operator!=(const EntityWrapper& e) const; + explicit operator EntityID() const; + operator bool(); }; +namespace std +{ + template<> struct hash + { + std::size_t operator()(const EntityWrapper& e) const + { + std::size_t seed = 0; + boost::hash_combine(seed, e.World); + boost::hash_combine(seed, e.ID); + return seed; + } + }; +} + #endif diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index b7de9dc2..ec57f5fc 100644 --- a/include/Engine/Core/System.h +++ b/include/Engine/Core/System.h @@ -11,14 +11,14 @@ class System friend class SystemPipeline; protected: - System() - : m_EventBroker(nullptr) - { } - System(EventBroker* eventBroker) - : m_EventBroker(eventBroker) + System(World* world, EventBroker) { } + System(World* world, EventBroker* eventBroker) + : m_World(world) + , m_EventBroker(eventBroker) { } virtual ~System() = default; + World* m_World; EventBroker* m_EventBroker; }; @@ -34,7 +34,7 @@ protected: const std::string m_ComponentType; - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) = 0; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) = 0; }; class ImpureSystem : public virtual System @@ -45,7 +45,7 @@ protected: ImpureSystem() = default; virtual ~ImpureSystem() = default; - virtual void Update(World* world, double dt) = 0; + virtual void Update(double dt) = 0; }; #endif \ No newline at end of file diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h index c0cd8ed6..90303f12 100644 --- a/include/Engine/Core/SystemPipeline.h +++ b/include/Engine/Core/SystemPipeline.h @@ -5,13 +5,19 @@ #include "EventBroker.h" #include "System.h" #include "World.h" +#include "EPause.h" class SystemPipeline { public: - SystemPipeline(EventBroker* eventBroker) - : m_EventBroker(eventBroker) - { } + SystemPipeline(World* world, EventBroker* eventBroker) + : m_World(world) + , m_EventBroker(eventBroker) + { + EVENT_SUBSCRIBE_MEMBER(m_EPause, &SystemPipeline::OnPause); + EVENT_SUBSCRIBE_MEMBER(m_EResume, &SystemPipeline::OnResume); + } + ~SystemPipeline() { for (UnorderedSystems& group : m_OrderedSystemGroups) { @@ -29,7 +35,7 @@ public: m_OrderedSystemGroups.resize(updateOrderLevel + 1); } UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel]; - System* system = new T(m_EventBroker, args...); + System* system = new T(m_World, m_EventBroker, args...); group.Systems[typeid(T).name()] = system; PureSystem* pureSystem = dynamic_cast(system); @@ -47,8 +53,12 @@ public: } } - void Update(World* world, double dt) + void Update(double dt) { + if (m_Paused) { + dt = 0.0; + } + for (UnorderedSystems& group : m_OrderedSystemGroups) { // Process events for (auto& pair : group.Systems) { @@ -57,18 +67,18 @@ public: // Update for (auto& system : group.ImpureSystems) { - system->Update(world, dt); + system->Update(dt); } for (auto& pair : group.PureSystems) { const std::string& componentName = pair.first; auto& systems = pair.second; - const ComponentPool* pool = world->GetComponents(componentName); + const ComponentPool* pool = m_World->GetComponents(componentName); if (pool == nullptr) { continue; } for (auto& component : *pool) { for (auto& system : systems) { - system->UpdateComponent(world, EntityWrapper(world, component.EntityID), component, dt); + system->UpdateComponent(EntityWrapper(m_World, component.EntityID), component, dt); } } } @@ -76,7 +86,10 @@ public: } private: + World* m_World; EventBroker* m_EventBroker; + bool m_Paused = false; + struct UnorderedSystems { std::map Systems; @@ -84,6 +97,21 @@ private: std::vector ImpureSystems; }; std::vector m_OrderedSystemGroups; + + EventRelay m_EPause; + bool OnPause(const Events::Pause& e) { + if (e.World == m_World) { + m_Paused = true; + } + return true; + } + EventRelay m_EResume; + bool OnResume(const Events::Resume& e) { + if (e.World == m_World) { + m_Paused = false; + } + return true; + } }; #endif \ No newline at end of file diff --git a/include/Engine/Core/UniformScaleSystem.h b/include/Engine/Core/UniformScaleSystem.h new file mode 100644 index 00000000..0ebc0672 --- /dev/null +++ b/include/Engine/Core/UniformScaleSystem.h @@ -0,0 +1,22 @@ +#ifndef UniformScaleSystem_h__ +#define UniformScaleSystem_h__ + +#include "../GLM.h" +#include "System.h" +#include "../Rendering/ESetCamera.h" + +class UniformScaleSystem : public PureSystem +{ +public: + UniformScaleSystem(World* world, EventBroker* eventBroker); + + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cUniformScale, double dt) override; + +private: + EntityWrapper m_Camera = EntityWrapper::Invalid; + + EventRelay m_ESetCamera; + bool OnSetCamera(const Events::SetCamera& e); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Editor/EditorGUI.h b/include/Engine/Editor/EditorGUI.h new file mode 100644 index 00000000..973f6a90 --- /dev/null +++ b/include/Engine/Editor/EditorGUI.h @@ -0,0 +1,153 @@ +#ifndef EditorGUI_h__ +#define EditorGUI_h__ + +#include +#define IMGUI_DEFINE_MATH_OPERATORS +#include +#include +#include +#include +#include "../Common.h" +#include "../GLM.h" +#include + +#include "EditorWidgetSystem.h" +#include "../Core/EventBroker.h" +#include "../Core/World.h" +#include "../Core/EntityWrapper.h" +#include "../Core/ResourceManager.h" +#include "../Core/EPause.h" +#include "../Core/EKeyDown.h" +#include "../Rendering/Texture.h" + +class EditorGUI +{ +public: + EditorGUI(World* world, EventBroker* eventBroker); + + enum class WidgetMode + { + Translate, + Rotate, + Scale + }; + + void Draw(); + + void SelectEntity(EntityWrapper entity); + void SetDirty(EntityWrapper entity); + + // Called when an entity is selected in the entity tree + typedef std::function OnEntitySelectedCallback_t; + void SetEntitySelectedCallback(OnEntitySelectedCallback_t f) { m_OnEntitySelected = f; } + // Called when the user means to import an entity file. + // @param EntityWrapper The entity to parent the imported entity to. The entity will be imported into the world of this entity. + // @param boost::filesystem::path The path to the entity to import + // @return EntityWrapper The newly created entity + typedef std::function OnEntityImport_t; + void SetEntityImportCallback(OnEntityImport_t f) { m_OnEntityImport = f; } + // Called when the user means to save an entity to file. + // Permitted to throw exceptions on save failure. + typedef std::function OnEntitySave_t; + void SetEntitySaveCallback(OnEntitySave_t f) { m_OnEntitySave = f; } + // Called when the user means to create a new entity. + // @param EntityWrapper The parent of the entity to be created + // @return EntityWrapper The newly created entity + typedef std::function OnEntityCreate_t; + void SetEntityCreateCallback(OnEntityCreate_t f) { m_OnEntityCreate = f; } + // Called when the user means to delete an entity. + typedef std::function OnEntityDelete_t; + void SetEntityDeleteCallback(OnEntityDelete_t f) { m_OnEntityDelete = f; } + // Called when the user means to change the parent of an entity. + typedef std::function OnEntityChangeParent_t; + void SetEntityChangeParentCallback(OnEntityChangeParent_t f) { m_OnEntityChangeParent = f; } + // Called when the user means to rename an entity. + typedef std::function OnEntityChangeName_t; + void SetEntityChangeNameCallback(OnEntityChangeName_t f) { m_OnEntityChangeName = f; } + // Called when the user means to attach a new component to an entity. + typedef std::function OnComponentAttach_t; + void SetComponentAttachCallback(OnComponentAttach_t f) { m_OnComponentAttach = f; } + // Called when the user means to delete a component off an entity. + typedef std::function OnComponentDelete_t; + void SetComponentDeleteCallback(OnComponentDelete_t f) { m_OnComponentDelete = f; } + // Called when the user selects a widget mode. + typedef std::function OnWidgetMode_t; + void SetWidgetModeCallback(OnWidgetMode_t f) { m_OnWidgetMode = f; } + +private: + World* m_World; + EventBroker* m_EventBroker; + + struct EntityFileInfo + { + boost::filesystem::path Path; + bool Dirty = false; + }; + + // Config variables + const boost::filesystem::path m_DefaultEntityPath = boost::filesystem::path("Schema") / boost::filesystem::path("Entities"); + + // State + EntityWrapper m_CurrentSelection = EntityWrapper::Invalid; + std::unordered_map m_EntityFiles; + EntityWrapper m_CurrentlyDragging = EntityWrapper::Invalid; + std::string m_LastErrorMessage; + WidgetMode m_CurrentWidgetMode = WidgetMode::Translate; + std::set m_ModalsToOpen; + std::map m_ModalData; + + // Callbacks + OnEntitySelectedCallback_t m_OnEntitySelected = nullptr; + OnEntityImport_t m_OnEntityImport = nullptr; + OnEntitySave_t m_OnEntitySave = nullptr; + OnEntityCreate_t m_OnEntityCreate = nullptr; + OnEntityDelete_t m_OnEntityDelete = nullptr; + OnEntityChangeParent_t m_OnEntityChangeParent = nullptr; + OnEntityChangeName_t m_OnEntityChangeName = nullptr; + OnComponentAttach_t m_OnComponentAttach = nullptr; + OnComponentDelete_t m_OnComponentDelete = nullptr; + OnWidgetMode_t m_OnWidgetMode = nullptr; + + // Events + EventRelay m_EKeyDown; + bool OnKeyDown(const Events::KeyDown& e); + + // Utility functions + boost::filesystem::path fileOpenDialog(); + boost::filesystem::path fileSaveDialog(); + const std::string formatEntityName(EntityWrapper entity); + GLuint tryLoadTexture(std::string filePath); + void openModal(const std::string& modal); + + // Entity file handling methods + void entityImport(World* world); + void entitySave(EntityWrapper entity, bool saveAs = false); + void entityCreate(World* world, EntityWrapper parent); + void entityDelete(EntityWrapper entity); + void entityChangeParent(EntityWrapper entity, EntityWrapper parent); + + // UI drawing methods + void drawMenu(); + void drawTools(); + void drawEntities(World* world); + void drawEntitiesRecursive(World* world, EntityID parent); + bool drawEntityNode(EntityWrapper entity); + void drawComponents(EntityWrapper entity); + bool drawComponentNode(EntityWrapper entity, const ComponentInfo& componentType); + bool drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field); + bool drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field); + bool drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field); + void drawModals(); + + // Custom UI elements + bool createDeleteButton(const std::string& componentType); + void createWidgetToolButton(WidgetMode mode); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Editor/EditorRenderSystem.h b/include/Engine/Editor/EditorRenderSystem.h new file mode 100644 index 00000000..361669ba --- /dev/null +++ b/include/Engine/Editor/EditorRenderSystem.h @@ -0,0 +1,27 @@ +#ifndef EditorRenderSystem_h__ +#define EditorRenderSystem_h__ + +#include "../Core/System.h" +#include "../Rendering/IRenderer.h" +#include "../Rendering/ModelJob.h" +#include "../Rendering/Camera.h" +#include "../Rendering/ESetCamera.h" + +class EditorRenderSystem : public ImpureSystem +{ +public: + EditorRenderSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame); + + virtual void Update(double dt) override; + +private: + IRenderer* m_Renderer; + RenderFrame* m_RenderFrame; + Camera* m_EditorCamera; + EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; + + EventRelay m_ESetCamera; + bool OnSetCamera(Events::SetCamera& e); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Editor/EditorStats.h b/include/Engine/Editor/EditorStats.h new file mode 100644 index 00000000..5dfa5378 --- /dev/null +++ b/include/Engine/Editor/EditorStats.h @@ -0,0 +1,29 @@ +#include +#include +#include +#include "../Common.h" +#include "../GLM.h" +#include "../OpenGL.h" + +class EditorStats +{ +public: + EditorStats(); + void Draw(double dt); + +private: + // FPS graph + const unsigned int m_SampleSize = 100; + unsigned int m_FrameCount = 0; + std::vector m_FrameTimes; + double m_TimeAccumulator = 0.0; + double m_AveragedSamplesPerSecond = 10.0; + const unsigned int m_AveragedSampleSize = 100; + unsigned int m_CurrentAveragedSampleIndex = 0; + std::vector m_AveragedSamples; + void drawFPSGraph(double dt); + + void drawRAMUsage(double dt); + + void drawVRAMStats(double dt); +}; diff --git a/include/Engine/Editor/EditorSystem.h b/include/Engine/Editor/EditorSystem.h index 05e106d9..befa46b6 100644 --- a/include/Engine/Editor/EditorSystem.h +++ b/include/Engine/Editor/EditorSystem.h @@ -1,94 +1,59 @@ -#include -#include -#include -#include #include "../Core/System.h" -#include "../Core/EMousePress.h" -#include "../Core/EMouseRelease.h" -#include "../Core/EMouseMove.h" -#include "../Core/ConfigFile.h" -#include "../Input/EInputCommand.h" #include "../Rendering/IRenderer.h" -#include "../Core/Transform.h" -#include "../Core/EFileDropped.h" +#include "../Rendering/Camera.h" +#include "../Rendering/DebugCameraInputController.h" +#include "../Rendering/ESetCamera.h" +#include "../Core/World.h" +#include "../Core/SystemPipeline.h" +#include "../Core/ResourceManager.h" #include "../Core/EntityFilePreprocessor.h" #include "../Core/EntityFileParser.h" #include "../Core/EntityFileWriter.h" +#include "../Core/EMouseRelease.h" +#include "EditorGUI.h" +#include "EditorStats.h" class EditorSystem : public ImpureSystem { public: - EditorSystem(EventBroker* eventBroker, IRenderer* renderer); + EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame); + ~EditorSystem(); - virtual void Update(World* world, double dt) override; + void Update(double dt); private: IRenderer* m_Renderer; - World* m_World = nullptr; - Camera* m_Camera = nullptr; + RenderFrame* m_RenderFrame; + World* m_EditorWorld; + SystemPipeline* m_EditorWorldSystemPipeline; + Camera* m_EditorCamera; + EntityWrapper m_Camera = EntityWrapper::Invalid; + DebugCameraInputController* m_DebugCameraInputController; + EditorGUI* m_EditorGUI; + EditorStats* m_EditorStats; - bool m_Enabled; - bool m_Visible; - boost::filesystem::path m_DefaultEntityDir; - boost::filesystem::path m_CurrentFile; - std::vector m_PickingQueue; + // State + EditorGUI::WidgetMode m_WidgetMode = EditorGUI::WidgetMode::Translate; + EntityWrapper m_Widget = EntityWrapper::Invalid; + EntityWrapper m_CurrentSelection = EntityWrapper::Invalid; - enum class WidgetMode - { - None, - Translate, - Rotate, - Scale - } m_WidgetMode = WidgetMode::None; + // Utility functions + EntityWrapper importEntity(EntityWrapper parent, boost::filesystem::path filePath); + void setWidgetMode(EditorGUI::WidgetMode mode); - enum class WidgetSpace - { - Local, - Global - } m_WidgetSpace = WidgetSpace::Global; + // GUI callbacks + void OnEntitySelected(EntityWrapper entity); + void OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath); + EntityWrapper OnEntityCreate(EntityWrapper parent); + void OnEntityDelete(EntityWrapper entity); + void OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent); + void OnEntityChangeName(EntityWrapper entity, const std::string& name); + void OnComponentAttach(EntityWrapper entity, const std::string& componentType); + void OnComponentDelete(EntityWrapper entity, const std::string& componentType); - EntityID m_Widget = EntityID_Invalid; - EntityID m_WidgetX = EntityID_Invalid; - EntityID m_WidgetPlaneX = EntityID_Invalid; - EntityID m_WidgetY = EntityID_Invalid; - EntityID m_WidgetPlaneY = EntityID_Invalid; - EntityID m_WidgetZ = EntityID_Invalid; - EntityID m_WidgetPlaneZ = EntityID_Invalid; - EntityID m_WidgetOrigin = EntityID_Invalid; - glm::vec3 m_WidgetCurrentAxis; - float m_WidgetPickingDepth = 0.f; - glm::vec3 m_WidgetPickingPosition = glm::vec3(0); - - EntityID m_Selection = EntityID_Invalid; - EntityID m_LastSelection = EntityID_Invalid; - EntityID m_UIDraggingEntity = EntityID_Invalid; - glm::vec3 m_Position; - std::string m_LastDroppedFile; - - static boost::filesystem::path openDialog(boost::filesystem::path defaultPath); - static boost::filesystem::path saveDialog(boost::filesystem::path defaultPath); - - EventRelay m_EInputCommand; - bool OnInputCommand(const Events::InputCommand& e); + // Events EventRelay m_EMouseRelease; bool OnMouseRelease(const Events::MouseRelease& e); - EventRelay m_EMousePress; - bool OnMousePress(const Events::MousePress& e); - EventRelay m_EMouseMove; - bool OnMouseMove(const Events::MouseMove& e); - EventRelay m_EFileDropped; - bool OnFileDropped(const Events::FileDropped& e); - - void Picking(); - void createWidget(); - void updateWidget(); - void setWidgetMode(WidgetMode newMode); - void setWidgetSpace(WidgetSpace space); - void drawUI(World* world, double dt); - bool createDeleteButton(std::string componentType); - bool createEntityNode(World* world, EntityID entity); - void changeParent(EntityID entity, EntityID newParent); - void fileImport(World* world); - void fileSave(World* world); - void fileSaveAs(World* world); + EventRelay m_EWidgetDelta; + bool OnWidgetDelta(const Events::WidgetDelta& e); }; \ No newline at end of file diff --git a/include/Engine/Editor/EditorWidgetSystem.h b/include/Engine/Editor/EditorWidgetSystem.h new file mode 100644 index 00000000..a060bdd5 --- /dev/null +++ b/include/Engine/Editor/EditorWidgetSystem.h @@ -0,0 +1,49 @@ +#ifndef EditorWidgetSystem_h__ +#define EditorWidgetSystem_h__ + +#include +#include "../GLM.h" +#include "../Core/System.h" +#include "../Rendering/IRenderer.h" +#include "../Rendering/Util/ScreenCoords.h" +#include "../Core/EMouseMove.h" +#include "../Core/EMousePress.h" +#include "../Core/EMouseRelease.h" + +namespace Events +{ + +struct WidgetDelta : Event +{ + glm::vec3 Translation; + glm::vec3 Rotation; + glm::vec3 Scale; +}; + +} + +class EditorWidgetSystem : public ImpureSystem, PureSystem +{ +public: + EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer); + + virtual void Update(double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cEditorWidget, double dt) override; + +private: + IRenderer* m_Renderer; + + // State + EntityWrapper m_PickEntity = EntityWrapper::Invalid; + PickData m_PickData; + glm::vec2 m_MouseDelta; + + EventRelay m_EMouseMove; + bool OnMouseMove(const Events::MouseMove& e); + EventRelay m_EMousePress; + bool OnMousePress(const Events::MousePress& e); + EventRelay m_EMouseRelease; + bool OnMouseRelease(const Events::MouseRelease& e); +}; + +#endif diff --git a/include/Engine/GLM.h b/include/Engine/GLM.h index 32729845..3143c905 100644 --- a/include/Engine/GLM.h +++ b/include/Engine/GLM.h @@ -7,4 +7,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/include/Engine/Rendering/Camera.h b/include/Engine/Rendering/Camera.h index 2b863448..29dd4626 100644 --- a/include/Engine/Rendering/Camera.h +++ b/include/Engine/Rendering/Camera.h @@ -2,6 +2,7 @@ #define Camera_h__ #include "../GLM.h" +#include "../Core/Util/Rectangle.h" class Camera { @@ -32,7 +33,6 @@ public: glm::mat4 ViewMatrix() const { return m_ViewMatrix; } void SetViewMatrix(glm::mat4 val); - float AspectRatio() const { return m_AspectRatio; } void SetAspectRatio(float val); @@ -48,6 +48,8 @@ public: void UpdateViewMatrix(); void UpdateProjectionMatrix(); + glm::vec2 WorldToScreen(glm::vec3 worldCoord, Rectangle resolution); + private: glm::vec3 m_Position; diff --git a/include/Engine/Rendering/DebugCameraInputController.h b/include/Engine/Rendering/DebugCameraInputController.h index 4d74e288..5ce85b3f 100644 --- a/include/Engine/Rendering/DebugCameraInputController.h +++ b/include/Engine/Rendering/DebugCameraInputController.h @@ -1,5 +1,10 @@ +#ifndef DebugCameraInputController_h__ +#define DebugCameraInputController_h__ + #include #include "../Input/FirstPersonInputController.h" +#include "../Core/EMousePress.h" +#include "../Core/EMouseRelease.h" template class DebugCameraInputController : public FirstPersonInputController @@ -7,7 +12,10 @@ class DebugCameraInputController : public FirstPersonInputController 0) { - if (!io.WantCaptureMouse) { - LockMouse(); - } - } else { - UnlockMouse(); - } - return false; - } - if (!io.WantCaptureKeyboard) { if (e.Command == "Right") { float value = std::max(-1.f, std::min(e.Value, 1.f)); @@ -63,4 +60,25 @@ protected: glm::vec3 m_Velocity = glm::vec3(0, 0, 0); float m_BaseSpeed = 2.0f; float m_Speed = m_BaseSpeed; -}; \ No newline at end of file + EventRelay m_EMousePress; + bool OnMousePress(const Events::MousePress& e) + { + if (e.Button == GLFW_MOUSE_BUTTON_2) { + ImGuiIO& io = ImGui::GetIO(); + if (!io.WantCaptureMouse) { + LockMouse(); + } + } + return true; + } + EventRelay m_EMouseRelease; + bool OnMouseRelease(const Events::MouseRelease& e) + { + if (e.Button == GLFW_MOUSE_BUTTON_2) { + UnlockMouse(); + } + return true; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/DrawFinalPass.h b/include/Engine/Rendering/DrawFinalPass.h index 52876592..20c7249d 100644 --- a/include/Engine/Rendering/DrawFinalPass.h +++ b/include/Engine/Rendering/DrawFinalPass.h @@ -32,7 +32,6 @@ private: const LightCullingPass* m_LightCullingPass; ShaderProgram* m_ForwardPlusProgram; - }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/DrawScenePass.h b/include/Engine/Rendering/DrawScenePass.h deleted file mode 100644 index ca2463cf..00000000 --- a/include/Engine/Rendering/DrawScenePass.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef DrawScenePass_h__ -#define DrawScenePass_h__ - -#include "IRenderer.h" -#include "DrawScenePassState.h" -#include "FrameBuffer.h" -#include "ShaderProgram.h" -#include "Util/UnorderedMapVec2.h" -#include "Texture.h" - -class DrawScenePass -{ -public: - DrawScenePass(IRenderer* renderer); - ~DrawScenePass() { } - void InitializeTextures(); - void InitializeFrameBuffers(); - void InitializeShaderPrograms(); - - void Draw(RenderScene& scene); - - //Getters - - -private: - void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const; - - static bool DepthSort(const std::shared_ptr &i, const std::shared_ptr &j) - { - return (i->Depth < j->Depth); - }; - - Texture* m_WhiteTexture; - - const IRenderer* m_Renderer; - - ShaderProgram* m_BasicForwardProgram; - - -}; - -#endif \ No newline at end of file diff --git a/include/Engine/Rendering/DrawScenePassState.h b/include/Engine/Rendering/DrawScenePassState.h deleted file mode 100644 index 7ce74006..00000000 --- a/include/Engine/Rendering/DrawScenePassState.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef DrawScenePassState_h__ -#define DrawScenePassState_h__ - -#include "Rendering/RenderState.h" - -class DrawScenePassState : public RenderState -{ -public: - DrawScenePassState(); - ~DrawScenePassState(); -private: - -}; - -#endif \ No newline at end of file diff --git a/include/Engine/Rendering/ESetCamera.h b/include/Engine/Rendering/ESetCamera.h index 650f3b12..1b39e890 100644 --- a/include/Engine/Rendering/ESetCamera.h +++ b/include/Engine/Rendering/ESetCamera.h @@ -2,20 +2,14 @@ #define Events_SetCamera_h__ #include "../Core/EventBroker.h" -#include "../Core/Entity.h" -#include +#include "../Core/EntityWrapper.h" namespace Events { struct SetCamera : Event { -public: - SetCamera() { }; - std::string Name; - -private: - + EntityWrapper CameraEntity; }; } diff --git a/include/Engine/Rendering/IRenderer.h b/include/Engine/Rendering/IRenderer.h index 95053a85..6ef189f4 100644 --- a/include/Engine/Rendering/IRenderer.h +++ b/include/Engine/Rendering/IRenderer.h @@ -31,15 +31,6 @@ public: void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; } bool VSYNC() const { return m_VSYNC; } void SetVSYNC(bool vsync) { m_VSYNC = vsync; } - ::Camera* Camera() const { return m_Camera; } - void SetCamera(::Camera* camera) - { - if (camera == nullptr) { - m_Camera = m_DefaultCamera; - } else { - m_Camera = camera; - } - } virtual void Initialize() = 0; virtual void Update(double dt) = 0; virtual void Draw(RenderFrame& rq) = 0; @@ -54,8 +45,6 @@ protected: int m_GLVersion[2]; std::string m_GLVendor; GLFWwindow* m_Window = nullptr; - ::Camera* m_DefaultCamera; - ::Camera* m_Camera = nullptr; }; #endif // Renderer_h__ diff --git a/include/Engine/Rendering/RenderJob.h b/include/Engine/Rendering/RenderJob.h index 4afe0386..bcffc4a5 100644 --- a/include/Engine/Rendering/RenderJob.h +++ b/include/Engine/Rendering/RenderJob.h @@ -14,7 +14,6 @@ struct RenderJob friend class RenderQueue; public: - float Depth; protected: diff --git a/include/Engine/Rendering/RenderQueue.h b/include/Engine/Rendering/RenderQueue.h index 8df967ac..e42cc8dc 100644 --- a/include/Engine/Rendering/RenderQueue.h +++ b/include/Engine/Rendering/RenderQueue.h @@ -51,11 +51,12 @@ struct PointLightJob : RenderJob struct RenderScene { - ::Camera* Camera; + ::Camera* Camera = nullptr; std::list> ForwardJobs; std::list> PointLightJobs; std::list> DirectionalLightJobs; Rectangle Viewport; + bool ClearDepth = false; void Clear() { diff --git a/include/Engine/Rendering/RenderState.h b/include/Engine/Rendering/RenderState.h index c6eb8775..688ef520 100644 --- a/include/Engine/Rendering/RenderState.h +++ b/include/Engine/Rendering/RenderState.h @@ -16,10 +16,10 @@ public: bool Disable(GLenum cap); bool CullFace(GLenum mode); bool ClearColor(glm::vec4 color); - bool Clear(GLbitfield mask); bool BindFramebuffer(GLint framebuffer); bool BlendEquation(GLenum mode); bool BlendFunc(GLenum sfactor, GLenum dfactor); + bool DepthMask(GLboolean flag); private: std::vector> m_ResetFunctions; diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index 966593db..003e308e 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -20,37 +20,26 @@ class RenderSystem : public ImpureSystem { public: - RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame); + RenderSystem(World* world, EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame); ~RenderSystem(); - virtual void Update(World* world, double dt) override; + virtual void Update(double dt) override; private: - World* m_World = nullptr; const IRenderer* m_Renderer; - RenderFrame* m_RenderFrame; - bool m_SwitchCamera = false; Camera* m_Camera; - DebugCameraInputController* m_DebugCameraInputController; - - std::list m_CameraComponents; + EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; EventRelay m_ESetCamera; - bool OnSetCamera(const Events::SetCamera &event); - EntityID m_CurrentCamera = EntityID_Invalid; - - void switchCamera(EntityID entity); - - void updateCamera(World* world, double dt); - void updateProjectionMatrix(ComponentWrapper& cameraComponent); - - void fillModels(std::list>& jobs, World* world); + bool OnSetCamera(Events::SetCamera &event); void fillPointLights(std::list>& jobs, World* world); void fillDirectionalLights(std::list>& jobs, World* world); - EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); + + void fillModels(std::list>& jobs); + void fillLight(std::list>& jobs); }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/Renderer.h b/include/Engine/Rendering/Renderer.h index 0006cca1..cc9599d3 100644 --- a/include/Engine/Rendering/Renderer.h +++ b/include/Engine/Rendering/Renderer.h @@ -11,7 +11,6 @@ #include "FrameBuffer.h" #include "../Core/World.h" #include "PickingPass.h" -#include "DrawScenePass.h" #include "LightCullingPass.h" #include "DrawFinalPass.h" #include "../Core/EventBroker.h" @@ -43,7 +42,6 @@ private: Model* m_UnitQuad; Model* m_UnitSphere; - DrawScenePass* m_DrawScenePass; PickingPass* m_PickingPass; LightCullingPass* m_LightCullingPass; ImGuiRenderPass* m_ImGuiRenderPass; diff --git a/include/Game/Systems/CapturePointSystem.h b/include/Game/Systems/CapturePointSystem.h index 3fac1326..3b459c40 100644 --- a/include/Game/Systems/CapturePointSystem.h +++ b/include/Game/Systems/CapturePointSystem.h @@ -17,10 +17,10 @@ class CapturePointSystem : public PureSystem { public: //WARNING: on new map, destroy all info in the vectors, as well as reset all variables (just make new?) - CapturePointSystem(EventBroker* eventBroker); + CapturePointSystem(World* world, EventBroker* eventBroker); //updatecomponent - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) override; private: //methods which will take care of specific events diff --git a/include/Game/Systems/HealthSystem.h b/include/Game/Systems/HealthSystem.h index 0db3ec41..f9843f11 100644 --- a/include/Game/Systems/HealthSystem.h +++ b/include/Game/Systems/HealthSystem.h @@ -16,10 +16,10 @@ class HealthSystem : public PureSystem { public: - HealthSystem(EventBroker* eventBroker); + HealthSystem(World* world, EventBroker* eventBroker); //updatecomponent - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: //methods which will take care of specific events diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h index fb7654b2..4b05571b 100644 --- a/include/Game/Systems/InterpolationSystem.h +++ b/include/Game/Systems/InterpolationSystem.h @@ -25,14 +25,14 @@ class InterpolationSystem : public PureSystem double interpolationTime; }; public: - InterpolationSystem(EventBroker* eventBroker) - : System(eventBroker) + InterpolationSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) , PureSystem("Transform") { EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); } ~InterpolationSystem() { } - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& transform, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override; private: std::unordered_map m_NextTransform; std::unordered_map m_LastReceivedTransform; diff --git a/include/Game/Systems/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h index 6dc2dc31..1be61bdd 100644 --- a/include/Game/Systems/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -5,10 +5,10 @@ class PlayerMovementSystem : public PureSystem { public: - PlayerMovementSystem(EventBroker* eventBroker) - : System(eventBroker) + PlayerMovementSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) , PureSystem("Player") { } - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt); + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt); }; \ No newline at end of file diff --git a/include/Game/Systems/PlayerSpawnSystem.h b/include/Game/Systems/PlayerSpawnSystem.h index f0e10949..8ade03a6 100644 --- a/include/Game/Systems/PlayerSpawnSystem.h +++ b/include/Game/Systems/PlayerSpawnSystem.h @@ -6,9 +6,9 @@ class PlayerSpawnSystem : public ImpureSystem { public: - PlayerSpawnSystem(EventBroker* eventBroker); + PlayerSpawnSystem(World* world, EventBroker* eventBroker); - virtual void Update(World* world, double dt) override; + virtual void Update(double dt) override; private: EventRelay m_OnInputCommand; diff --git a/include/Game/Systems/RaptorCopterSystem.h b/include/Game/Systems/RaptorCopterSystem.h index 57a8de86..8bb18de6 100644 --- a/include/Game/Systems/RaptorCopterSystem.h +++ b/include/Game/Systems/RaptorCopterSystem.h @@ -4,14 +4,14 @@ class RaptorCopterSystem : public PureSystem { public: - RaptorCopterSystem(EventBroker* eventBroker) - : System(eventBroker) + RaptorCopterSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) , PureSystem("RaptorCopter") { } - virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override { - ComponentWrapper& transform = world->GetComponent(component.EntityID, "Transform"); + ComponentWrapper& transform = m_World->GetComponent(component.EntityID, "Transform"); (glm::vec3&)transform["Orientation"] += (float)(double)component["Speed"] * (float)dt * (glm::vec3)component["Axis"]; } }; \ No newline at end of file diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h index 2c094528..62f6b09a 100644 --- a/include/Game/Systems/SpawnerSystem.h +++ b/include/Game/Systems/SpawnerSystem.h @@ -13,7 +13,7 @@ class SpawnerSystem : public System { public: - SpawnerSystem(EventBroker* eventBroker); + SpawnerSystem(World* world, EventBroker* eventBroker); static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid); diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index bed93c1f..0b5ba629 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -20,4 +20,6 @@ + + \ No newline at end of file diff --git a/resources/Schema/Components/Camera.xml b/resources/Schema/Components/Camera.xml index ccb12f01..b9c28d53 100644 --- a/resources/Schema/Components/Camera.xml +++ b/resources/Schema/Components/Camera.xml @@ -1,6 +1,5 @@ - cam 45 0.01 5000 diff --git a/resources/Schema/Components/Camera.xsd b/resources/Schema/Components/Camera.xsd index 2b896c74..1bde2333 100644 --- a/resources/Schema/Components/Camera.xsd +++ b/resources/Schema/Components/Camera.xsd @@ -9,7 +9,6 @@ - Vertical Field of View in degrees diff --git a/resources/Schema/Components/EditorWidget.xml b/resources/Schema/Components/EditorWidget.xml new file mode 100644 index 00000000..fed2f809 --- /dev/null +++ b/resources/Schema/Components/EditorWidget.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/EditorWidget.xsd b/resources/Schema/Components/EditorWidget.xsd new file mode 100644 index 00000000..3d08e82e --- /dev/null +++ b/resources/Schema/Components/EditorWidget.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Components/Physics.xsd b/resources/Schema/Components/Physics.xsd index cc5e24bb..72037f48 100644 --- a/resources/Schema/Components/Physics.xsd +++ b/resources/Schema/Components/Physics.xsd @@ -9,7 +9,9 @@ - + + m/s^2 + diff --git a/resources/Schema/Components/PointLight.xsd b/resources/Schema/Components/PointLight.xsd index 9b802d8c..25d0aa07 100644 --- a/resources/Schema/Components/PointLight.xsd +++ b/resources/Schema/Components/PointLight.xsd @@ -12,7 +12,7 @@ - + diff --git a/resources/Schema/Components/UniformScale.xml b/resources/Schema/Components/UniformScale.xml new file mode 100755 index 00000000..0eed72d4 --- /dev/null +++ b/resources/Schema/Components/UniformScale.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/Schema/Components/UniformScale.xsd b/resources/Schema/Components/UniformScale.xsd new file mode 100755 index 00000000..cbd218ea --- /dev/null +++ b/resources/Schema/Components/UniformScale.xsd @@ -0,0 +1,16 @@ + + + + + + + + Keeps an entity at an uniform scale relative to the camera + + + + + + + + diff --git a/resources/Schema/Entities/EditorWidgetRotate.xml b/resources/Schema/Entities/EditorWidgetRotate.xml new file mode 100644 index 00000000..b918794e --- /dev/null +++ b/resources/Schema/Entities/EditorWidgetRotate.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + Models/RotationWidgetX.obj + + + + + + + + + + + + + + + Models/RotationWidgetY.obj + + + + + + + + + + + + + + + Models/RotationWidgetZ.obj + + + + + + + + + -1 + 0 + + + + + + + + diff --git a/resources/Schema/Entities/EditorWidgetScale.xml b/resources/Schema/Entities/EditorWidgetScale.xml new file mode 100644 index 00000000..15bcb38b --- /dev/null +++ b/resources/Schema/Entities/EditorWidgetScale.xml @@ -0,0 +1,68 @@ + + + + + + Models/ScaleWidgetOrigin.obj + + + + + + + + + + + + + + + + + Models/ScaleWidgetX.obj + + + + + + + + + + + + + + Models/ScaleWidgetY.obj + + + + + + + + + + + + + + Models/ScaleWidgetZ.obj + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/EditorWidgetTranslate.xml b/resources/Schema/Entities/EditorWidgetTranslate.xml new file mode 100644 index 00000000..a9b7eaff --- /dev/null +++ b/resources/Schema/Entities/EditorWidgetTranslate.xml @@ -0,0 +1,98 @@ + + + + + + Models/TranslationWidgetOrigin.obj + + + + + + + + + + + + + + + Models/TranslationWidgetX.obj + + + + + + + + + + + + Models/TranslationWidgetY.obj + + + + + + + + + + + + Models/TranslationWidgetZ.obj + + + + + + + + + + + + Models/WidgetPlaneX.obj + + + + + + + + + + + + Models/WidgetPlaneY.obj + + + + + + + + + + + + Models/WidgetPlaneZ.obj + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index d2838ae9..42e2660e 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -9,12 +9,11 @@ Models/DummyScene.obj - - + @@ -24,4 +23,6 @@ + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index b37692a9..2f9e5184 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -29,6 +29,8 @@ + + @@ -39,9 +41,7 @@ - - diff --git a/src/Engine/Collision/CollidableOctreeSystem.cpp b/src/Engine/Collision/CollidableOctreeSystem.cpp index 62d742f5..e5da7910 100644 --- a/src/Engine/Collision/CollidableOctreeSystem.cpp +++ b/src/Engine/Collision/CollidableOctreeSystem.cpp @@ -1,11 +1,11 @@ #include "Collision/CollidableOctreeSystem.h" -void CollidableOctreeSystem::Update(World* world, double dt) +void CollidableOctreeSystem::Update(double dt) { m_Octree->ClearDynamicObjects(); } -void CollidableOctreeSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) +void CollidableOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { if (entity.HasComponent("AABB")) { boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index a9d125ac..0c77c306 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -2,7 +2,7 @@ #include "Collision/CollisionSystem.h" #include "Core/AABB.h" -void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) +void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { if (!entity.HasComponent("Physics")) { return; diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index b398b091..ca169e16 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -3,10 +3,10 @@ #include "Core/AABB.h" #include "Rendering/Model.h" -void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) +void TriggerSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { //Currently only players can trigger things. - auto players = world->GetComponents("Player"); + auto players = m_World->GetComponents("Player"); if (players == nullptr) { return; } @@ -18,7 +18,7 @@ void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, Compone } for (auto& pc : *players) { EntityID pId = pc.EntityID; - boost::optional playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(world, pId)); + boost::optional playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(m_World, pId)); //The player can't trigger anything without an AABB. if (!playerBox) { continue; diff --git a/src/Engine/Core/ComponentPool.cpp b/src/Engine/Core/ComponentPool.cpp index b6286c28..f4ca9f4a 100644 --- a/src/Engine/Core/ComponentPool.cpp +++ b/src/Engine/Core/ComponentPool.cpp @@ -50,7 +50,6 @@ ComponentWrapper ComponentPool::GetByEntity(EntityID ent) return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent)); } - bool ComponentPool::KnowsEntity(EntityID ent) { return m_EntityToComponent.find(ent) != m_EntityToComponent.end(); diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index c1125e10..a8e93e49 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -47,7 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName) { "float", sizeof(float) }, { "double", sizeof(double) }, { "string", sizeof(std::string) }, - { "enum", sizeof(int) }, + { "enum", sizeof(ComponentInfo::EnumType) }, { "Vector", sizeof(glm::vec3) }, { "Quaternion", sizeof(glm::quat) }, { "Color", sizeof(glm::vec4) } @@ -86,23 +86,29 @@ void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) { - if (field.Type == "int" || field.Type == "enum") { - int value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "float") { - float value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "double") { - double value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "bool") { - bool value = (valueData[0] == 't'); // Lazy bool evaluation - memcpy(outData, reinterpret_cast(&value), field.Stride); - } else if (field.Type == "string") { - new (outData) std::string(valueData); - } else { - LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); - } + // Catch and ignore casting errors so whitespace around string enums won't mess anything up + try { + if (field.Type == "int") { + int value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "enum") { + ComponentInfo::EnumType value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "float") { + float value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "double") { + double value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "bool") { + bool value = (valueData[0] == 't'); // Lazy bool evaluation + memcpy(outData, reinterpret_cast(&value), field.Stride); + } else if (field.Type == "string") { + new (outData) std::string(valueData); + } else { + LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); + } + } catch (const boost::bad_lexical_cast&) { } } EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler) @@ -165,7 +171,7 @@ void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* cons //} } - if (m_StateStack.top() == State::ComponentField) { + if (m_StateStack.top() == State::ComponentField && name == m_CurrentField) { m_StateStack.pop(); onEndComponentField(name); return; diff --git a/src/Engine/Core/EntityFileParser.cpp b/src/Engine/Core/EntityFileParser.cpp index 1633bbc7..23c0c4c4 100644 --- a/src/Engine/Core/EntityFileParser.cpp +++ b/src/Engine/Core/EntityFileParser.cpp @@ -28,14 +28,14 @@ void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std m_World->SetName(realEntity, name); } m_EntityIDMapper[entity] = realEntity; - LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent); + //LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent); } void EntityFileParser::onStartComponent(EntityID entity, const std::string& component) { EntityID realEntity = m_EntityIDMapper.at(entity); m_World->AttachComponent(realEntity, component); - LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity); + //LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity); } void EntityFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map& attributes) @@ -49,11 +49,11 @@ void EntityFileParser::onStartComponentField(EntityID entity, const std::string& } auto& field = fieldIt->second; - LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str()); - LOG_DEBUG("Attributes:"); - for (auto& kv : attributes) { - LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); - } + //LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str()); + //LOG_DEBUG("Attributes:"); + //for (auto& kv : attributes) { + // LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); + //} char* data = component.Data + field.Offset; EntityFile::WriteAttributeData(data, field, attributes); diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index 90151941..7b4b2bb7 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -7,23 +7,23 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); m_EntityFile->Parse(&handler); - LOG_DEBUG("___ COMPONENT DEFINITIONS ___"); - for (auto& kv : m_ComponentCounts) { - LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second); - } + //LOG_DEBUG("___ COMPONENT DEFINITIONS ___"); + //for (auto& kv : m_ComponentCounts) { + // LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second); + //} parseComponentInfo(); - for (auto& kv : m_ComponentInfo) { - auto& info = kv.second; - LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str()); - LOG_DEBUG("Stride: %i", info.Stride); - LOG_DEBUG("Allocation: %i", info.Meta->Allocation); - for (auto& kv : info.Fields) { - auto& field = kv.second; - LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str()); - } - } + //for (auto& kv : m_ComponentInfo) { + // auto& info = kv.second; + // LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str()); + // LOG_DEBUG("Stride: %i", info.Stride); + // LOG_DEBUG("Allocation: %i", info.Meta->Allocation); + // for (auto& kv : info.Fields) { + // auto& field = kv.second; + // LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str()); + // } + //} parseDefaults(); } @@ -50,7 +50,6 @@ void EntityFilePreprocessor::parseComponentInfo() auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs); // Find component xsd element declarations - std::cout << "Enumerating components..." << std::endl; // auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION); for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { @@ -73,7 +72,7 @@ void EntityFilePreprocessor::parseComponentInfo() if (componentAnnotation != nullptr) { compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString()); } else { - LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); + //LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); } // @@ -91,7 +90,7 @@ void EntityFilePreprocessor::parseComponentInfo() // auto modelGroupParticle = complexTypeDefinition->getParticle(); if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { - LOG_ERROR("Failed to parse component definition for \"%s\": Model group particle was null or wasn't TERM_MODELGROUP!", compInfo.Name.c_str()); + //LOG_ERROR("Failed to parse component definition for \"%s\": Model group particle was null or wasn't TERM_MODELGROUP!", compInfo.Name.c_str()); continue; } auto modelGroup = modelGroupParticle->getModelGroupTerm(); @@ -103,7 +102,7 @@ void EntityFilePreprocessor::parseComponentInfo() for (unsigned int i = 0; i < particles->size(); ++i) { auto particle = particles->elementAt(i); if (particle->getTermType() != XSParticle::TERM_ELEMENT) { - LOG_ERROR("Failed to parse a field definition in component \"%s\": Particle wasn't TERM_ELEMENT! Skipping.", compInfo.Name.c_str()); + //LOG_ERROR("Failed to parse a field definition in component \"%s\": Particle wasn't TERM_ELEMENT! Skipping.", compInfo.Name.c_str()); continue; } auto elementDeclaration = particle->getElementTerm(); @@ -129,7 +128,7 @@ void EntityFilePreprocessor::parseComponentInfo() if (fieldAnnotation != nullptr) { compInfo.Meta->FieldAnnotations[name] = parseAnnotationXML(fieldAnnotation->getAnnotationString()); } else { - LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str()); + //LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str()); } if (effectiveType == "enum") { @@ -146,8 +145,8 @@ void EntityFilePreprocessor::parseComponentInfo() auto enumElement = xsChoiceParticles->elementAt(i)->getElementTerm(); std::string enumName = XS::ToString(enumElement->getName()); std::string enumValue = XS::ToString(enumElement->getConstraintValue()); - compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast(enumValue); - LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str()); + compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast(enumValue); + //LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str()); } } } @@ -190,7 +189,7 @@ void EntityFilePreprocessor::parseDefaults() //std::string namespaceSchema = schemaLocation.string(); //parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd"); - LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); + //LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; parser.parse(defaultsFile.string().c_str()); diff --git a/src/Engine/Core/EntityFileWriter.cpp b/src/Engine/Core/EntityFileWriter.cpp index 4d46be06..06a3c4ca 100644 --- a/src/Engine/Core/EntityFileWriter.cpp +++ b/src/Engine/Core/EntityFileWriter.cpp @@ -114,9 +114,18 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(q.y))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(q.z))); fieldElement->setAttribute(X("W"), X(boost::lexical_cast(q.w))); - } else if (field.Type == "int" || field.Type == "enum") { + } else if (field.Type == "int") { const int& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); + } else if (field.Type == "enum") { + const ComponentInfo::EnumType& value = c[fieldName]; + auto& enumDef = c.Info.Meta->FieldEnumDefinitions.at(fieldName); + for (auto& kv : enumDef) { + if (kv.second == value) { + fieldElement->appendChild(doc->createElement(X(kv.first))); + break; + } + } } else if (field.Type == "float") { const float& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 7b321a63..98b9c7d4 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -3,28 +3,65 @@ const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Invalid); -bool EntityWrapper::operator==(const EntityWrapper& e) -{ - return (this->World == e.World) && (this->ID == e.ID); -} - bool EntityWrapper::HasComponent(const std::string& componentName) { return World->HasComponent(ID, componentName); } -ComponentWrapper EntityWrapper::operator[](const std::string& componentName) +EntityWrapper EntityWrapper::Parent() +{ + if (this->World == nullptr || this->ID == EntityID_Invalid) { + return EntityWrapper::Invalid; + } else { + return EntityWrapper(this->World, this->World->GetParent(this->ID)); + } +} + +bool EntityWrapper::Valid() +{ + if (this->World == nullptr) { + return false; + } + + if (this->ID == EntityID_Invalid) { + return false; + } + + if (!this->World->ValidEntity(this->ID)) { + this->ID = EntityID_Invalid; + return false; + } + + return true; +} + +ComponentWrapper EntityWrapper::operator[](const char* componentName) { if (World->HasComponent(ID, componentName)) { return World->GetComponent(ID, componentName); } else { - LOG_WARNING("EntityWrapper implicitly attached \"%s\" component to #%i as a result of a fetch request!", componentName.c_str(), ID); + LOG_WARNING("EntityWrapper implicitly attached \"%s\" component to #%i as a result of a fetch request!", componentName, ID); return World->AttachComponent(ID, componentName); } } -EntityWrapper::operator EntityID() +bool EntityWrapper::operator==(const EntityWrapper& e) const +{ + return (this->ID == e.ID) && (this->World == e.World); +} + +bool EntityWrapper::operator!=(const EntityWrapper& e) const +{ + return !this->operator==(e); +} + +EntityWrapper::operator EntityID() const { return this->ID; } +EntityWrapper::operator bool() +{ + return this->Valid(); +} + diff --git a/src/Engine/Core/InputManager.cpp b/src/Engine/Core/InputManager.cpp index 50dcac7c..941cc223 100644 --- a/src/Engine/Core/InputManager.cpp +++ b/src/Engine/Core/InputManager.cpp @@ -34,10 +34,16 @@ void InputManager::Update(double dt) if (m_CurrentKeyState[i]) { Events::KeyDown e; e.KeyCode = i; + e.ModCtrl = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_CONTROL) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_CONTROL); + e.ModAlt = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_ALT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_ALT); + e.ModShift = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_SHIFT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_SHIFT); m_EventBroker->Publish(e); } else { Events::KeyUp e; e.KeyCode = i; + e.ModCtrl = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_CONTROL) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_CONTROL); + e.ModAlt = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_ALT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_ALT); + e.ModShift = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_SHIFT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_SHIFT); m_EventBroker->Publish(e); } } diff --git a/src/Engine/Core/UniformScaleSystem.cpp b/src/Engine/Core/UniformScaleSystem.cpp new file mode 100644 index 00000000..ab954a05 --- /dev/null +++ b/src/Engine/Core/UniformScaleSystem.cpp @@ -0,0 +1,24 @@ +#include "Core/UniformScaleSystem.h" + +UniformScaleSystem::UniformScaleSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) + , PureSystem("UniformScale") +{ + EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &UniformScaleSystem::OnSetCamera); +} + +void UniformScaleSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cUniformScale, double dt) +{ + if (!m_Camera.Valid()) { + return; + } + + float distance = glm::length((glm::vec3)entity["Transform"]["Position"] - (glm::vec3&)m_Camera["Transform"]["Position"]); + entity["Transform"]["Scale"] = (glm::vec3&)cUniformScale["Scale"] * distance; +} + +bool UniformScaleSystem::OnSetCamera(const Events::SetCamera& e) +{ + m_Camera = e.CameraEntity; + return false; +} \ No newline at end of file diff --git a/src/Engine/Editor/EditorGUI.cpp b/src/Engine/Editor/EditorGUI.cpp new file mode 100644 index 00000000..390e69a5 --- /dev/null +++ b/src/Engine/Editor/EditorGUI.cpp @@ -0,0 +1,734 @@ +#include "Editor/EditorGUI.h" + +EditorGUI::EditorGUI(World* world, EventBroker* eventBroker) + : m_World(world) + , m_EventBroker(eventBroker) +{ + EVENT_SUBSCRIBE_MEMBER(m_EKeyDown, &EditorGUI::OnKeyDown); +} + +void EditorGUI::Draw() +{ + ImGui::ShowTestWindow(); + drawMenu(); + drawTools(); + drawEntities(m_World); + drawComponents(m_CurrentSelection); + drawModals(); +} + +void EditorGUI::SelectEntity(EntityWrapper entity) +{ + m_CurrentSelection = entity; + if (m_OnEntitySelected != nullptr) { + m_OnEntitySelected(entity); + } +} + +void EditorGUI::drawMenu() +{ + +} + +void EditorGUI::drawTools() +{ + if (!ImGui::Begin("Tools", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) { + return; + } + + createWidgetToolButton(WidgetMode::Translate); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Translate"); + } + ImGui::SameLine(); + createWidgetToolButton(WidgetMode::Rotate); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Rotate"); + } + ImGui::SameLine(); + createWidgetToolButton(WidgetMode::Scale); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Scale"); + } + ImGui::SameLine(); + ImGui::ItemSize(ImVec2(5, 0)); + + // Play button + ImGui::SameLine(); + static bool paused = false; + if (ImGui::ImageButton((void*)tryLoadTexture("Textures/Icons/Play.png"), ImVec2(24, 24), ImVec2(0, 1), ImVec2(1, 0), -1, ImVec4(0, 0, 0, 0), (!paused) ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 1, 1))) { + Events::Resume e; + e.World = m_World; + m_EventBroker->Publish(e); + paused = false; + } + // Pause button + ImGui::SameLine(); + if (ImGui::ImageButton((void*)tryLoadTexture("Textures/Icons/Pause.png"), ImVec2(24, 24), ImVec2(0, 1), ImVec2(1, 0), -1, ImVec4(0, 0, 0, 0), (paused) ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 1, 1))) { + Events::Pause e; + e.World = m_World; + m_EventBroker->Publish(e); + paused = true; + } + + ImGui::End(); +} + +void EditorGUI::drawEntities(World* world) +{ + if (!ImGui::Begin("Entities")) { + ImGui::End(); + return; + } + + float buttonWidth = (ImGui::GetContentRegionAvailWidth() - 10.f) / 3.f ; + if (ImGui::Button("Create", ImVec2(buttonWidth, 0))) { + entityCreate(world, m_CurrentSelection); + } + ImGui::SameLine(0.f, 5.f); + if (ImGui::Button("Import", ImVec2(buttonWidth, 0))) { + entityImport(world); + } + ImGui::SameLine(0.f, 5.f); + ImGui::ButtonEx("Reference", ImVec2(buttonWidth, 0), ImGuiButtonFlags_Disabled); + + // Naming + char buffer[256]; + buffer[0] = '\0'; + buffer[255] = '\0'; + std::size_t nameLength = 0; + ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_AutoSelectAll; + if (m_CurrentSelection.Valid()) { + std::string name = world->GetName(m_CurrentSelection.ID); + nameLength = name.length(); + if (!name.empty()) { + memcpy(buffer, name.c_str(), std::min(sizeof(buffer) - 1, name.length() + 1)); + } + } else { + flags |= ImGuiInputTextFlags_ReadOnly; + } + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - 7.f); + if (ImGui::InputText("", &buffer[0], sizeof(buffer), flags)) { + if (m_CurrentSelection.Valid()) { + if (m_OnEntityChangeName != nullptr) { + m_OnEntityChangeName(m_CurrentSelection, std::string(buffer)); + SetDirty(m_CurrentSelection); + } + } + } + ImGui::PopItemWidth(); + + ImGui::ItemSize(ImVec2(0, 3)); + + drawEntitiesRecursive(world, EntityID_Invalid); + + ImGui::End(); +} + +void EditorGUI::drawEntitiesRecursive(World* world, EntityID parent) +{ + auto entityChildren = world->GetEntityChildren(); + auto range = entityChildren.equal_range(parent); + for (auto it = range.first; it != range.second; it++) { + if (EditorGUI::drawEntityNode(EntityWrapper(world, it->second))) { + drawEntitiesRecursive(world, it->second); + ImGui::TreePop(); + } + } +} + +bool EditorGUI::drawEntityNode(EntityWrapper entity) +{ + // Custom button hitbox to select entities on top of tree node + ImVec2 pos = ImGui::GetCursorScreenPos(); + float width = ImGui::GetContentRegionAvailWidth(); + ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 14)); + auto window = ImGui::GetCurrentWindow(); + if (m_CurrentSelection == entity) { + const ImU32 col = window->Color(ImGuiCol_HeaderActive); + window->DrawList->AddRectFilled(bb.Min, bb.Max, col); + } + ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity.ID)).c_str()); + bool hovered = false; + bool held = false; + if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) { + SelectEntity(entity); + } + // Handle entity dragging + if (held) { + ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0); + if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) { + if (m_CurrentlyDragging == EntityWrapper::Invalid) { + m_CurrentlyDragging = entity; + LOG_DEBUG("Started dragging %i", entity.ID); + } + ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0)); + ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings); + ImGui::Text(formatEntityName(entity).c_str()); + ImGui::End(); + } + }/* else if (m_CurrentlyDragging == entity) { + LOG_DEBUG("Stopped dragging %i", entity.ID); + m_CurrentlyDragging = EntityWrapper::Invalid; + }*/ + // Entity context menu + std::string contextMenuUniqueID = std::string("EntityContextMenu") + std::to_string(entity.ID); + if (hovered && ImGui::IsMouseClicked(1)) { + ImGui::OpenPopup(contextMenuUniqueID.c_str()); + } + if (ImGui::BeginPopup(contextMenuUniqueID.c_str())) { + ImGui::TextDisabled(formatEntityName(entity).c_str()); + if (ImGui::MenuItem("Save", "Ctrl+S")) { + entitySave(entity); + } else + if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) { + entitySave(entity, true); + } else + if (ImGui::MenuItem("Delete", "Del")) { + entityDelete(entity); + } else + if (ImGui::MenuItem("Move to root")) { + entityChangeParent(entity, EntityWrapper::Invalid); + } + ImGui::EndPopup(); + } + + ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once); + if (ImGui::TreeNode(formatEntityName(entity).c_str())) { + // Handle drop events for reparenting + if (m_CurrentlyDragging != EntityWrapper::Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) { + entityChangeParent(m_CurrentlyDragging, entity); + m_CurrentlyDragging = EntityWrapper::Invalid; + } + return true; + } else { + return false; + } +} + +void EditorGUI::drawComponents(EntityWrapper entity) +{ + std::stringstream title; + title << "Components"; + if (entity.Valid()) { + title << " " << formatEntityName(entity); + } + title << "###Components"; + if (!ImGui::Begin(title.str().c_str())) { + ImGui::End(); + return; + } + + if (!entity.Valid()) { + ImGui::End(); + return; + } + + auto& pools = entity.World->GetComponentPools(); + // Create list of component types available to be added + std::vector componentTypes; + for (auto& pair : pools) { + // Don't list components the entity already has attached + if (!entity.HasComponent(pair.first)) { + componentTypes.push_back(pair.first.c_str()); + } + } + // Draw combo box + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - 10.f); + int selectedItem = -1; + if (ImGui::Combo("", &selectedItem, componentTypes.data(), componentTypes.size())) { + if (selectedItem != -1) { + if (m_OnComponentAttach != nullptr) { + std::string chosenComponentType(componentTypes.at(selectedItem)); + m_OnComponentAttach(entity, chosenComponentType); + SetDirty(entity); + } + } + } + ImGui::PopItemWidth(); + + for (auto& pair : pools) { + const std::string& componentType = pair.first; + auto pool = pair.second; + // Don't show components the entity doesn't have attached + if (!entity.HasComponent(componentType)) { + continue; + } + // Handle deletion with early out + if (createDeleteButton(componentType)) { + if (m_OnComponentDelete != nullptr) { + m_OnComponentDelete(entity, componentType); + continue; + } + } + // Draw the actual component node + drawComponentNode(entity, pool->ComponentInfo()); + } + + ImGui::End(); +} + +bool EditorGUI::drawComponentNode(EntityWrapper entity, const ComponentInfo& ci) +{ + if (!ImGui::CollapsingHeader(ci.Name.c_str(), nullptr, true, true)) { + return false; + } + + // Show component annotation + const std::string annotation = ci.Meta->Annotation; + if (!annotation.empty()) { + ImGui::TextWrapped(annotation.c_str()); + } + + // Draw component fields + ComponentWrapper& component = entity.World->GetComponent(entity.ID, ci.Name); + for (auto& kv : ci.Fields) { + const std::string& fieldName = kv.first; + const ComponentInfo::Field_t& field = kv.second; + + // Draw the field widget based on its type + bool dirty = drawComponentField(component, field); + if (dirty) { + SetDirty(entity); + } + ImGui::SameLine(); + // Draw field name + ImGui::Text(fieldName.c_str()); + // Draw potential field annotation + auto fieldAnnotationIt = ci.Meta->FieldAnnotations.find(fieldName); + if (fieldAnnotationIt != ci.Meta->FieldAnnotations.end()) { + ImGui::SameLine(); + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip(fieldAnnotationIt->second.c_str()); + } + } + } + + return true; +} + +bool EditorGUI::drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field) +{ + // Push an unique widget id so different components with fields with equal names are still counted as different + ImGui::PushID((c.Info.Name + field.Name).c_str()); + + bool dirty = false; + + if (field.Type == "Vector") { + dirty = drawComponentField_Vector(c, field); + } else if (field.Type == "Color") { + dirty = drawComponentField_Color(c, field); + //} else if (field.Type == "Quaternion") { + } else if (field.Type == "int") { + dirty = drawComponentField_int(c, field); + } else if (field.Type == "enum") { + dirty = drawComponentField_enum(c, field); + } else if (field.Type == "float") { + dirty = drawComponentField_float(c, field); + } else if (field.Type == "double") { + dirty = drawComponentField_double(c, field); + } else if (field.Type == "bool") { + dirty = drawComponentField_bool(c, field); + } else if (field.Type == "string") { + dirty = drawComponentField_string(c, field); + } else { + ImGui::TextDisabled(field.Type.c_str()); + } + + ImGui::PopID(); + + return dirty; +} + +bool EditorGUI::drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto& val = c.Field(field.Name); + if (field.Name == "Scale") { + // Limit scale values to a minimum of 0 + return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits::max()); + } else if (field.Name == "Orientation") { + // Make orentations have a period of 2*Pi + glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi())); + if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi())) { + val = tempVal; + return true; + } else { + return false; + } + } else { + return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits::lowest(), std::numeric_limits::max()); + } +} + +bool EditorGUI::drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto& val = c.Field(field.Name); + return ImGui::ColorEdit4("", glm::value_ptr(val), true); +} + +bool EditorGUI::drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto& val = c.Field(field.Name); + return ImGui::InputInt("", &val); +} + +bool EditorGUI::drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto fieldEnumDefIt = c.Info.Meta->FieldEnumDefinitions.find(field.Name); + if (fieldEnumDefIt == c.Info.Meta->FieldEnumDefinitions.end()) { + return drawComponentField_int(c, field); + } + + auto& val = c.Field(field.Name); + int selectedItem = -1; + std::stringstream enumKeys; + std::vector enumValues; + int i = 0; + for (auto& kv : fieldEnumDefIt->second) { + enumKeys << kv.first << " (" << kv.second << ")" << '\0'; + enumValues.push_back(kv.second); + if (val == kv.second) { + selectedItem = i; + } + i++; + } + if (ImGui::Combo("", &selectedItem, enumKeys.str().c_str())) { + val = enumValues.at(selectedItem); + return true; + } else { + return false; + } +} + +bool EditorGUI::drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto& val = c.Field(field.Name); + return ImGui::InputFloat("", &val, 0.01f, 1.f); +} + +bool EditorGUI::drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + float tempVal = static_cast(c.Field(field.Name)); + if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { + c.SetField(field.Name, static_cast(tempVal)); + return true; + } else { + return false; + } +} + +bool EditorGUI::drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto& val = c.Field(field.Name); + return ImGui::Checkbox("", &val); +} + +bool EditorGUI::drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field) +{ + auto& val = c.Field(field.Name); + char tempString[1024]; // Let's just hope this is an sufficiently large buffer for strings :) + tempString[1023] = '\0'; // Null terminator just in case the string is larger than the buffer + // Copy the string into the buffer, taking the null terminator into account + memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString) - 1)); + if (ImGui::InputText("", tempString, sizeof(tempString))) { + val = std::string(tempString); + return true; + } else { + return false; + } + // TODO: Handle drag and drop of files +} + +void EditorGUI::drawModals() +{ + for (auto& modal : m_ModalsToOpen) { + ImGui::OpenPopup(modal.c_str()); + } + m_ModalsToOpen.clear(); + + if (ImGui::BeginPopupModal("Import failed", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("Entity import failed. Check console for more information.\n\n"); + ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 120); + if (ImGui::Button("OK", ImVec2(120, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + if (ImGui::BeginPopupModal("Save failed", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("Entity save failed on an exception.\nMessage: %s\n\n", m_LastErrorMessage.c_str()); + ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 120); + if (ImGui::Button("OK", ImVec2(120, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + if (ImGui::BeginPopupModal("Confirm deletion", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + if (m_ModalData.count("Confirm deletion") == 0) { + ImGui::CloseCurrentPopup(); + } + + ImGui::Text("Are you sure you want to delete entity \"%s\"?", formatEntityName(m_CurrentSelection).c_str()); + ImGui::ItemSize(ImVec2(5.f, 0.f)); + ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 2*60); + if (ImGui::Button("Delete (Del)", ImVec2(60, 0))) { + entityDelete(boost::any_cast(m_ModalData.at("Confirm deletion"))); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(60, 0))) { + m_ModalData.erase("Confirm deletion"); + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } +} + +bool EditorGUI::createDeleteButton(const std::string& componentType) +{ + float width = ImGui::GetContentRegionAvailWidth(); + ImGuiWindow* window = ImGui::GetCurrentWindow(); + auto pos = ImGui::GetCursorScreenPos() + ImVec2(width - 14.f, 1); + ImRect bb = ImRect(pos, pos + ImVec2(14.f, 14.f)); + std::string idString = "#DELETE"; + idString += componentType; + ImGuiID id = window->GetID(idString.c_str()); + bool hovered; + bool held; + bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); + //ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); + ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + window->DrawList->AddCircleFilled(bb.GetCenter(), 7.f, col, 16); + return pressed; +} + +void EditorGUI::createWidgetToolButton(WidgetMode mode) +{ + GLuint texture = 0; + switch (mode) { + case WidgetMode::Translate: + texture = tryLoadTexture("Textures/Icons/Translate.png"); + break; + case WidgetMode::Rotate: + texture = tryLoadTexture("Textures/Icons/Rotate.png"); + break; + case WidgetMode::Scale: + texture = tryLoadTexture("Textures/Icons/Scale.png"); + break; + } + if (ImGui::ImageButton( + (void*)texture, + ImVec2(24, 24), + ImVec2(0, 1), + ImVec2(1, 0), + -1, + ImVec4(0, 0, 0, 0), + (m_CurrentWidgetMode == mode) ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 1, 1) + ) + ) { + if (m_OnWidgetMode != nullptr) { + m_OnWidgetMode(mode); + } + m_CurrentWidgetMode = mode; + } +} + +bool EditorGUI::OnKeyDown(const Events::KeyDown& e) +{ + if (e.ModCtrl && e.KeyCode == GLFW_KEY_S) { + if (m_CurrentSelection.Valid()) { + EntityWrapper baseParent = m_CurrentSelection; + while (baseParent.Parent().Valid()) { + baseParent = baseParent.Parent(); + } + entitySave(baseParent); + } + } + + if (e.ModCtrl && e.KeyCode == GLFW_KEY_N) { + entityCreate(m_World, m_CurrentSelection); + } + + if (e.ModCtrl && e.KeyCode == GLFW_KEY_O) { + entityImport(m_World); + } + + if (e.KeyCode == GLFW_KEY_DELETE) { + if (m_CurrentSelection.Valid()) { + entityDelete(m_CurrentSelection); + } + } + + return true; +} + +boost::filesystem::path EditorGUI::fileOpenDialog() +{ + namespace bfs = boost::filesystem; + nfdchar_t* outPath = nullptr; + nfdresult_t result = NFD_OpenDialog("xml", bfs::absolute(m_DefaultEntityPath).string().c_str(), &outPath); + + if (result == NFD_ERROR) { + LOG_ERROR("NFD Error: %s", NFD_GetError()); + return bfs::path(); + } else if (result == NFD_CANCEL) { + return bfs::path(); + } else { + return bfs::absolute(outPath); + } +} + +boost::filesystem::path EditorGUI::fileSaveDialog() +{ + namespace bfs = boost::filesystem; + nfdchar_t* outPath = nullptr; + nfdresult_t result = NFD_SaveDialog("xml", bfs::absolute(m_DefaultEntityPath).string().c_str(), &outPath); + + if (result == NFD_ERROR) { + LOG_ERROR("NFD Error: %s", NFD_GetError()); + return bfs::path(); + } else if (result == NFD_CANCEL) { + return bfs::path(); + } else { + return bfs::absolute(outPath); + } +} + +const std::string EditorGUI::formatEntityName(EntityWrapper entity) +{ + if (!entity.Valid()) { + return "EntityID_Invalid"; + } + + std::stringstream name; + + std::string entityName = entity.World->GetName(entity.ID); + if (!entityName.empty()) { + name << entityName; + } else { + name << "#" << entity.ID; + } + + if (m_EntityFiles.count(entity) == 1) { + name << " (" << m_EntityFiles.at(entity).Path.filename().string() << ")"; + if (m_EntityFiles.at(entity).Dirty) { + name << "*"; + } + } + + return name.str(); +} + +GLuint EditorGUI::tryLoadTexture(std::string filePath) +{ + GLuint texture = 0; + try { + texture = ResourceManager::Load(filePath)->m_Texture; + } catch (const std::exception&) { } + return texture; +} + +void EditorGUI::openModal(const std::string& modal) +{ + m_ModalsToOpen.insert(modal); +} + +void EditorGUI::SetDirty(EntityWrapper entity) +{ + EntityWrapper baseParent = entity; + while (baseParent.Parent().Valid()) { + baseParent = baseParent.Parent(); + } + if (m_EntityFiles.find(baseParent) != m_EntityFiles.end()) { + m_EntityFiles.at(baseParent).Dirty = true; + } +} + +void EditorGUI::entityImport(World* world) +{ + boost::filesystem::path filePath = fileOpenDialog(); + if (filePath.empty()) { + return; + } + + EntityWrapper entity = m_OnEntityImport(EntityWrapper(world, EntityID_Invalid), filePath); + if (entity.Valid()) { + m_EntityFiles[entity].Path = filePath; + SelectEntity(entity); + } else { + openModal("Import failed"); + } +} + +void EditorGUI::entitySave(EntityWrapper entity, bool saveAs /* = false */) +{ + boost::filesystem::path filePath; + if (!saveAs && m_EntityFiles.count(entity) == 1) { + filePath = m_EntityFiles.at(entity).Path; + } else { + filePath = fileSaveDialog(); + } + + if (filePath.empty()) { + return; + } + + try { + m_OnEntitySave(entity, filePath); + m_EntityFiles[entity].Path = filePath; + m_EntityFiles[entity].Dirty = false; + } catch (const std::exception& e) { + m_LastErrorMessage = e.what(); + openModal("Save failed"); + } +} + +void EditorGUI::entityCreate(World* world, EntityWrapper parent) +{ + if (m_OnEntityCreate != nullptr) { + // Create the new entity in the world we're drawing for + if (parent.World == nullptr) { + parent.World = world; + } + EntityWrapper newEntity = m_OnEntityCreate(parent); + SelectEntity(newEntity); + } +} + +void EditorGUI::entityDelete(EntityWrapper entity) +{ + std::string modalName = "Confirm deletion"; + + if (m_ModalData.count(modalName) == 0) { + m_ModalData[modalName] = entity; + openModal(modalName); + } else { + if (boost::any_cast(m_ModalData[modalName]) == entity) { + EntityWrapper parent = entity.Parent(); + if (m_OnEntityDelete != nullptr) { + SetDirty(entity); + m_OnEntityDelete(entity); + m_EntityFiles.erase(entity); + } + if (!m_CurrentSelection.Valid()) { + SelectEntity(parent); + } + } + m_ModalData.erase(modalName); + } +} + +void EditorGUI::entityChangeParent(EntityWrapper entity, EntityWrapper parent) +{ + if (entity == parent) { + return; + } + + if (m_OnEntityChangeParent != nullptr) { + SetDirty(entity); + m_OnEntityChangeParent(entity, parent); + LOG_DEBUG("Changed parent of %i to %i", entity.ID, parent.ID); + } +} diff --git a/src/Engine/Editor/EditorRenderSystem.cpp b/src/Engine/Editor/EditorRenderSystem.cpp new file mode 100644 index 00000000..2e31e3f0 --- /dev/null +++ b/src/Engine/Editor/EditorRenderSystem.cpp @@ -0,0 +1,87 @@ +#include "Editor/EditorRenderSystem.h" + +EditorRenderSystem::EditorRenderSystem(World* m_World, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame) + : System(m_World, eventBroker) + , m_Renderer(renderer) + , m_RenderFrame(renderFrame) +{ + EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &EditorRenderSystem::OnSetCamera); + auto resolution = Rectangle::Rectangle(1280, 720); + m_EditorCamera = new Camera((float)resolution.Width / resolution.Height, glm::radians(45.f), 0.01f, 5000.f); +} + +void EditorRenderSystem::Update(double dt) +{ + if (m_CurrentCamera) { + ComponentWrapper cameraTransform = m_CurrentCamera["Transform"]; + m_EditorCamera->SetPosition(cameraTransform["Position"]); + m_EditorCamera->SetOrientation(glm::quat((const glm::vec3&)cameraTransform["Orientation"])); + } + + RenderScene scene; + scene.ClearDepth = true; + scene.Camera = m_EditorCamera; + scene.Viewport = Rectangle(1920, 1080); + + auto models = m_World->GetComponents("Model"); + if (models != nullptr) { + for (auto& cModel : *models) { + if (!(bool)cModel["Visible"]) { + continue; + } + + const std::string& resource = cModel["Resource"]; + + Model* model; + try { + model = ResourceManager::Load<::Model, true>(resource); + } catch (const Resource::StillLoadingException&) { + continue; + } catch (const std::exception&) { + try { + model = ResourceManager::Load<::Model>("Models/Core/Error.obj"); + } catch (const std::exception&) { + continue; + } + } + + EntityWrapper entity(m_World, cModel.EntityID); + glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, entity.World); + for (auto matGroup : model->MaterialGroups()) { + std::shared_ptr modelJob = std::make_shared(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World); + scene.ForwardJobs.push_back(modelJob); + } + } + } + + auto pointLights = m_World->GetComponents("PointLight"); + if (pointLights != nullptr) { + for (auto& cPointLight : *pointLights) { + bool visible = cPointLight["Visible"]; + if (!visible) { + continue; + } + + EntityWrapper entity(m_World, cPointLight.EntityID); + ComponentWrapper& cTransform = entity["Transform"]; + std::shared_ptr pointLightJob = std::make_shared(cTransform, cPointLight, entity.World); + scene.PointLightJobs.push_back(pointLightJob); + } + } + + m_RenderFrame->Add(scene); +} + +bool EditorRenderSystem::OnSetCamera(Events::SetCamera& e) +{ + ComponentWrapper cTransform = e.CameraEntity["Transform"]; + ComponentWrapper cCamera = e.CameraEntity["Camera"]; + m_EditorCamera->SetFOV((double)cCamera["FOV"]); + m_EditorCamera->SetNearClip((double)cCamera["NearClip"]); + m_EditorCamera->SetFarClip((double)cCamera["FarClip"]); + m_EditorCamera->SetPosition(cTransform["Position"]); + m_EditorCamera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"])); + m_CurrentCamera = e.CameraEntity; + return true; +} + diff --git a/src/Engine/Editor/EditorStats.cpp b/src/Engine/Editor/EditorStats.cpp new file mode 100644 index 00000000..a626c442 --- /dev/null +++ b/src/Engine/Editor/EditorStats.cpp @@ -0,0 +1,115 @@ +#include "Editor/EditorStats.h" +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include +#endif +#include + +EditorStats::EditorStats() +{ + m_AveragedSamples.push_back(0.0); + m_CurrentAveragedSampleIndex = 1; +} + +void EditorStats::Draw(double dt) +{ + if (ImGui::Begin("Stats")) { + drawFPSGraph(dt); + drawRAMUsage(dt); + drawVRAMStats(dt); + } + ImGui::End(); +} + +void EditorStats::drawFPSGraph(double dt) +{ + if (m_FrameCount < m_SampleSize) { + m_FrameTimes.push_back(dt); + } else { + m_FrameTimes[m_FrameCount % m_SampleSize] = dt; + } + m_FrameCount++; + + double average = 0.0; + double max = 0.0; + for (double t : m_FrameTimes) { + average += t; + max = std::max(max, t); + } + average /= m_FrameTimes.size(); + + m_TimeAccumulator += dt; + if (m_TimeAccumulator >= 1.0/m_AveragedSamplesPerSecond) { + if (m_CurrentAveragedSampleIndex < m_AveragedSampleSize) { + m_AveragedSamples.push_back(1.0/average); + } else { + m_AveragedSamples[m_CurrentAveragedSampleIndex % m_AveragedSampleSize] = 1.0/average; + } + m_CurrentAveragedSampleIndex++; + m_TimeAccumulator = 0.0; + } + + float maxFPS = 0.f; + ImVector values; + int values_offset = m_CurrentAveragedSampleIndex % m_AveragedSampleSize; + for (double d : m_AveragedSamples) { + values.push_back(static_cast(d)); + maxFPS = std::max(maxFPS, static_cast(d)); + } + std::stringstream header; + header << std::round(1.0/average) << " FPS (" << std::setprecision(5) << average << " ms)"; + ImGui::PlotLines("##FPSGraph", values.Data, values.Size, values_offset, header.str().c_str(), 0.f, maxFPS + maxFPS/5.f, ImVec2(0, 100)); +} + +void EditorStats::drawRAMUsage(double dt) +{ +#ifdef WIN32 + PROCESS_MEMORY_COUNTERS_EX ppm; + GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&ppm, sizeof(ppm)); + float megabytes = ppm.WorkingSetSize / (float)std::pow(1024, 2); + ImGui::Text("Memory: ~%f MiB", megabytes); +#endif +} + +void EditorStats::drawVRAMStats(double dt) +{ + //const unsigned int GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049; + //const unsigned int GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048; + //glm::ivec4 total; + //glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, glm::value_ptr(total)); + //if (glGetError() == GL_NO_ERROR) { + // glm::ivec4 available; + // glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, glm::value_ptr(available)); + // float megabytes = (total.x - available.x) / 1024.f; // NVidia returns in KiB + // ImGui::Text("VRAM: %f", megabytes); + //} + + //GLuint uNoOfGPUs = wglGetGPUIDsAMD(0, 0); + //if (!GLERROR("")) { + // GLuint* uGPUIDs = new GLuint[uNoOfGPUs]; + // wglGetGPUIDsAMD(uNoOfGPUs, uGPUIDs); + // GLuint uTotalMemoryInMB = 0; + // wglGetGPUInfoAMD(uGPUIDs[0], + // WGL_GPU_RAM_AMD, + // GL_UNSIGNED_INT, + // sizeof(GLuint), + // &uTotalMemoryInMB); + // GLint nCurAvailMemoryInKB[4]; + // glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, + // &nCurAvailMemoryInKB[0]); + // float usedTexture = (nCurAvailMemoryInKB[0] / 1024.f); + // glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, + // &nCurAvailMemoryInKB[0]); + // float usedVBO = (nCurAvailMemoryInKB[0] / 1024.f); + // glGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, + // &nCurAvailMemoryInKB[0]); + // float usedFB = (nCurAvailMemoryInKB[0] / 1024.f); + // ImGui::Text("VRAM: %f MiB ", (float)uTotalMemoryInMB - usedTexture - usedVBO - usedFB); + // ImGui::Text(" Texture: %f MiB", usedTexture); + // ImGui::Text(" VBO: %f MiB", usedVBO); + // ImGui::Text(" Framebuffer: %f MiB", usedFB); + // delete[] uGPUIDs; + //} +} diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index d5863814..1ef8b02b 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -1,738 +1,199 @@ #include "Editor/EditorSystem.h" -#define IMGUI_DEFINE_MATH_OPERATORS -#include +#include "Core/UniformScaleSystem.h" +#include "Editor/EditorRenderSystem.h" +#include "Editor/EditorWidgetSystem.h" -EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer) - : System(eventBroker) - , ImpureSystem() +EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame) + : System(world, eventBroker) , m_Renderer(renderer) + , m_RenderFrame(renderFrame) { - auto config = ResourceManager::Load("Config.ini"); - m_Enabled = config->Get("Debug.EditorEnabled", false); - m_Visible = m_Enabled; - m_DefaultEntityDir = boost::filesystem::path("Schema") / boost::filesystem::path("Entities"); + m_EditorWorld = new World(); + m_EditorWorldSystemPipeline = new SystemPipeline(m_EditorWorld, eventBroker); + m_EditorWorldSystemPipeline->AddSystem(0); + m_EditorWorldSystemPipeline->AddSystem(0, m_Renderer); + m_EditorWorldSystemPipeline->AddSystem(1, m_Renderer, m_RenderFrame); + + m_Camera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml"); + m_EditorWorld->AttachComponent(m_Camera.ID, "Transform"); + m_EditorWorld->AttachComponent(m_Camera.ID, "Camera"); + m_DebugCameraInputController = new DebugCameraInputController(m_EventBroker, -1); - if (!m_Enabled) { - return; - } + m_EditorGUI = new EditorGUI(m_World, m_EventBroker); + m_EditorGUI->SetEntitySelectedCallback(std::bind(&EditorSystem::OnEntitySelected, this, std::placeholders::_1)); + m_EditorGUI->SetEntityImportCallback(std::bind(&EditorSystem::importEntity, this, std::placeholders::_1, std::placeholders::_2)); + m_EditorGUI->SetEntitySaveCallback(std::bind(&EditorSystem::OnEntitySave, this, std::placeholders::_1, std::placeholders::_2)); + m_EditorGUI->SetEntityCreateCallback(std::bind(&EditorSystem::OnEntityCreate, this, std::placeholders::_1)); + m_EditorGUI->SetEntityDeleteCallback(std::bind(&EditorSystem::OnEntityDelete, this, std::placeholders::_1)); + m_EditorGUI->SetEntityChangeParentCallback(std::bind(&EditorSystem::OnEntityChangeParent, this, std::placeholders::_1, std::placeholders::_2)); + m_EditorGUI->SetEntityChangeNameCallback(std::bind(&EditorSystem::OnEntityChangeName, this, std::placeholders::_1, std::placeholders::_2)); + m_EditorGUI->SetComponentAttachCallback(std::bind(&EditorSystem::OnComponentAttach, this, std::placeholders::_1, std::placeholders::_2)); + m_EditorGUI->SetComponentDeleteCallback(std::bind(&EditorSystem::OnComponentDelete, this, std::placeholders::_1, std::placeholders::_2)); + m_EditorGUI->SetWidgetModeCallback(std::bind(&EditorSystem::setWidgetMode, this, std::placeholders::_1)); - EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &EditorSystem::OnInputCommand); - EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress); EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorSystem::OnMouseRelease); - EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorSystem::OnMouseMove); - EVENT_SUBSCRIBE_MEMBER(m_EFileDropped, &EditorSystem::OnFileDropped); + EVENT_SUBSCRIBE_MEMBER(m_EWidgetDelta, &EditorSystem::OnWidgetDelta); + + m_EditorStats = new EditorStats(); + + Events::SetCamera e; + e.CameraEntity = m_Camera; + m_EventBroker->Publish(e); } -void EditorSystem::Update(World* world, double dt) +EditorSystem::~EditorSystem() { - m_World = world; + delete m_EditorStats; + delete m_EditorGUI; + delete m_DebugCameraInputController; + delete m_EditorWorldSystemPipeline; + delete m_EditorWorld; +} - if (!m_Enabled) { - return; +void EditorSystem::Update(double dt) +{ + m_EventBroker->Process(); + m_EditorGUI->Draw(); + m_EditorStats->Draw(dt); + + if (m_CurrentSelection.Valid() && m_Widget.Valid()) { + (glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID); } - if (!m_Visible) { - return; - } - Picking(); - updateWidget(); + m_EditorWorldSystemPipeline->Update(dt); - drawUI(world, dt); + m_DebugCameraInputController->Update(dt); + m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position(); + m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation()); +} - // Clear drop queue if it wasn't handled by any UI element - if (!m_LastDroppedFile.empty()) { - m_LastDroppedFile = ""; +void EditorSystem::OnEntitySelected(EntityWrapper entity) +{ + m_CurrentSelection = entity; + setWidgetMode(m_WidgetMode); +} + +void EditorSystem::OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath) +{ + EntityFileWriter writer(filePath); + writer.WriteEntity(entity.World, entity.ID); +} + +EntityWrapper EditorSystem::OnEntityCreate(EntityWrapper parent) +{ + EntityID entity = parent.World->CreateEntity(parent.ID); + parent.World->AttachComponent(entity, "Transform"); + return EntityWrapper(parent.World, entity); +} + +void EditorSystem::OnEntityDelete(EntityWrapper entity) +{ + if (entity.Valid()) { + entity.World->DeleteEntity(entity.ID); } } - -boost::filesystem::path EditorSystem::openDialog(boost::filesystem::path defaultPath) +void EditorSystem::OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent) { - namespace bfs = boost::filesystem; - auto absolutePath = bfs::absolute(defaultPath); - nfdchar_t* outPath = nullptr; - nfdresult_t result = NFD_OpenDialog(NULL, absolutePath.string().c_str(), &outPath); - if (result == NFD_ERROR) { - LOG_ERROR("NFD Error: %s", NFD_GetError()); - return bfs::path(); + if (entity.Valid()) { + entity.World->SetParent(entity.ID, parent.ID); } - - return bfs::absolute(outPath); } -boost::filesystem::path EditorSystem::saveDialog(boost::filesystem::path defaultPath) +void EditorSystem::OnEntityChangeName(EntityWrapper entity, const std::string& name) { - namespace bfs = boost::filesystem; - auto absolutePath = bfs::absolute(defaultPath); - nfdchar_t* outPath = nullptr; - nfdresult_t result = NFD_SaveDialog(NULL, absolutePath.string().c_str(), &outPath); - if (result == NFD_ERROR) { - LOG_ERROR("NFD Error: %s", NFD_GetError()); - return bfs::path(); + if (entity.Valid()) { + entity.World->SetName(entity.ID, name); } - - return bfs::absolute(outPath); } -bool EditorSystem::OnInputCommand(const Events::InputCommand& e) +void EditorSystem::OnComponentAttach(EntityWrapper entity, const std::string& componentType) { - if (e.Command == "ToggleEditor" && e.Value > 0) { - m_Visible = !m_Visible; + if (entity.Valid()) { + entity.World->AttachComponent(entity.ID, componentType); } - - if (e.Command == "EditorToolMove" && e.Value > 0) { - setWidgetMode(WidgetMode::Translate); - } - if (e.Command == "EditorToolRotate" && e.Value > 0) { - setWidgetMode(WidgetMode::Rotate); - } - if (e.Command == "EditorToolScale" && e.Value > 0) { - setWidgetMode(WidgetMode::Scale); - } - - if (e.Command == "EditorToggleTransformSpace" && e.Value > 0) { - if (m_WidgetSpace == WidgetSpace::Global) { - setWidgetSpace(WidgetSpace::Local); - } else if (m_WidgetSpace == WidgetSpace::Local) { - setWidgetSpace(WidgetSpace::Global); - } - } - - return true; } -bool EditorSystem::OnMousePress(const Events::MousePress& e) +void EditorSystem::OnComponentDelete(EntityWrapper entity, const std::string& componentType) { - if (e.Button == GLFW_MOUSE_BUTTON_RIGHT) { - m_PickingQueue.push_back(glm::vec2((int)e.X, (int)e.Y)); + if (entity.Valid()) { + entity.World->DeleteComponent(entity.ID, componentType); } - return true; -} - -bool EditorSystem::OnMouseMove(const Events::MouseMove& e) -{ - if (m_Widget == EntityID_Invalid) { - return false; - } - if (m_Selection == EntityID_Invalid) { - return false; - } - if (m_Selection == m_Widget) { - return false; - } - // TODO: No widgets for root entity until widgets reside in thier own world, - // or the widgets will move relative to the root entity being moved, which is WEEEIRD. - if (m_Selection == 0) { - return false; - } - if (m_Camera == nullptr) { - return false; - } - - auto widgetTransform = m_World->GetComponent(m_Widget, "Transform"); - glm::vec3 widgetOrientation = widgetTransform["Orientation"]; - glm::quat totalOrientation = m_Camera->Orientation() * glm::inverse(glm::quat(widgetOrientation)); - - int width; - int height; - glfwGetFramebufferSize(m_Renderer->Window(), &width, &height); - Rectangle res(width, height); - - glm::vec2 delta2(res.Width / 2.f + e.DeltaX, res.Height / 2.f + -e.DeltaY); - glm::vec3 deltaWorld = ScreenCoords::ToWorldPos( - delta2, - m_WidgetPickingDepth, - res, - m_Camera->ProjectionMatrix(), - glm::toMat4(glm::inverse(totalOrientation)) - ); - glm::vec3 origin = ScreenCoords::ToWorldPos( - glm::vec2(res.Width / 2.f, res.Height / 2.f), - m_WidgetPickingDepth, - res, - m_Camera->ProjectionMatrix(), - glm::toMat4(glm::inverse(totalOrientation)) - ); - deltaWorld = deltaWorld - origin; - glm::vec3 movement = deltaWorld * m_WidgetCurrentAxis; - - if (glm::length2(m_WidgetCurrentAxis) > 0.f) { - auto widgetTransform = m_World->GetComponent(m_Widget, "Transform"); - if (m_WidgetMode == WidgetMode::Translate) { - if (m_WidgetSpace == WidgetSpace::Global) { - EntityID parent = m_World->GetParent(m_Selection); - glm::quat inverseParentOrientation; - //if (parent != 0) { - inverseParentOrientation = glm::inverse(Transform::AbsoluteOrientation(m_World, parent)); - //} - (glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Position"] += inverseParentOrientation * movement; - } else if (m_WidgetSpace == WidgetSpace::Local) { - auto selectionTransform = m_World->GetComponent(m_Selection, "Transform"); - (glm::vec3&)selectionTransform["Position"] += glm::quat((glm::vec3)selectionTransform["Orientation"]) * movement; - } - } else if (m_WidgetMode == WidgetMode::Rotate) { - glm::vec3 finalMovement; - finalMovement.x = -deltaWorld.y * m_WidgetCurrentAxis.x; - finalMovement.y = deltaWorld.x * m_WidgetCurrentAxis.y; - finalMovement.z = deltaWorld.y * m_WidgetCurrentAxis.z; - if (m_WidgetSpace == WidgetSpace::Global) { - EntityID parent = m_World->GetParent(m_Selection); - glm::quat parentOrientation; - //if (parent != 0) { - // parentOrientation = RenderSystem::AbsoluteOrientation(m_World, parent); - //} - glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"]; - glm::quat currentOrientation = Transform::AbsoluteOrientation(m_World, m_Selection); - //glm::quat currentOrientation = parentOrientation * glm::quat(selectionOrientation); - glm::quat deltaOrientation(finalMovement); - selectionOrientation = glm::eulerAngles(glm::inverse(parentOrientation) * (deltaOrientation * currentOrientation)); - } else if (m_WidgetSpace == WidgetSpace::Local) { - glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"]; - glm::quat currentOrientation(selectionOrientation); - glm::quat deltaOrientation(finalMovement); - selectionOrientation = glm::eulerAngles(currentOrientation * deltaOrientation); - } - } else if (m_WidgetMode == WidgetMode::Scale) { - glm::vec3& scaleX = m_World->GetComponent(m_WidgetX, "Transform")["Scale"]; - glm::vec3& scaleY = m_World->GetComponent(m_WidgetY, "Transform")["Scale"]; - glm::vec3& scaleZ = m_World->GetComponent(m_WidgetZ, "Transform")["Scale"]; - - if (m_WidgetCurrentAxis.x > 0 && m_WidgetCurrentAxis.y > 0 && m_WidgetCurrentAxis.z > 0) { - float movementLength = glm::length(movement); - float dot = glm::dot((glm::vec3)widgetOrientation, movement); - movement = glm::vec3(movementLength) * glm::sign(dot); - (glm::vec3&)m_World->GetComponent(m_WidgetOrigin, "Transform")["Scale"] += movement; - } - if (m_WidgetCurrentAxis.x > 0) { - scaleX.x += movement.x; - } - if (m_WidgetCurrentAxis.y > 0) { - scaleY.y += movement.y; - } - if (m_WidgetCurrentAxis.z > 0) { - scaleZ.z += movement.z; - } - (glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Scale"] += movement; - } - } - - - /*LOG_DEBUG("DELTA %f", e.DeltaX); - if (e.X < 0) { - glfwSetCursorPos(m_Renderer->Window(), width - 1, e.Y); - } - if (e.X >= width) { - glfwSetCursorPos(m_Renderer->Window(), 0, e.Y); - }*/ - - return true; } bool EditorSystem::OnMouseRelease(const Events::MouseRelease& e) { - if (glm::length2(m_WidgetCurrentAxis) > 0.f) { - m_WidgetCurrentAxis = glm::vec3(0.f); - //setWidgetMode(m_WidgetMode); + if (e.Button == GLFW_MOUSE_BUTTON_1) { + PickData pick = m_Renderer->Pick(glm::vec2(e.X, e.Y)); + if (pick.World == m_World) { + m_CurrentSelection = EntityWrapper(m_World, pick.Entity); + m_EditorGUI->SelectEntity(m_CurrentSelection); + } } - return true; } -void EditorSystem::Picking() +bool EditorSystem::OnWidgetDelta(const Events::WidgetDelta& e) { - for (auto& pos : m_PickingQueue) { - auto result = m_Renderer->Pick(pos); - EntityID entity = result.Entity; - if (glm::length2(m_WidgetCurrentAxis) > 0.f) { - // ??? - } else { - LOG_INFO("Selected %i", entity); - if (entity != EntityID_Invalid) { - EntityID parent = m_World->GetParent(entity); - m_Camera = result.Camera; - if (parent == m_Widget) { - m_WidgetCurrentAxis = glm::vec3( - (entity == m_WidgetX) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneY || entity == m_WidgetPlaneZ), - (entity == m_WidgetY) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneX || entity == m_WidgetPlaneZ), - (entity == m_WidgetZ) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneX || entity == m_WidgetPlaneY) - ); - m_WidgetPickingDepth = result.Depth; - //auto widgetTransform = m_World->GetComponent(m_Widget, "Transform"); - //auto selectionTransform = m_World->GetComponent(m_Selection, "Transform"); - //widgetTransform["Position"] = (glm::vec3)selectionTransform["Position"]; - } else { - ImGui::SetActiveID(0, nullptr); - if (m_WidgetMode == WidgetMode::None) { - m_WidgetMode = WidgetMode::Translate; - } - setWidgetMode(m_WidgetMode); - m_Selection = entity; - } - } + if (m_CurrentSelection.Valid()) { + glm::quat parentOrientation; + EntityWrapper parent = m_CurrentSelection.Parent(); + if (parent.Valid()) { + parentOrientation = glm::inverse(Transform::AbsoluteOrientation(parent.World, parent.ID)); } + (glm::vec3&)m_CurrentSelection["Transform"]["Position"] += parentOrientation * e.Translation; + m_EditorGUI->SetDirty(m_CurrentSelection); } - m_PickingQueue.clear(); -}; - -bool EditorSystem::OnFileDropped(const Events::FileDropped& e) -{ - m_LastDroppedFile = boost::filesystem::path(e.Path).lexically_relative(boost::filesystem::current_path()).string(); - std::replace(m_LastDroppedFile.begin(), m_LastDroppedFile.end(), '\\', '/'); return true; } -void EditorSystem::createWidget() +EntityWrapper EditorSystem::importEntity(EntityWrapper parent, boost::filesystem::path filePath) { - if (m_Widget == EntityID_Invalid) { - m_Widget = m_World->CreateEntity(); - m_World->AttachComponent(m_Widget, "Transform"); - m_WidgetX = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetX, "Transform"); - m_World->AttachComponent(m_WidgetX, "Model"); - m_WidgetPlaneX = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetPlaneX, "Transform"); - m_World->AttachComponent(m_WidgetPlaneX, "Model"); - m_World->GetComponent(m_WidgetPlaneX, "Model")["Resource"] = "Models/WidgetPlaneX.obj"; - m_WidgetY = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetY, "Transform"); - m_World->AttachComponent(m_WidgetY, "Model"); - m_WidgetPlaneY = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetPlaneY, "Transform"); - m_World->AttachComponent(m_WidgetPlaneY, "Model"); - m_World->GetComponent(m_WidgetPlaneY, "Model")["Resource"] = "Models/WidgetPlaneY.obj"; - m_WidgetZ = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetZ, "Transform"); - m_World->AttachComponent(m_WidgetZ, "Model"); - m_WidgetPlaneZ = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetPlaneZ, "Transform"); - m_World->AttachComponent(m_WidgetPlaneZ, "Model"); - m_World->GetComponent(m_WidgetPlaneZ, "Model")["Resource"] = "Models/WidgetPlaneZ.obj"; - m_WidgetOrigin = m_World->CreateEntity(m_Widget); - m_World->AttachComponent(m_WidgetOrigin, "Transform"); - m_World->AttachComponent(m_WidgetOrigin, "Model"); - setWidgetMode(WidgetMode::None); + if (parent.World == nullptr) { + LOG_ERROR("Tried to import entity \"%s\" into null world!", filePath.string().c_str()); + return EntityWrapper::Invalid; + } + + try { + auto entityFile = ResourceManager::Load(filePath.string()); + EntityFilePreprocessor fpp(entityFile); + fpp.RegisterComponents(parent.World); + EntityFileParser fp(entityFile); + EntityID newEntity = fp.MergeEntities(parent.World, parent.ID); + return EntityWrapper(parent.World, newEntity); + } catch (const std::exception&) { + return EntityWrapper::Invalid; } } -void EditorSystem::updateWidget() +void EditorSystem::setWidgetMode(EditorGUI::WidgetMode mode) { - if (m_Widget == EntityID_Invalid) { - return; - } - if (m_Selection == m_Widget) { + if (mode == m_WidgetMode && m_Widget.Valid() && m_CurrentSelection.Valid()) { return; } - if (m_Selection != EntityID_Invalid) { - auto widgetTransform = m_World->GetComponent(m_Widget, "Transform"); - glm::vec3 selectionPosition = Transform::AbsolutePosition(m_World, m_Selection); - widgetTransform["Position"] = selectionPosition; - if (m_WidgetSpace == WidgetSpace::Local) { - widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection)); - } - } -} + m_WidgetMode = mode; -void EditorSystem::setWidgetMode(WidgetMode newMode) -{ - if (m_Widget == EntityID_Invalid) { + if (m_Widget.Valid()) { + m_Widget.World->DeleteEntity(m_Widget.ID); + m_Widget = EntityWrapper::Invalid; + } + + if (!m_CurrentSelection.Valid()) { return; } - auto widgetTransform = m_World->GetComponent(m_Widget, "Transform"); - widgetTransform["Orientation"] = glm::vec3(0.f); - m_World->GetComponent(m_WidgetX, "Transform")["Scale"] = glm::vec3(1.f); - m_World->GetComponent(m_WidgetPlaneX, "Model")["Visible"] = false; - m_World->GetComponent(m_WidgetY, "Transform")["Scale"] = glm::vec3(1.f); - m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = false; - m_World->GetComponent(m_WidgetZ, "Transform")["Scale"] = glm::vec3(1.f); - m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = false; - m_World->GetComponent(m_WidgetOrigin, "Transform")["Scale"] = glm::vec3(1.f); - m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = false; - - if (newMode == WidgetMode::Translate) { - m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/TranslationWidgetX.obj"; - m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/TranslationWidgetY.obj"; - m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/TranslationWidgetZ.obj"; - // Temporarily disabled for local space until I can figure out what's wrong with the math - if (m_WidgetSpace != WidgetSpace::Local) { - m_World->GetComponent(m_WidgetPlaneX, "Model")["Visible"] = true; - m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = true; - m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = true; - } - if (m_Selection != EntityID_Invalid) { - if (m_WidgetSpace == WidgetSpace::Local) { - auto selectionTransform = m_World->GetComponent(m_Selection, "Transform"); - widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection)); - } - } - } else if (newMode == WidgetMode::Scale) { - m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/ScaleWidgetX.obj"; - m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/ScaleWidgetY.obj"; - m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/ScaleWidgetZ.obj"; - m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = true; - m_World->GetComponent(m_WidgetOrigin, "Model")["Resource"] = "Models/ScaleWidgetOrigin.obj"; - if (m_Selection != EntityID_Invalid) { - auto selectionTransform = m_World->GetComponent(m_Selection, "Transform"); - widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection)); - } - } else if (newMode == WidgetMode::Rotate) { - m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/RotationWidgetX.obj"; - m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/RotationWidgetY.obj"; - m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/RotationWidgetZ.obj"; - if (m_Selection != EntityID_Invalid) { - auto selectionTransform = m_World->GetComponent(m_Selection, "Transform"); - if (m_WidgetSpace == WidgetSpace::Local) { - widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection)); - } - } + switch (mode) { + case EditorGUI::WidgetMode::Translate: + m_Widget = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/EditorWidgetTranslate.xml"); + break; + case EditorGUI::WidgetMode::Rotate: + m_Widget = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/EditorWidgetRotate.xml"); + break; + case EditorGUI::WidgetMode::Scale: + m_Widget = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/EditorWidgetScale.xml"); + break; } - m_WidgetMode = newMode; -} - -void EditorSystem::setWidgetSpace(WidgetSpace space) -{ - m_WidgetSpace = space; - setWidgetMode(m_WidgetMode); -} - -void EditorSystem::drawUI(World* world, double dt) -{ - namespace bfs = boost::filesystem; - - ImGui::ShowTestWindow(); - //ImGui::ShowStyleEditor(); - - if (ImGui::BeginMainMenuBar()) { - if (ImGui::BeginMenu("File")) { - //if (ImGui::MenuItem("New")) { } - if (ImGui::MenuItem("Import", "Ctrl+O")) { - fileImport(world); - } - if (ImGui::MenuItem("Save", "Ctrl+S")) { - fileSave(world); - } - if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) { - fileSaveAs(world); - } - ImGui::Separator(); - if (ImGui::MenuItem("Close Editor", "F1")) { } - - ImGui::EndMenu(); - } - - ImGui::SameLine(); - if (ImGui::Button("Move")) { - setWidgetMode(WidgetMode::Translate); - } - ImGui::SameLine(); - if (ImGui::Button("Rotate")) { - setWidgetMode(WidgetMode::Rotate); - } - ImGui::SameLine(); - if (ImGui::Button("Scale")) { - setWidgetMode(WidgetMode::Scale); - } - ImGui::SameLine(); - if (m_WidgetSpace == WidgetSpace::Global) { - if (ImGui::Button("(Global)")) { - setWidgetSpace(WidgetSpace::Local); - } - } else if (m_WidgetSpace == WidgetSpace::Local) { - if (ImGui::Button("(Local)")) { - setWidgetSpace(WidgetSpace::Global); - } - } - - ImGui::EndMainMenuBar(); - } - - std::string title = std::string("Components #") + std::to_string(m_Selection) + std::string("###Components"); - if (ImGui::Begin(title.c_str())) { - if (m_Selection != EntityID_Invalid) { - auto& pools = world->GetComponentPools(); - - std::vector componentTypes; - for (auto& pair : pools) { - // Only add components the entity doesn't already have - if (!pair.second->KnowsEntity(m_Selection)) { - componentTypes.push_back(pair.first.c_str()); - } - } - int item = -1; - ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth() - 5.f); - if (ImGui::Combo("", &item, componentTypes.data(), componentTypes.size())) { - if (item != -1) { - std::string chosenType = std::string(componentTypes.at(item)); - world->AttachComponent(m_Selection, chosenType); - } - } - ImGui::PopItemWidth(); - - for (auto& pair : pools) { - const std::string& componentType = pair.first; - auto pool = pair.second; - if (!pool->KnowsEntity(m_Selection)) { - continue; - } - auto& ci = pool->ComponentInfo(); - - bool deletePressed = createDeleteButton(componentType); - if (deletePressed) { - world->DeleteComponent(m_Selection, componentType); - continue; - } - - if (ImGui::CollapsingHeader(componentType.c_str())) { - if (!ci.Meta->Annotation.empty()) { - ImGui::Text(ci.Meta->Annotation.c_str()); - } - - auto& component = world->GetComponent(m_Selection, componentType); - for (auto& kv : ci.Fields) { - const std::string& fieldName = kv.first; - auto& field = kv.second; - - std::string uniqueID = componentType + fieldName; - ImGui::PushID(uniqueID.c_str()); - if (field.Type == "Vector") { - auto& val = component.Field(fieldName); - if (fieldName == "Scale") { - ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits::max()); - } else if (fieldName == "Orientation") { - glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi())); - if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi())) { - val = tempVal; - } - } else { - ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits::lowest(), std::numeric_limits::max()); - } - } else if (field.Type == "Color") { - auto& val = component.Field(fieldName); - ImGui::ColorEdit4("", glm::value_ptr(val), true); - } else if (field.Type == "string") { - std::string& val = component.Field(fieldName); - char tempString[1024]; - memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString))); - if (ImGui::InputText("", tempString, sizeof(tempString))) { - val = std::string(tempString); - LOG_DEBUG("%s::%s changed!", componentType.c_str(), fieldName.c_str()); - } - // DROP STUFF - if (ImGui::IsItemHovered() && !m_LastDroppedFile.empty()) { - val = m_LastDroppedFile; - m_LastDroppedFile = ""; - } - - } else if (field.Type == "double") { - float tempVal = static_cast(component.Field(fieldName)); - if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { - component.SetField(fieldName, static_cast(tempVal)); - } - } else if (field.Type == "int") { - int val = component.Field(fieldName); - ImGui::InputInt("", &val); - } else if (field.Type == "enum") { - int currentValue = component.Field(fieldName); - int item = -1; - std::stringstream enumKeys; - std::vector enumValues; - int i = 0; - for (auto& kv : ci.Meta->FieldEnumDefinitions.at(fieldName)) { - enumKeys << kv.first << " (" << kv.second << ")" << '\0'; - enumValues.push_back(kv.second); - if (currentValue == kv.second) { - item = i; - } - i++; - } - if (ImGui::Combo("", &item, enumKeys.str().c_str())) { - component.SetField(fieldName, enumValues.at(item)); - } - } else if (field.Type == "bool") { - auto& val = component.Field(fieldName); - ImGui::Checkbox("", &val); - } else { - ImGui::TextDisabled(field.Type.c_str()); - } - ImGui::PopID(); - - ImGui::SameLine(); - ImGui::Text(fieldName.c_str()); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("field annotation goes here"); - } - } - } - } - } - - } - ImGui::End(); - - if (ImGui::Begin("Entities")) { - auto entityChildren = world->GetEntityChildren(); - std::function recurse = [&](EntityID parent) { - auto range = entityChildren.equal_range(parent); - for (auto it = range.first; it != range.second; it++) { - if (createEntityNode(world, it->second)) { - recurse(it->second); - ImGui::TreePop(); - } - } - }; - recurse(EntityID_Invalid); - } - ImGui::End(); -} - -bool EditorSystem::createEntityNode(World* world, EntityID entity) -{ - // HACK: Don't show the widget entities in the entity tree - if (entity == m_Widget) { - return false; - } - - ImVec2 pos = ImGui::GetCursorScreenPos(); - float width = ImGui::GetContentRegionAvailWidth(); - ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13)); - auto window = ImGui::GetCurrentWindow(); - if (m_Selection == entity) { - const ImU32 col = window->Color(ImGuiCol_HeaderActive); - window->DrawList->AddRectFilled(bb.Min, bb.Max, col); - } - ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity)).c_str()); - bool hovered = false; - bool held = false; - if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) { - m_Selection = entity; - } - if (held) { - ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0); - if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) { - if (m_UIDraggingEntity == EntityID_Invalid) { - m_UIDraggingEntity = entity; - LOG_DEBUG("Started drag of entity %i", m_UIDraggingEntity); - } - ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0)); - ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings); - ImGui::Text("#%i", m_UIDraggingEntity); - ImGui::End(); - } - } - - ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once); - std::string nodeTitle; - const std::string& entityName = world->GetName(entity); - if (!entityName.empty()) { - nodeTitle = entityName; - } else { - nodeTitle = std::string("#") + std::to_string(entity); - } - if (ImGui::TreeNode(nodeTitle.c_str())) { - if (m_UIDraggingEntity != EntityID_Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) { - LOG_DEBUG("Changed parent of %i to %i", m_UIDraggingEntity, entity); - changeParent(m_UIDraggingEntity, entity); - m_UIDraggingEntity = EntityID_Invalid; - } - - if (ImGui::BeginPopupContextItem("item context menu")) { - if (ImGui::Button("Add")) { - EntityID newEntity = world->CreateEntity(entity); - world->AttachComponent(newEntity, "Transform"); - } - ImGui::SameLine(); - if (ImGui::Button("Delete")) { - world->DeleteEntity(entity); - ImGui::CloseCurrentPopup(); - if (!world->ValidEntity(m_Selection)) { - m_Selection = EntityID_Invalid; - } - } - ImGui::EndPopup(); - } - return true; - } else { - return false; - } -} - -bool EditorSystem::createDeleteButton(std::string componentType) -{ - float width = ImGui::GetContentRegionAvailWidth(); - ImGuiWindow* window = ImGui::GetCurrentWindow(); - auto pos = ImGui::GetCursorScreenPos() + ImVec2(width - 14.f, 1); - ImRect bb = ImRect(pos, pos + ImVec2(14.f, 14.f)); - std::string idString = "#DELETE"; - idString += componentType; - ImGuiID id = window->GetID(idString.c_str()); - bool hovered; - bool held; - bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); - //ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); - ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - window->DrawList->AddCircleFilled(bb.GetCenter(), 7.f, col, 16); - return pressed; -} - -void EditorSystem::changeParent(EntityID entity, EntityID newParent) -{ - if (entity == newParent) { - return; - } - - // An entity can't be a child to one of its own children - auto children = m_World->GetEntityChildren().equal_range(entity); - for (auto it = children.first; it != children.second; it++) { - if (it->second == newParent) { - return; - } - } - - m_World->SetParent(entity, newParent); -} - -void EditorSystem::fileImport(World* world) -{ - m_CurrentFile = openDialog(m_DefaultEntityDir); - auto file = ResourceManager::Load(m_CurrentFile.string()); - EntityFilePreprocessor fpp(file); - fpp.RegisterComponents(world); - EntityFileParser fp(file); - fp.MergeEntities(world); - createWidget(); - updateWidget(); -} - -void EditorSystem::fileSave(World* world) -{ - if (boost::filesystem::exists(m_CurrentFile)) { - // HACK: Delete the widgets so they don't appear in the saved file - world->DeleteEntity(m_Widget); - m_Widget = EntityID_Invalid; - - EntityFileWriter writer(m_CurrentFile.string()); - writer.WriteWorld(world); - - createWidget(); - } else { - fileSaveAs(world); - } -} - -void EditorSystem::fileSaveAs(World* world) -{ - auto filePath = saveDialog(m_DefaultEntityDir); - if (filePath.empty()) { - return; - } - - // HACK: Delete the widgets so they don't appear in the saved file - world->DeleteEntity(m_Widget); - m_Widget = EntityID_Invalid; - - EntityFileWriter writer(filePath.string()); - writer.WriteWorld(world); - - createWidget(); + + m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID); } diff --git a/src/Engine/Editor/EditorWidgetSystem.cpp b/src/Engine/Editor/EditorWidgetSystem.cpp new file mode 100644 index 00000000..f0c72ab0 --- /dev/null +++ b/src/Engine/Editor/EditorWidgetSystem.cpp @@ -0,0 +1,74 @@ +#include "Editor/EditorWidgetSystem.h" + +EditorWidgetSystem::EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer) + : System(world, eventBroker) + , PureSystem("EditorWidget") + , m_Renderer(renderer) +{ + EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorWidgetSystem::OnMouseMove); + EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorWidgetSystem::OnMousePress); + EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorWidgetSystem::OnMouseRelease); +} + +void EditorWidgetSystem::Update(double dt) +{ + // Pick at current mouse position +} + +void EditorWidgetSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cEditorWidget, double dt) +{ + if (!m_PickEntity.Valid() || m_PickEntity != entity) { + return; + } + + Events::WidgetDelta e; + + EntityWrapper moveEntity = entity.Parent(); + if (!moveEntity.Valid()) { + moveEntity = entity; + } + + auto camera = m_PickData.Camera; + glm::vec3 axis = cEditorWidget["Axis"]; + glm::vec2 axisScreen = camera->WorldToScreen(axis, m_Renderer->Resolution()) - camera->WorldToScreen(glm::vec3(0, 0, 0), m_Renderer->Resolution()); + float dot = glm::dot(m_MouseDelta, glm::normalize(axisScreen)) / glm::length(axisScreen); + glm::vec3 worldMovement = dot * axis; + + ComponentWrapper::SubscriptProxy& type = cEditorWidget["Type"]; + if ((ComponentInfo::EnumType)type == type.Enum("Translate")) { + e.Translation += worldMovement; + m_EventBroker->Publish(e); + } else if ((ComponentInfo::EnumType)type == type.Enum("Rotate")) { + //if (glm::length(worldMovement) > 0) { + // glm::vec3& orientation = moveEntity["Transform"]["Orientation"]; + // glm::quat q = glm::quat(orientation); + // q *= glm::quat(glm::vec3(worldMovement)); + // orientation = glm::eulerAngles(q); + //} + } + + m_MouseDelta = glm::vec2(0); +} + +bool EditorWidgetSystem::OnMouseMove(const Events::MouseMove& e) +{ + m_MouseDelta = glm::vec2((float)e.DeltaX, (float)-e.DeltaY); + return false; +} + +bool EditorWidgetSystem::OnMousePress(const Events::MousePress & e) +{ + if (e.Button == GLFW_MOUSE_BUTTON_1) { + m_PickData = m_Renderer->Pick(glm::vec2(e.X, e.Y)); + if (m_PickData.Entity != EntityID_Invalid && m_PickData.World == m_World) { + m_PickEntity = EntityWrapper(m_World, m_PickData.Entity); + } + } + return true; +} + +bool EditorWidgetSystem::OnMouseRelease(const Events::MouseRelease& e) +{ + m_PickEntity = EntityWrapper::Invalid; + return true; +} \ No newline at end of file diff --git a/src/Engine/Rendering/Camera.cpp b/src/Engine/Rendering/Camera.cpp index 5a774c34..f6b2e5ef 100644 --- a/src/Engine/Rendering/Camera.cpp +++ b/src/Engine/Rendering/Camera.cpp @@ -79,6 +79,19 @@ void Camera::UpdateProjectionMatrix() m_ProjectionMatrix = glm::perspective(m_FOV, m_AspectRatio, m_NearClip, m_FarClip); } +glm::vec2 Camera::WorldToScreen(glm::vec3 worldCoord, Rectangle resolution) +{ + glm::vec4 screenCoord = m_ProjectionMatrix * m_ViewMatrix * glm::vec4(worldCoord, 1.f); + if (screenCoord.w != 0) { + screenCoord.x /= screenCoord.w; + screenCoord.y /= screenCoord.w; + screenCoord.z /= screenCoord.w; + } + screenCoord.x = screenCoord.x * (resolution.Width / 2.f); + screenCoord.y = screenCoord.y * (resolution.Height / 2.f); + return glm::vec2(screenCoord); +} + void Camera::UpdateViewMatrix() { m_ViewMatrix = glm::toMat4(glm::inverse(m_Orientation)) diff --git a/src/Engine/Rendering/DrawFinalPass.cpp b/src/Engine/Rendering/DrawFinalPass.cpp index b0ca4afe..eeaa7bb3 100644 --- a/src/Engine/Rendering/DrawFinalPass.cpp +++ b/src/Engine/Rendering/DrawFinalPass.cpp @@ -27,15 +27,20 @@ void DrawFinalPass::Draw(RenderScene& scene) GLERROR("DrawFinalPass::Draw: Pre"); DrawFinalPassState state; + m_ForwardPlusProgram->Bind(); GLuint shaderHandle = m_ForwardPlusProgram->GetHandle(); + if (scene.ClearDepth) { + glClear(GL_DEPTH_BUFFER_BIT); + } + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightCullingPass->LightSSBO()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO()); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ViewMatrix())); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ProjectionMatrix())); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height); //TODO: Render: Add code for more jobs than modeljobs. diff --git a/src/Engine/Rendering/DrawFinalPassState.cpp b/src/Engine/Rendering/DrawFinalPassState.cpp index 1cb9d7da..2cda4069 100644 --- a/src/Engine/Rendering/DrawFinalPassState.cpp +++ b/src/Engine/Rendering/DrawFinalPassState.cpp @@ -9,7 +9,6 @@ DrawFinalPassState::DrawFinalPassState() Enable(GL_DEPTH_TEST); Enable(GL_CULL_FACE); ClearColor(glm::vec4(200.f / 255, 0.f / 255, 200.f / 255, 0.f)); - Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } DrawFinalPassState::~DrawFinalPassState() diff --git a/src/Engine/Rendering/DrawScenePass.cpp b/src/Engine/Rendering/DrawScenePass.cpp deleted file mode 100644 index 7871f1dd..00000000 --- a/src/Engine/Rendering/DrawScenePass.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "Rendering/DrawScenePass.h" - -DrawScenePass::DrawScenePass(IRenderer* renderer) -{ - m_Renderer = renderer; - InitializeTextures(); - InitializeShaderPrograms(); -} - -void DrawScenePass::InitializeTextures() -{ - m_WhiteTexture = ResourceManager::Load("Textures/Core/Blank.png"); -} - -void DrawScenePass::InitializeShaderPrograms() -{ - m_BasicForwardProgram = ResourceManager::Load("#BasicForwardProgram"); - - m_BasicForwardProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/BasicForward.vert.glsl"))); - m_BasicForwardProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/BasicForward.frag.glsl"))); - m_BasicForwardProgram->Compile(); - m_BasicForwardProgram->Link(); -} - -void DrawScenePass::Draw(RenderScene& scene) -{ - //glBindFramebuffer(GL_FRAMEBUFFER, 0); - GLERROR("DrawScenePass::Draw: Pre"); - - DrawScenePassState state = DrawScenePassState(); - m_BasicForwardProgram->Bind(); - - for (auto &job : scene.ForwardJobs) { - auto modelJob = std::dynamic_pointer_cast(job); - if (modelJob) { - GLuint ShaderHandle = m_BasicForwardProgram->GetHandle(); - - //TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms - glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); - glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); - glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); - glUniform4fv(glGetUniformLocation(ShaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color)); - - //TODO: Renderer: bättre textur felhantering samt fler texturer stöd - if (modelJob->DiffuseTexture != nullptr) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, modelJob->DiffuseTexture->m_Texture); - } else { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); - } - - glBindVertexArray(modelJob->Model->VAO); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex); - - //continue; - } - - } - GLERROR("DrawScenePass::Draw: End"); -} diff --git a/src/Engine/Rendering/DrawScenePassState.cpp b/src/Engine/Rendering/DrawScenePassState.cpp deleted file mode 100644 index 2d643697..00000000 --- a/src/Engine/Rendering/DrawScenePassState.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Rendering/DrawScenePassState.h" - - -DrawScenePassState::DrawScenePassState() -{ - GLERROR("---"); - BindFramebuffer(0); - GLERROR("---"); - Enable(GL_DEPTH_TEST); - Enable(GL_CULL_FACE); - Enable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // ClearColor(glm::vec4(255.f / 255, 163.f / 255, 176.f / 255, 0.f)); - // Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -DrawScenePassState::~DrawScenePassState() -{ - -} diff --git a/src/Engine/Rendering/ImGuiRenderPass.cpp b/src/Engine/Rendering/ImGuiRenderPass.cpp index 96f987d9..e67eea71 100644 --- a/src/Engine/Rendering/ImGuiRenderPass.cpp +++ b/src/Engine/Rendering/ImGuiRenderPass.cpp @@ -105,7 +105,7 @@ void ImGuiRenderPass::Draw() if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); } else { - glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); + glBindTexture(GL_TEXTURE_2D, (GLuint)pcmd->TextureId); glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); } @@ -190,7 +190,7 @@ bool ImGuiRenderPass::createDeviceObjects() "{\n" " Frag_UV = UV;\n" " Frag_Color = Color;\n" - " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" + " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n" "}\n"; const GLchar* fragment_shader = @@ -201,7 +201,7 @@ bool ImGuiRenderPass::createDeviceObjects() "out vec4 Out_Color;\n" "void main()\n" "{\n" - " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" + " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n" "}\n"; g_ShaderHandle = glCreateProgram(); @@ -271,7 +271,7 @@ bool ImGuiRenderPass::createFontsTexture() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier - io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; + io.Fonts->TexID = (void*)g_FontTexture; // Restore state glBindTexture(GL_TEXTURE_2D, last_texture); diff --git a/src/Engine/Rendering/PickingPass.cpp b/src/Engine/Rendering/PickingPass.cpp index 6800df1d..3b5ade59 100644 --- a/src/Engine/Rendering/PickingPass.cpp +++ b/src/Engine/Rendering/PickingPass.cpp @@ -53,7 +53,9 @@ void PickingPass::Draw(RenderScene& scene) GLuint ShaderHandle = m_PickingProgram->GetHandle(); m_PickingProgram->Bind(); - + if (scene.ClearDepth) { + glClear(GL_DEPTH_BUFFER_BIT); + } m_Camera = scene.Camera; diff --git a/src/Engine/Rendering/RenderState.cpp b/src/Engine/Rendering/RenderState.cpp index 4c47a8a2..1da2f0b1 100644 --- a/src/Engine/Rendering/RenderState.cpp +++ b/src/Engine/Rendering/RenderState.cpp @@ -44,12 +44,6 @@ bool RenderState::ClearColor(glm::vec4 color) return !GLERROR("RenderState::ClearColor"); } -bool RenderState::Clear(GLbitfield mask) -{ - glClear(mask); - return !GLERROR("RenderState::Clear"); -} - bool RenderState::BindFramebuffer(GLint framebuffer) { GLint originalRead; @@ -91,6 +85,15 @@ bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor) return !GLERROR("RenderState::BlendFunc"); } +bool RenderState::DepthMask(GLboolean flag) +{ + GLboolean original; + glGetBooleanv(GL_DEPTH_WRITEMASK, &original); + m_ResetFunctions.push_back(std::bind(glDepthMask, original)); + glDepthMask(flag); + return !GLERROR("RenderState::DepthMask"); +} + RenderState::~RenderState() { for (auto& f : m_ResetFunctions) { diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index a31d3094..80b6696c 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -1,7 +1,7 @@ #include "Rendering/RenderSystem.h" -RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame) - : System(eventBroker) +RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame) + : System(world, eventBroker) , m_Renderer(renderer) , m_RenderFrame(renderFrame) { @@ -9,74 +9,29 @@ RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer, EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand); m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f); - m_DebugCameraInputController = new DebugCameraInputController(eventBroker, -1); } RenderSystem::~RenderSystem() { delete m_Camera; - delete m_DebugCameraInputController; } -bool RenderSystem::OnSetCamera(const Events::SetCamera &event) +bool RenderSystem::OnSetCamera(Events::SetCamera& e) { - auto cameras = m_World->GetComponents("Camera"); - - if (cameras != nullptr) { - for (auto it = cameras->begin(); it != cameras->end(); it++) { - if ((std::string)(*it)["Name"] == event.Name) { - switchCamera((*it).EntityID); - } - } - } + ComponentWrapper cTransform = e.CameraEntity["Transform"]; + ComponentWrapper cCamera = e.CameraEntity["Camera"]; + m_Camera->SetFOV((double)cCamera["FOV"]); + m_Camera->SetNearClip((double)cCamera["NearClip"]); + m_Camera->SetFarClip((double)cCamera["FarClip"]); + m_Camera->SetPosition(cTransform["Position"]); + m_Camera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"])); + m_CurrentCamera = e.CameraEntity; return true; } -void RenderSystem::switchCamera(EntityID entity) +void RenderSystem::fillModels(std::list>& jobs) { - if(m_World->HasComponent(entity, "Camera")) { - - if (m_CurrentCamera != EntityID_Invalid) { - if (m_World->HasComponent(m_CurrentCamera, "Model")) { - m_World->GetComponent(m_CurrentCamera, "Model")["Visible"] = true; - } - if (m_World->HasComponent(m_CurrentCamera, "Listener")) { - m_World->DeleteComponent(m_CurrentCamera, "Listener"); - } - } - - if (m_World->HasComponent(entity, "Model")) { - m_World->GetComponent(entity, "Model")["Visible"] = false; - } - if (!m_World->HasComponent(entity, "Listener")) { - m_World->AttachComponent(entity, "Listener"); - } - m_CurrentCamera = entity; - m_SwitchCamera = false; - - } else { - LOG_ERROR("Entity %i does not have a CameraComponent", entity); - m_SwitchCamera = false; - } -} - -void RenderSystem::updateProjectionMatrix(ComponentWrapper& cameraComponent) -{ - double fov = cameraComponent["FOV"]; - double aspectRatio = (float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height; - double nearClip = cameraComponent["NearClip"]; - double farClip = cameraComponent["FarClip"]; - - m_Camera->SetFOV(glm::radians(fov)); - m_Camera->SetAspectRatio(aspectRatio); - m_Camera->SetNearClip(nearClip); - m_Camera->SetFarClip(farClip); - m_Camera->UpdateProjectionMatrix(); -} - -void RenderSystem::fillModels(std::list>& jobs, World* world) -{ - auto models = world->GetComponents("Model"); + auto models = m_World->GetComponents("Model"); if (models == nullptr) { return; } @@ -105,18 +60,17 @@ void RenderSystem::fillModels(std::list>& jobs, World } } - glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, world); + glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, m_World); for (auto matGroup : model->MaterialGroups()) { - std::shared_ptr modelJob = std::shared_ptr(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, world)); + std::shared_ptr modelJob = std::shared_ptr(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, m_World)); jobs.push_back(modelJob); } } } - void RenderSystem::fillPointLights(std::list>& jobs, World* world) { - auto pointLights = world->GetComponents("PointLight"); + auto pointLights = m_World->GetComponents("PointLight"); if (pointLights != nullptr) { for (auto& pointlightC : *pointLights) { bool visible = pointlightC["Visible"]; @@ -158,96 +112,26 @@ void RenderSystem::fillDirectionalLights(std::list>& bool RenderSystem::OnInputCommand(const Events::InputCommand& e) { - if (e.Command == "SwitchCamera" && e.Value > 0) { - m_SwitchCamera = true; - return true; - } else { - return false; - } + return false; } -void RenderSystem::Update(World* world, double dt) +void RenderSystem::Update(double dt) { - m_World = world; m_EventBroker->Process(); - updateCamera(world, dt); - + if (m_CurrentCamera) { + ComponentWrapper cameraTransform = m_CurrentCamera["Transform"]; + m_Camera->SetPosition(cameraTransform["Position"]); + m_Camera->SetOrientation(glm::quat((const glm::vec3&)cameraTransform["Orientation"])); + } //Only supports opaque geometry atm - m_RenderFrame->Clear(); RenderScene scene; scene.Camera = m_Camera; scene.Viewport = Rectangle(1280, 720); - fillModels(scene.ForwardJobs, world); - fillPointLights(scene.PointLightJobs, world); - fillDirectionalLights(scene.DirectionalLightJobs, world); + fillModels(scene.ForwardJobs); + fillPointLights(scene.PointLightJobs, m_World); + fillDirectionalLights(scene.DirectionalLightJobs, m_World); m_RenderFrame->Add(scene); -} - -void RenderSystem::updateCamera(World* world, double dt) -{ - if (m_SwitchCamera) { - auto cameras = world->GetComponents("Camera"); - if (cameras == nullptr) { - return; - } - for (auto it = cameras->begin(); it != cameras->end(); it++) { - if ((*it).EntityID == m_CurrentCamera) { - it++; - if (it != cameras->end()) { - switchCamera((*it).EntityID); - } else { - switchCamera((*cameras->begin()).EntityID); - } - break; - } - } - if (m_World->HasComponent(m_CurrentCamera, "Camera")) { - ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); - ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); - - m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"])); - m_DebugCameraInputController->SetPosition(cameraTransform["Position"]); - } - } - - if (m_World->ValidEntity(m_CurrentCamera)) { - if (world->HasComponent(m_CurrentCamera, "Camera") && world->HasComponent(m_CurrentCamera, "Transform")) { - ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); - ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); - - m_DebugCameraInputController->Update(dt); - (glm::vec3&)cameraTransform["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation()); - (glm::vec3&)cameraTransform["Position"] = m_DebugCameraInputController->Position(); - - glm::vec3 position = Transform::AbsolutePosition(world, m_CurrentCamera); - glm::quat orientation = Transform::AbsoluteOrientation(world, m_CurrentCamera); - - m_Camera->SetPosition(position); - m_Camera->SetOrientation(orientation); - - updateProjectionMatrix(cameraComponent); - - } - } else { - m_Camera = m_Camera; - - auto cameras = world->GetComponents("Camera"); - if (cameras != nullptr) { - if (cameras->begin() != cameras->end()) { - ComponentWrapper& cameraC = *cameras->begin(); - switchCamera(cameraC.EntityID); - - ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); - ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); - - m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"])); - m_DebugCameraInputController->SetPosition(cameraTransform["Position"]); - } - } - } - - m_Camera->UpdateViewMatrix(); } \ No newline at end of file diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index 8c30adfd..c0347612 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -15,15 +15,6 @@ void Renderer::Initialize() m_UnitSphere = ResourceManager::Load("Models/Core/UnitSphere.obj"); m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker); - - - // Create default camera - m_DefaultCamera = new ::Camera((float)m_Resolution.Width / m_Resolution.Height, glm::radians(45.f), 0.01f, 5000.f); - m_DefaultCamera->SetPosition(glm::vec3(0, 0, 10)); - if (m_Camera == nullptr) { - m_Camera = m_DefaultCamera; - } - } void Renderer::InitializeWindow() @@ -92,13 +83,11 @@ void Renderer::Update(double dt) void Renderer::Draw(RenderFrame& frame) { glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - m_PickingPass->ClearPicking(); for (auto scene : frame.RenderScenes){ - m_Camera = scene->Camera; // remove renderer camera when Editor uses the render scene cameras. + SortRenderJobsByDepth(*scene); m_PickingPass->Draw(*scene); m_LightCullingPass->GenerateNewFrustum(*scene); @@ -167,8 +156,7 @@ void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filterin void Renderer::InitializeRenderPasses() { - m_DrawScenePass = new DrawScenePass(this); m_PickingPass = new PickingPass(this, m_EventBroker); m_LightCullingPass = new LightCullingPass(this); m_DrawFinalPass = new DrawFinalPass(this, m_LightCullingPass); -} \ No newline at end of file +} diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 8d647f6f..7b2f114e 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -29,7 +29,6 @@ Game::Game(int argc, char* argv[]) // Create the core event broker m_EventBroker = new EventBroker(); - // Create the renderer m_Renderer = new Renderer(m_EventBroker); m_Renderer->SetFullscreen(m_Config->Get("Video.Fullscreen", false)); @@ -72,12 +71,11 @@ Game::Game(int argc, char* argv[]) m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); @@ -94,6 +92,8 @@ Game::Game(int argc, char* argv[]) ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); + ++updateOrderLevel; + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); // Invoke network if (m_Config->Get("Networking.StartNetwork", false)) { @@ -145,12 +145,14 @@ void Game::Tick() m_ClientOrServer->Update(); } // Iterate through systems and update world! - m_SystemPipeline->Update(m_World, dt); + m_EventBroker->Process(); + m_SystemPipeline->Update(dt); debugTick(dt); m_Renderer->Update(dt); m_SoundSystem->Update(dt); GLERROR("Game::Tick m_RenderQueueFactory->Update"); m_Renderer->Draw(*m_RenderFrame); + m_RenderFrame->Clear(); GLERROR("Game::Tick m_Renderer->Draw"); m_EventBroker->Swap(); m_EventBroker->Clear(); diff --git a/src/Game/Systems/CapturePointSystem.cpp b/src/Game/Systems/CapturePointSystem.cpp index 94ec8d62..67c2353c 100644 --- a/src/Game/Systems/CapturePointSystem.cpp +++ b/src/Game/Systems/CapturePointSystem.cpp @@ -1,9 +1,9 @@ #include "Systems/CapturePointSystem.h" #include -CapturePointSystem::CapturePointSystem(EventBroker* eventBroker) - : System(eventBroker), - PureSystem("CapturePoint") +CapturePointSystem::CapturePointSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) + , PureSystem("CapturePoint") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &CapturePointSystem::OnTriggerTouch); @@ -13,22 +13,22 @@ CapturePointSystem::CapturePointSystem(EventBroker* eventBroker) //here all capturepoints will update their component //NOTE: needs to run each frame, since we're possibly modifying the captureTimer for the capturePoints by dt -void CapturePointSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) +void CapturePointSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) { if (m_WinnerWasFound) { return; } const int capturePointNumber = capturePoint["CapturePointNumber"]; - const bool hasTeamComponent = world->HasComponent(capturePoint.EntityID, "Team"); + const bool hasTeamComponent = m_World->HasComponent(capturePoint.EntityID, "Team"); //if point doesnt have a teamComponent yet, add one. since: //what if capture point has no team -> we cant get/use the team enum from it... if (!hasTeamComponent) { - world->AttachComponent(capturePoint.EntityID, "Team"); - ComponentWrapper& teamComponent = world->GetComponent(capturePoint.EntityID, "Team"); + m_World->AttachComponent(capturePoint.EntityID, "Team"); + ComponentWrapper& teamComponent = m_World->GetComponent(capturePoint.EntityID, "Team"); teamComponent["Team"] = (int)teamComponent["Team"].Enum("Spectator"); } - ComponentWrapper& teamComponent = world->GetComponent(capturePoint.EntityID, "Team"); + ComponentWrapper& teamComponent = m_World->GetComponent(capturePoint.EntityID, "Team"); const int redTeam = (int)teamComponent["Team"].Enum("Red"); const int blueTeam = (int)teamComponent["Team"].Enum("Blue"); const int spectatorTeam = (int)teamComponent["Team"].Enum("Spectator"); @@ -66,7 +66,7 @@ void CapturePointSystem::UpdateComponent(World* world, EntityWrapper& entity, Co nextPossibleCapturePoint["Blue"] = -1; for (size_t i = 0; i < m_NumberOfCapturePoints; i++) { - ComponentWrapper& capturePointOwnedBy = world->GetComponent(m_CapturePointNumberToEntityIDMap[i], "Team"); + ComponentWrapper& capturePointOwnedBy = m_World->GetComponent(m_CapturePointNumberToEntityIDMap[i], "Team"); if ((int)capturePointOwnedBy["Team"] == redTeam && m_RedTeamHomeCapturePoint == 0) { nextPossibleCapturePoint["Red"] = i + 1; } @@ -76,7 +76,7 @@ void CapturePointSystem::UpdateComponent(World* world, EntityWrapper& entity, Co } for (int i = m_NumberOfCapturePoints - 1; i >= 0; i--) { - ComponentWrapper& capturePointOwnedBy = world->GetComponent(m_CapturePointNumberToEntityIDMap[i], "Team"); + ComponentWrapper& capturePointOwnedBy = m_World->GetComponent(m_CapturePointNumberToEntityIDMap[i], "Team"); if ((int)capturePointOwnedBy["Team"] == redTeam && m_RedTeamHomeCapturePoint != 0) { nextPossibleCapturePoint["Red"] = i - 1; } @@ -89,7 +89,7 @@ void CapturePointSystem::UpdateComponent(World* world, EntityWrapper& entity, Co if (m_ResetTimers) { for (size_t i = 0; i < m_NumberOfCapturePoints; i++) { - ComponentWrapper& capturePoint = world->GetComponent(m_CapturePointNumberToEntityIDMap[i], "CapturePoint"); + ComponentWrapper& capturePoint = m_World->GetComponent(m_CapturePointNumberToEntityIDMap[i], "CapturePoint"); if ((int)capturePoint["CapturePointNumber"] != nextPossibleCapturePoint["Red"] && (int)capturePoint["CapturePointNumber"] != nextPossibleCapturePoint["Blue"]) { capturePoint["CaptureTimer"] = 0.0; @@ -113,21 +113,21 @@ void CapturePointSystem::UpdateComponent(World* world, EntityWrapper& entity, Co if (std::get<1>(triggerTouched) == capturePoint.EntityID) { //some player has touched this - lets figure out: what team, health EntityID playerID = std::get<0>(triggerTouched); - if (!world->HasComponent(playerID, "Player")) { + if (!m_World->HasComponent(playerID, "Player")) { //if a non-player has entered the capturePoint, just erase that event and continue m_ETriggerTouchVector.erase(m_ETriggerTouchVector.begin() + i - 1); continue; } - bool hasHealthComponent = world->HasComponent(playerID, "Health"); + bool hasHealthComponent = m_World->HasComponent(playerID, "Health"); if (hasHealthComponent) { - double currentHealth = world->GetComponent(playerID, "Health")["Health"]; + double currentHealth = m_World->GetComponent(playerID, "Health")["Health"]; //check if player is dead if ((int)currentHealth == 0) { continue; } } //check team - spectatorNumber = "no team" - int teamNumber = world->GetComponent(playerID, "Team")["Team"]; + int teamNumber = m_World->GetComponent(playerID, "Team")["Team"]; if (teamNumber == redTeam) { redTeamPlayersStandingInside++; } else if (teamNumber == blueTeam) { diff --git a/src/Game/Systems/HealthSystem.cpp b/src/Game/Systems/HealthSystem.cpp index 7d4b96b8..5e5be33e 100644 --- a/src/Game/Systems/HealthSystem.cpp +++ b/src/Game/Systems/HealthSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/HealthSystem.h" -HealthSystem::HealthSystem(EventBroker* eventBroker) - : System(eventBroker) +HealthSystem::HealthSystem(World* m_World, EventBroker* eventBroker) + : System(m_World, eventBroker) , PureSystem("Health") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) @@ -9,9 +9,10 @@ HealthSystem::HealthSystem(EventBroker* eventBroker) EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup); } -void HealthSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) +void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { //if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity) + ComponentWrapper player = m_World->GetComponent(component.EntityID, "Player"); double maxHealth = (double)component["MaxHealth"]; //process the DeltaHealthVector and change the entitys health accordingly @@ -38,7 +39,7 @@ void HealthSystem::UpdateComponent(World* world, EntityWrapper& entity, Componen m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + j - 1); } //delete the player and break the loop - world->DeleteEntity(entity.ID); + m_World->DeleteEntity(entity.ID); break; } } diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index f6d5989d..75f68678 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -20,7 +20,7 @@ // } //} -void InterpolationSystem::UpdateComponent(World * world, EntityWrapper& entity, ComponentWrapper & transform, double dt) +void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) { if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map m_NextTransform[transform.EntityID].interpolationTime += dt; diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index 57eef38d..e14cd146 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -1,6 +1,6 @@ #include "Systems/PlayerMovementSystem.h" -void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) +void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { ComponentWrapper& cTransform = entity["Transform"]; if (!entity.HasComponent("Physics")) { diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index 0bf5bdea..4224d46c 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -1,21 +1,21 @@ #include "Systems/PlayerSpawnSystem.h" -PlayerSpawnSystem::PlayerSpawnSystem(EventBroker* eventBroker) - : System(eventBroker) +PlayerSpawnSystem::PlayerSpawnSystem(World* m_World, EventBroker* eventBroker) + : System(m_World, eventBroker) { EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand); } -void PlayerSpawnSystem::Update(World* world, double dt) +void PlayerSpawnSystem::Update(double dt) { - auto playerSpawns = world->GetComponents("PlayerSpawn"); + auto playerSpawns = m_World->GetComponents("PlayerSpawn"); if (playerSpawns == nullptr) { return; } for (auto& team : m_SpawnRequests) { for (auto& cPlayerSpawn : *playerSpawns) { - EntityWrapper spawner(world, cPlayerSpawn.EntityID); + EntityWrapper spawner(m_World, cPlayerSpawn.EntityID); if (!spawner.HasComponent("Spawner")) { continue; } diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp index 3454c58b..8cb5b99d 100644 --- a/src/Game/Systems/SpawnerSystem.cpp +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -1,6 +1,7 @@ #include "Systems/SpawnerSystem.h" -SpawnerSystem::SpawnerSystem(EventBroker* eventBroker) : System(eventBroker) +SpawnerSystem::SpawnerSystem(World* world, EventBroker* eventBroker) + : System(world, eventBroker) { EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); } diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index 22a6e62e..dd26793b 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -103,7 +103,7 @@ void GameHealthSystemTest::Tick() m_LastTime = currentTime; // Iterate through systems and update world! - m_SystemPipeline->Update(m_World, dt); + m_SystemPipeline->Update(dt); m_EventBroker->Swap(); m_EventBroker->Clear();