Rendering pipeline fixes across the board and base work on refactored editor
This commit is contained in:
@@ -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(EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame);
|
||||||
|
|
||||||
|
virtual void Update(World* world, double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IRenderer* m_Renderer;
|
||||||
|
RenderFrame* m_RenderFrame;
|
||||||
|
Camera* m_EditorCamera;
|
||||||
|
EntityWrapper m_CurrentCamera = EntityWrapper::Invalid;
|
||||||
|
|
||||||
|
EventRelay<EditorRenderSystem, Events::SetCamera> m_ESetCamera;
|
||||||
|
bool OnSetCamera(Events::SetCamera& e);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,94 +1,30 @@
|
|||||||
#include <imgui/imgui.h>
|
|
||||||
#include <glm/gtx/common.hpp>
|
|
||||||
#include <boost/filesystem/path.hpp>
|
|
||||||
#include <nativefiledialog/nfd.h>
|
|
||||||
#include "../Core/System.h"
|
#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 "../Rendering/IRenderer.h"
|
||||||
#include "../Core/Transform.h"
|
#include "../Rendering/Camera.h"
|
||||||
#include "../Core/EFileDropped.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/EntityFilePreprocessor.h"
|
||||||
#include "../Core/EntityFileParser.h"
|
#include "../Core/EntityFileParser.h"
|
||||||
#include "../Core/EntityFileWriter.h"
|
|
||||||
|
|
||||||
class EditorSystem : public ImpureSystem
|
class EditorSystem : public ImpureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EditorSystem(EventBroker* eventBroker, IRenderer* renderer);
|
EditorSystem(EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame);
|
||||||
|
~EditorSystem();
|
||||||
|
|
||||||
virtual void Update(World* world, double dt) override;
|
void Update(World* world, double dt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IRenderer* m_Renderer;
|
IRenderer* m_Renderer;
|
||||||
World* m_World = nullptr;
|
RenderFrame* m_RenderFrame;
|
||||||
Camera* m_Camera = nullptr;
|
World* m_EditorWorld;
|
||||||
|
SystemPipeline* m_EditorWorldSystemPipeline;
|
||||||
|
Camera* m_EditorCamera;
|
||||||
|
|
||||||
bool m_Enabled;
|
EntityWrapper m_Widget = EntityWrapper::Invalid;
|
||||||
bool m_Visible;
|
EntityWrapper m_Camera = EntityWrapper::Invalid;
|
||||||
boost::filesystem::path m_DefaultEntityDir;
|
DebugCameraInputController<EditorSystem>* m_DebugCameraInputController;
|
||||||
boost::filesystem::path m_CurrentFile;
|
|
||||||
std::vector<glm::vec2> m_PickingQueue;
|
|
||||||
|
|
||||||
enum class WidgetMode
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Translate,
|
|
||||||
Rotate,
|
|
||||||
Scale
|
|
||||||
} m_WidgetMode = WidgetMode::None;
|
|
||||||
|
|
||||||
enum class WidgetSpace
|
|
||||||
{
|
|
||||||
Local,
|
|
||||||
Global
|
|
||||||
} m_WidgetSpace = WidgetSpace::Global;
|
|
||||||
|
|
||||||
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<EditorSystem, Events::InputCommand> m_EInputCommand;
|
|
||||||
bool OnInputCommand(const Events::InputCommand& e);
|
|
||||||
EventRelay<EditorSystem, Events::MouseRelease> m_EMouseRelease;
|
|
||||||
bool OnMouseRelease(const Events::MouseRelease& e);
|
|
||||||
EventRelay<EditorSystem, Events::MousePress> m_EMousePress;
|
|
||||||
bool OnMousePress(const Events::MousePress& e);
|
|
||||||
EventRelay<EditorSystem, Events::MouseMove> m_EMouseMove;
|
|
||||||
bool OnMouseMove(const Events::MouseMove& e);
|
|
||||||
EventRelay<EditorSystem, Events::FileDropped> 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);
|
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#include <imgui/imgui.h>
|
||||||
|
#include <glm/gtx/common.hpp>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <nativefiledialog/nfd.h>
|
||||||
|
#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 "../Core/EntityFilePreprocessor.h"
|
||||||
|
#include "../Core/EntityFileParser.h"
|
||||||
|
#include "../Core/EntityFileWriter.h"
|
||||||
|
|
||||||
|
class EditorSystemOld : public ImpureSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EditorSystemOld(EventBroker* eventBroker, IRenderer* renderer);
|
||||||
|
|
||||||
|
virtual void Update(World* world, double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IRenderer* m_Renderer;
|
||||||
|
World* m_World = nullptr;
|
||||||
|
Camera* m_Camera = nullptr;
|
||||||
|
|
||||||
|
bool m_Enabled;
|
||||||
|
bool m_Visible;
|
||||||
|
boost::filesystem::path m_DefaultEntityDir;
|
||||||
|
boost::filesystem::path m_CurrentFile;
|
||||||
|
std::vector<glm::vec2> m_PickingQueue;
|
||||||
|
|
||||||
|
enum class WidgetMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Translate,
|
||||||
|
Rotate,
|
||||||
|
Scale
|
||||||
|
} m_WidgetMode = WidgetMode::None;
|
||||||
|
|
||||||
|
enum class WidgetSpace
|
||||||
|
{
|
||||||
|
Local,
|
||||||
|
Global
|
||||||
|
} m_WidgetSpace = WidgetSpace::Global;
|
||||||
|
|
||||||
|
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<EditorSystemOld, Events::InputCommand> m_EInputCommand;
|
||||||
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
|
EventRelay<EditorSystemOld, Events::MouseRelease> m_EMouseRelease;
|
||||||
|
bool OnMouseRelease(const Events::MouseRelease& e);
|
||||||
|
EventRelay<EditorSystemOld, Events::MousePress> m_EMousePress;
|
||||||
|
bool OnMousePress(const Events::MousePress& e);
|
||||||
|
EventRelay<EditorSystemOld, Events::MouseMove> m_EMouseMove;
|
||||||
|
bool OnMouseMove(const Events::MouseMove& e);
|
||||||
|
EventRelay<EditorSystemOld, Events::FileDropped> 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);
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#include <imgui/imgui.h>
|
||||||
|
#include <nativefiledialog/nfd.h>
|
||||||
|
|
||||||
|
class EditorUI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EditorUI();
|
||||||
|
};
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#ifndef DebugCameraInputController_h__
|
||||||
|
#define DebugCameraInputController_h__
|
||||||
|
|
||||||
#include <imgui/imgui.h>
|
#include <imgui/imgui.h>
|
||||||
#include "../Input/FirstPersonInputController.h"
|
#include "../Input/FirstPersonInputController.h"
|
||||||
|
|
||||||
@@ -64,3 +67,5 @@ protected:
|
|||||||
float m_BaseSpeed = 2.0f;
|
float m_BaseSpeed = 2.0f;
|
||||||
float m_Speed = m_BaseSpeed;
|
float m_Speed = m_BaseSpeed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -32,7 +32,6 @@ private:
|
|||||||
const LightCullingPass* m_LightCullingPass;
|
const LightCullingPass* m_LightCullingPass;
|
||||||
|
|
||||||
ShaderProgram* m_ForwardPlusProgram;
|
ShaderProgram* m_ForwardPlusProgram;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,20 +2,14 @@
|
|||||||
#define Events_SetCamera_h__
|
#define Events_SetCamera_h__
|
||||||
|
|
||||||
#include "../Core/EventBroker.h"
|
#include "../Core/EventBroker.h"
|
||||||
#include "../Core/Entity.h"
|
#include "../Core/EntityWrapper.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace Events
|
namespace Events
|
||||||
{
|
{
|
||||||
|
|
||||||
struct SetCamera : Event
|
struct SetCamera : Event
|
||||||
{
|
{
|
||||||
public:
|
EntityWrapper CameraEntity;
|
||||||
SetCamera() { };
|
|
||||||
std::string Name;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,15 +31,6 @@ public:
|
|||||||
void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
|
void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
|
||||||
bool VSYNC() const { return m_VSYNC; }
|
bool VSYNC() const { return m_VSYNC; }
|
||||||
void SetVSYNC(bool vsync) { m_VSYNC = 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 Initialize() = 0;
|
||||||
virtual void Update(double dt) = 0;
|
virtual void Update(double dt) = 0;
|
||||||
virtual void Draw(RenderFrame& rq) = 0;
|
virtual void Draw(RenderFrame& rq) = 0;
|
||||||
@@ -54,8 +45,6 @@ protected:
|
|||||||
int m_GLVersion[2];
|
int m_GLVersion[2];
|
||||||
std::string m_GLVendor;
|
std::string m_GLVendor;
|
||||||
GLFWwindow* m_Window = nullptr;
|
GLFWwindow* m_Window = nullptr;
|
||||||
::Camera* m_DefaultCamera;
|
|
||||||
::Camera* m_Camera = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Renderer_h__
|
#endif // Renderer_h__
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ struct RenderJob
|
|||||||
friend class RenderQueue;
|
friend class RenderQueue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
float Depth;
|
float Depth;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -50,10 +50,11 @@ struct PointLightJob : RenderJob
|
|||||||
|
|
||||||
struct RenderScene
|
struct RenderScene
|
||||||
{
|
{
|
||||||
::Camera* Camera;
|
::Camera* Camera = nullptr;
|
||||||
std::list<std::shared_ptr<RenderJob>> ForwardJobs;
|
std::list<std::shared_ptr<RenderJob>> ForwardJobs;
|
||||||
std::list<std::shared_ptr<RenderJob>> PointLightJobs;
|
std::list<std::shared_ptr<RenderJob>> PointLightJobs;
|
||||||
Rectangle Viewport;
|
Rectangle Viewport;
|
||||||
|
bool ClearDepth = false;
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ public:
|
|||||||
bool Disable(GLenum cap);
|
bool Disable(GLenum cap);
|
||||||
bool CullFace(GLenum mode);
|
bool CullFace(GLenum mode);
|
||||||
bool ClearColor(glm::vec4 color);
|
bool ClearColor(glm::vec4 color);
|
||||||
bool Clear(GLbitfield mask);
|
|
||||||
bool BindFramebuffer(GLint framebuffer);
|
bool BindFramebuffer(GLint framebuffer);
|
||||||
bool BlendEquation(GLenum mode);
|
bool BlendEquation(GLenum mode);
|
||||||
bool BlendFunc(GLenum sfactor, GLenum dfactor);
|
bool BlendFunc(GLenum sfactor, GLenum dfactor);
|
||||||
|
bool DepthMask(GLboolean flag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::function<void(void)>> m_ResetFunctions;
|
std::vector<std::function<void(void)>> m_ResetFunctions;
|
||||||
|
|||||||
@@ -28,28 +28,17 @@ public:
|
|||||||
private:
|
private:
|
||||||
World* m_World = nullptr;
|
World* m_World = nullptr;
|
||||||
const IRenderer* m_Renderer;
|
const IRenderer* m_Renderer;
|
||||||
|
|
||||||
RenderFrame* m_RenderFrame;
|
RenderFrame* m_RenderFrame;
|
||||||
bool m_SwitchCamera = false;
|
|
||||||
Camera* m_Camera;
|
Camera* m_Camera;
|
||||||
DebugCameraInputController<RenderSystem>* m_DebugCameraInputController;
|
EntityWrapper m_CurrentCamera = EntityWrapper::Invalid;
|
||||||
|
|
||||||
std::list<ComponentWrapper> m_CameraComponents;
|
|
||||||
|
|
||||||
EventRelay<RenderSystem, Events::SetCamera> m_ESetCamera;
|
EventRelay<RenderSystem, Events::SetCamera> m_ESetCamera;
|
||||||
bool OnSetCamera(const Events::SetCamera &event);
|
bool OnSetCamera(Events::SetCamera &event);
|
||||||
EntityID m_CurrentCamera = EntityID_Invalid;
|
EventRelay<RenderSystem, Events::InputCommand> m_EInputCommand;
|
||||||
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
void switchCamera(EntityID entity);
|
|
||||||
|
|
||||||
void updateCamera(World* world, double dt);
|
|
||||||
void updateProjectionMatrix(ComponentWrapper& cameraComponent);
|
|
||||||
|
|
||||||
void fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
|
void fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
|
||||||
void fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
|
void fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
|
||||||
|
|
||||||
EventRelay<RenderSystem, Events::InputCommand> m_EInputCommand;
|
|
||||||
bool OnInputCommand(const Events::InputCommand& e);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
<Camera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Camera.xsd">
|
<Camera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Camera.xsd">
|
||||||
<Name>cam</Name>
|
|
||||||
<FOV>45</FOV>
|
<FOV>45</FOV>
|
||||||
<NearClip>0.01</NearClip>
|
<NearClip>0.01</NearClip>
|
||||||
<FarClip>5000</FarClip>
|
<FarClip>5000</FarClip>
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element name="Name" type="t:string" minOccurs="0"/>
|
|
||||||
<xs:element name="FOV" type="t:double" minOccurs="0">
|
<xs:element name="FOV" type="t:double" minOccurs="0">
|
||||||
<xs:annotation><xs:documentation>Vertical Field of View in degrees</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>Vertical Field of View in degrees</xs:documentation></xs:annotation>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<xs:element name="Color" type="t:Color" minOccurs="0"/>
|
<xs:element name="Color" type="t:Color" minOccurs="0"/>
|
||||||
<xs:element name="Radius" type="t:double" minOccurs="0"/>
|
<xs:element name="Radius" type="t:double" minOccurs="0"/>
|
||||||
<xs:element name="Intensity" type="t:double" minOccurs="0"/>
|
<xs:element name="Intensity" type="t:double" minOccurs="0"/>
|
||||||
<xs:element name="Falloff">
|
<xs:element name="Falloff" minOccurs="0">
|
||||||
<xs:simpleType>
|
<xs:simpleType>
|
||||||
<xs:restriction base="t:double">
|
<xs:restriction base="t:double">
|
||||||
<xs:minInclusive value="0"/>
|
<xs:minInclusive value="0"/>
|
||||||
|
|||||||
Executable
+79
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" name="TranslationWidget">
|
||||||
|
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:UniformScale>
|
||||||
|
<Scale X="0.2" Y="0.2" Z="0.2"/>
|
||||||
|
</c:UniformScale>
|
||||||
|
|
||||||
|
</Components>
|
||||||
|
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0.2" Y="0.2" Z="0.2"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:PointLight/>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/TranslationWidgetOrigin.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/TranslationWidgetX.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/TranslationWidgetY.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/TranslationWidgetZ.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/WidgetPlaneX.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/WidgetPlaneY.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/WidgetPlaneZ.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
|
||||||
|
</Entity>
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
<Resource>Models/DummyScene.obj</Resource>
|
<Resource>Models/DummyScene.obj</Resource>
|
||||||
</c:Model>
|
</c:Model>
|
||||||
</Components>
|
</Components>
|
||||||
</Entity>
|
|
||||||
<Children>
|
<Children>
|
||||||
<Entity>
|
<Entity>
|
||||||
<Components>
|
<Components>
|
||||||
@@ -25,3 +24,4 @@
|
|||||||
</Components>
|
</Components>
|
||||||
</Entity>
|
</Entity>
|
||||||
</Children>
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#include "Editor/EditorRenderSystem.h"
|
||||||
|
|
||||||
|
EditorRenderSystem::EditorRenderSystem(EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame)
|
||||||
|
: System(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(World* world, 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 = 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(world, cModel.EntityID);
|
||||||
|
glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, entity.World);
|
||||||
|
for (auto matGroup : model->MaterialGroups()) {
|
||||||
|
std::shared_ptr<ModelJob> modelJob = std::make_shared<ModelJob>(model, nullptr, modelMatrix, matGroup, cModel, entity.World);
|
||||||
|
scene.ForwardJobs.push_back(modelJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pointLights = world->GetComponents("PointLight");
|
||||||
|
if (pointLights != nullptr) {
|
||||||
|
for (auto& cPointLight : *pointLights) {
|
||||||
|
bool visible = cPointLight["Visible"];
|
||||||
|
if (!visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityWrapper entity(world, cPointLight.EntityID);
|
||||||
|
ComponentWrapper& cTransform = entity["Transform"];
|
||||||
|
std::shared_ptr<PointLightJob> pointLightJob = std::make_shared<PointLightJob>(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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,738 +1,46 @@
|
|||||||
#include "Editor/EditorSystem.h"
|
#include "Editor/EditorSystem.h"
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
#include "Core/UniformScaleSystem.h"
|
||||||
#include <imgui/imgui_internal.h>
|
#include "Editor/EditorRenderSystem.h"
|
||||||
|
|
||||||
EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
|
EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame)
|
||||||
: System(eventBroker)
|
: System(eventBroker)
|
||||||
, ImpureSystem()
|
|
||||||
, m_Renderer(renderer)
|
, m_Renderer(renderer)
|
||||||
|
, m_RenderFrame(renderFrame)
|
||||||
{
|
{
|
||||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
m_EditorWorld = new World();
|
||||||
m_Enabled = config->Get<bool>("Debug.EditorEnabled", false);
|
m_EditorWorldSystemPipeline = new SystemPipeline(eventBroker);
|
||||||
m_Visible = m_Enabled;
|
m_EditorWorldSystemPipeline->AddSystem<UniformScaleSystem>(0);
|
||||||
m_DefaultEntityDir = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
|
m_EditorWorldSystemPipeline->AddSystem<EditorRenderSystem>(1, m_Renderer, m_RenderFrame);
|
||||||
|
|
||||||
if (!m_Enabled) {
|
auto widgetEntityFile = ResourceManager::Load<EntityFile>("Schema/Entities/EditorWidget.xml");
|
||||||
return;
|
EntityFilePreprocessor fpp(widgetEntityFile);
|
||||||
}
|
fpp.RegisterComponents(m_EditorWorld);
|
||||||
|
EntityFileParser fp(widgetEntityFile);
|
||||||
|
EntityID widgetID = fp.MergeEntities(m_EditorWorld);
|
||||||
|
m_Widget = EntityWrapper(m_EditorWorld, widgetID);
|
||||||
|
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &EditorSystem::OnInputCommand);
|
m_Camera = EntityWrapper(m_EditorWorld, m_EditorWorld->CreateEntity());
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress);
|
m_EditorWorld->AttachComponent(m_Camera.ID, "Transform");
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorSystem::OnMouseRelease);
|
m_EditorWorld->AttachComponent(m_Camera.ID, "Camera");
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorSystem::OnMouseMove);
|
m_DebugCameraInputController = new DebugCameraInputController<EditorSystem>(m_EventBroker, -1);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EFileDropped, &EditorSystem::OnFileDropped);
|
|
||||||
|
Events::SetCamera e;
|
||||||
|
e.CameraEntity = m_Camera;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorSystem::~EditorSystem()
|
||||||
|
{
|
||||||
|
delete m_DebugCameraInputController;
|
||||||
|
delete m_EditorWorldSystemPipeline;
|
||||||
|
delete m_EditorWorld;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorSystem::Update(World* world, double dt)
|
void EditorSystem::Update(World* world, double dt)
|
||||||
{
|
{
|
||||||
m_World = world;
|
m_EditorWorldSystemPipeline->Update(m_EditorWorld, dt);
|
||||||
|
|
||||||
if (!m_Enabled) {
|
m_DebugCameraInputController->Update(dt);
|
||||||
return;
|
m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position();
|
||||||
}
|
m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
|
||||||
|
|
||||||
if (!m_Visible) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Picking();
|
|
||||||
updateWidget();
|
|
||||||
|
|
||||||
drawUI(world, dt);
|
|
||||||
|
|
||||||
// Clear drop queue if it wasn't handled by any UI element
|
|
||||||
if (!m_LastDroppedFile.empty()) {
|
|
||||||
m_LastDroppedFile = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
boost::filesystem::path EditorSystem::openDialog(boost::filesystem::path defaultPath)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return bfs::absolute(outPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::filesystem::path EditorSystem::saveDialog(boost::filesystem::path defaultPath)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return bfs::absolute(outPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EditorSystem::OnInputCommand(const Events::InputCommand& e)
|
|
||||||
{
|
|
||||||
if (e.Command == "ToggleEditor" && e.Value > 0) {
|
|
||||||
m_Visible = !m_Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (e.Button == GLFW_MOUSE_BUTTON_RIGHT) {
|
|
||||||
m_PickingQueue.push_back(glm::vec2((int)e.X, (int)e.Y));
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorSystem::Picking()
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorSystem::updateWidget()
|
|
||||||
{
|
|
||||||
if (m_Widget == EntityID_Invalid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_Selection == m_Widget) {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorSystem::setWidgetMode(WidgetMode newMode)
|
|
||||||
{
|
|
||||||
if (m_Widget == EntityID_Invalid) {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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<const char*> 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<glm::vec3>(fieldName);
|
|
||||||
if (fieldName == "Scale") {
|
|
||||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
|
||||||
} else if (fieldName == "Orientation") {
|
|
||||||
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
|
|
||||||
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
|
|
||||||
val = tempVal;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
|
||||||
}
|
|
||||||
} else if (field.Type == "Color") {
|
|
||||||
auto& val = component.Field<glm::vec4>(fieldName);
|
|
||||||
ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
|
||||||
} else if (field.Type == "string") {
|
|
||||||
std::string& val = component.Field<std::string>(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<float>(component.Field<double>(fieldName));
|
|
||||||
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
|
||||||
component.SetField(fieldName, static_cast<double>(tempVal));
|
|
||||||
}
|
|
||||||
} else if (field.Type == "int") {
|
|
||||||
int val = component.Field<int>(fieldName);
|
|
||||||
ImGui::InputInt("", &val);
|
|
||||||
} else if (field.Type == "enum") {
|
|
||||||
int currentValue = component.Field<int>(fieldName);
|
|
||||||
int item = -1;
|
|
||||||
std::stringstream enumKeys;
|
|
||||||
std::vector<int> 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<bool>(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<void(EntityID)> 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<EntityFile>(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();
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,738 @@
|
|||||||
|
#include "Editor/EditorSystemOld.h"
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#include <imgui/imgui_internal.h>
|
||||||
|
|
||||||
|
EditorSystemOld::EditorSystemOld(EventBroker* eventBroker, IRenderer* renderer)
|
||||||
|
: System(eventBroker)
|
||||||
|
, ImpureSystem()
|
||||||
|
, m_Renderer(renderer)
|
||||||
|
{
|
||||||
|
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
|
m_Enabled = config->Get<bool>("Debug.EditorEnabled", false);
|
||||||
|
m_Visible = m_Enabled;
|
||||||
|
m_DefaultEntityDir = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
|
||||||
|
|
||||||
|
if (!m_Enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &EditorSystemOld::OnInputCommand);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystemOld::OnMousePress);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorSystemOld::OnMouseRelease);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorSystemOld::OnMouseMove);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EFileDropped, &EditorSystemOld::OnFileDropped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::Update(World* world, double dt)
|
||||||
|
{
|
||||||
|
m_World = world;
|
||||||
|
|
||||||
|
if (!m_Enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_Visible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Picking();
|
||||||
|
updateWidget();
|
||||||
|
|
||||||
|
drawUI(world, dt);
|
||||||
|
|
||||||
|
// Clear drop queue if it wasn't handled by any UI element
|
||||||
|
if (!m_LastDroppedFile.empty()) {
|
||||||
|
m_LastDroppedFile = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boost::filesystem::path EditorSystemOld::openDialog(boost::filesystem::path defaultPath)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bfs::absolute(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path EditorSystemOld::saveDialog(boost::filesystem::path defaultPath)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bfs::absolute(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorSystemOld::OnInputCommand(const Events::InputCommand& e)
|
||||||
|
{
|
||||||
|
if (e.Command == "ToggleEditor" && e.Value > 0) {
|
||||||
|
m_Visible = !m_Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 EditorSystemOld::OnMousePress(const Events::MousePress& e)
|
||||||
|
{
|
||||||
|
if (e.Button == GLFW_MOUSE_BUTTON_RIGHT) {
|
||||||
|
m_PickingQueue.push_back(glm::vec2((int)e.X, (int)e.Y));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorSystemOld::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 EditorSystemOld::OnMouseRelease(const Events::MouseRelease& e)
|
||||||
|
{
|
||||||
|
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
|
||||||
|
m_WidgetCurrentAxis = glm::vec3(0.f);
|
||||||
|
//setWidgetMode(m_WidgetMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::Picking()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_PickingQueue.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool EditorSystemOld::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 EditorSystemOld::createWidget()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::updateWidget()
|
||||||
|
{
|
||||||
|
if (m_Widget == EntityID_Invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_Selection == m_Widget) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::setWidgetMode(WidgetMode newMode)
|
||||||
|
{
|
||||||
|
if (m_Widget == EntityID_Invalid) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_WidgetMode = newMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::setWidgetSpace(WidgetSpace space)
|
||||||
|
{
|
||||||
|
m_WidgetSpace = space;
|
||||||
|
setWidgetMode(m_WidgetMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::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<const char*> 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<glm::vec3>(fieldName);
|
||||||
|
if (fieldName == "Scale") {
|
||||||
|
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
||||||
|
} else if (fieldName == "Orientation") {
|
||||||
|
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
|
||||||
|
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
|
||||||
|
val = tempVal;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
||||||
|
}
|
||||||
|
} else if (field.Type == "Color") {
|
||||||
|
auto& val = component.Field<glm::vec4>(fieldName);
|
||||||
|
ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
||||||
|
} else if (field.Type == "string") {
|
||||||
|
std::string& val = component.Field<std::string>(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<float>(component.Field<double>(fieldName));
|
||||||
|
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
||||||
|
component.SetField(fieldName, static_cast<double>(tempVal));
|
||||||
|
}
|
||||||
|
} else if (field.Type == "int") {
|
||||||
|
int val = component.Field<int>(fieldName);
|
||||||
|
ImGui::InputInt("", &val);
|
||||||
|
} else if (field.Type == "enum") {
|
||||||
|
int currentValue = component.Field<int>(fieldName);
|
||||||
|
int item = -1;
|
||||||
|
std::stringstream enumKeys;
|
||||||
|
std::vector<int> 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<bool>(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<void(EntityID)> 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 EditorSystemOld::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 EditorSystemOld::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 EditorSystemOld::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 EditorSystemOld::fileImport(World* world)
|
||||||
|
{
|
||||||
|
m_CurrentFile = openDialog(m_DefaultEntityDir);
|
||||||
|
auto file = ResourceManager::Load<EntityFile>(m_CurrentFile.string());
|
||||||
|
EntityFilePreprocessor fpp(file);
|
||||||
|
fpp.RegisterComponents(world);
|
||||||
|
EntityFileParser fp(file);
|
||||||
|
fp.MergeEntities(world);
|
||||||
|
createWidget();
|
||||||
|
updateWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystemOld::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 EditorSystemOld::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();
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ void DrawFinalPass::Draw(RenderScene& scene)
|
|||||||
GLERROR("DrawFinalPass::Draw: Pre");
|
GLERROR("DrawFinalPass::Draw: Pre");
|
||||||
|
|
||||||
DrawFinalPassState state;
|
DrawFinalPassState state;
|
||||||
|
|
||||||
m_ForwardPlusProgram->Bind();
|
m_ForwardPlusProgram->Bind();
|
||||||
GLuint shaderHandle = m_ForwardPlusProgram->GetHandle();
|
GLuint shaderHandle = m_ForwardPlusProgram->GetHandle();
|
||||||
|
|
||||||
@@ -34,8 +35,8 @@ void DrawFinalPass::Draw(RenderScene& scene)
|
|||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO());
|
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO());
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO());
|
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, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ProjectionMatrix()));
|
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);
|
glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
|
||||||
|
|
||||||
//TODO: Render: Add code for more jobs than modeljobs.
|
//TODO: Render: Add code for more jobs than modeljobs.
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ DrawFinalPassState::DrawFinalPassState()
|
|||||||
Enable(GL_DEPTH_TEST);
|
Enable(GL_DEPTH_TEST);
|
||||||
Enable(GL_CULL_FACE);
|
Enable(GL_CULL_FACE);
|
||||||
ClearColor(glm::vec4(200.f / 255, 0.f / 255, 200.f / 255, 0.f));
|
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()
|
DrawFinalPassState::~DrawFinalPassState()
|
||||||
|
|||||||
@@ -44,12 +44,6 @@ bool RenderState::ClearColor(glm::vec4 color)
|
|||||||
return !GLERROR("RenderState::ClearColor");
|
return !GLERROR("RenderState::ClearColor");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderState::Clear(GLbitfield mask)
|
|
||||||
{
|
|
||||||
glClear(mask);
|
|
||||||
return !GLERROR("RenderState::Clear");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderState::BindFramebuffer(GLint framebuffer)
|
bool RenderState::BindFramebuffer(GLint framebuffer)
|
||||||
{
|
{
|
||||||
GLint originalRead;
|
GLint originalRead;
|
||||||
@@ -91,6 +85,15 @@ bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor)
|
|||||||
return !GLERROR("RenderState::BlendFunc");
|
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()
|
RenderState::~RenderState()
|
||||||
{
|
{
|
||||||
for (auto& f : m_ResetFunctions) {
|
for (auto& f : m_ResetFunctions) {
|
||||||
|
|||||||
@@ -9,71 +9,26 @@ RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer,
|
|||||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand);
|
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_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f);
|
||||||
m_DebugCameraInputController = new DebugCameraInputController<RenderSystem>(eventBroker, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderSystem::~RenderSystem()
|
RenderSystem::~RenderSystem()
|
||||||
{
|
{
|
||||||
delete m_Camera;
|
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");
|
ComponentWrapper cTransform = e.CameraEntity["Transform"];
|
||||||
|
ComponentWrapper cCamera = e.CameraEntity["Camera"];
|
||||||
if (cameras != nullptr) {
|
m_Camera->SetFOV((double)cCamera["FOV"]);
|
||||||
for (auto it = cameras->begin(); it != cameras->end(); it++) {
|
m_Camera->SetNearClip((double)cCamera["NearClip"]);
|
||||||
if ((std::string)(*it)["Name"] == event.Name) {
|
m_Camera->SetFarClip((double)cCamera["FarClip"]);
|
||||||
switchCamera((*it).EntityID);
|
m_Camera->SetPosition(cTransform["Position"]);
|
||||||
}
|
m_Camera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"]));
|
||||||
}
|
m_CurrentCamera = e.CameraEntity;
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSystem::switchCamera(EntityID entity)
|
|
||||||
{
|
|
||||||
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<std::shared_ptr<RenderJob>>& jobs, World* world)
|
void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
||||||
{
|
{
|
||||||
auto models = world->GetComponents("Model");
|
auto models = world->GetComponents("Model");
|
||||||
@@ -113,7 +68,6 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderSystem::fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
void RenderSystem::fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
||||||
{
|
{
|
||||||
auto pointLights = world->GetComponents("PointLight");
|
auto pointLights = world->GetComponents("PointLight");
|
||||||
@@ -138,12 +92,7 @@ void RenderSystem::fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World*
|
|||||||
|
|
||||||
bool RenderSystem::OnInputCommand(const Events::InputCommand& e)
|
bool RenderSystem::OnInputCommand(const Events::InputCommand& e)
|
||||||
{
|
{
|
||||||
if (e.Command == "SwitchCamera" && e.Value > 0) {
|
return false;
|
||||||
m_SwitchCamera = true;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderSystem::Update(World* world, double dt)
|
void RenderSystem::Update(World* world, double dt)
|
||||||
@@ -151,10 +100,12 @@ void RenderSystem::Update(World* world, double dt)
|
|||||||
m_World = world;
|
m_World = world;
|
||||||
m_EventBroker->Process<RenderSystem>();
|
m_EventBroker->Process<RenderSystem>();
|
||||||
|
|
||||||
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
|
//Only supports opaque geometry atm
|
||||||
m_RenderFrame->Clear();
|
|
||||||
|
|
||||||
RenderScene scene;
|
RenderScene scene;
|
||||||
scene.Camera = m_Camera;
|
scene.Camera = m_Camera;
|
||||||
@@ -164,69 +115,3 @@ void RenderSystem::Update(World* world, double dt)
|
|||||||
m_RenderFrame->Add(scene);
|
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();
|
|
||||||
}
|
|
||||||
@@ -15,15 +15,6 @@ void Renderer::Initialize()
|
|||||||
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");
|
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");
|
||||||
|
|
||||||
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
|
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()
|
void Renderer::InitializeWindow()
|
||||||
@@ -92,14 +83,14 @@ void Renderer::Update(double dt)
|
|||||||
void Renderer::Draw(RenderFrame& frame)
|
void Renderer::Draw(RenderFrame& frame)
|
||||||
{
|
{
|
||||||
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
|
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
||||||
m_PickingPass->ClearPicking();
|
m_PickingPass->ClearPicking();
|
||||||
for (auto scene : frame.RenderScenes){
|
for (auto scene : frame.RenderScenes){
|
||||||
|
if (scene->ClearDepth) {
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
m_Camera = scene->Camera; // remove renderer camera when Editor uses the render scene cameras.
|
|
||||||
FillDepth(*scene);
|
FillDepth(*scene);
|
||||||
m_PickingPass->Draw(*scene);
|
m_PickingPass->Draw(*scene);
|
||||||
m_LightCullingPass->GenerateNewFrustum(*scene);
|
m_LightCullingPass->GenerateNewFrustum(*scene);
|
||||||
|
|||||||
+3
-1
@@ -77,7 +77,6 @@ Game::Game(int argc, char* argv[])
|
|||||||
unsigned int updateOrderLevel = 0;
|
unsigned int updateOrderLevel = 0;
|
||||||
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
|
|
||||||
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
|
||||||
@@ -91,6 +90,8 @@ Game::Game(int argc, char* argv[])
|
|||||||
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel, m_OctreeCollision);
|
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel, m_OctreeCollision);
|
||||||
++updateOrderLevel;
|
++updateOrderLevel;
|
||||||
m_SystemPipeline->AddSystem<RenderSystem>(updateOrderLevel, m_Renderer, m_RenderFrame);
|
m_SystemPipeline->AddSystem<RenderSystem>(updateOrderLevel, m_Renderer, m_RenderFrame);
|
||||||
|
++updateOrderLevel;
|
||||||
|
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer, m_RenderFrame);
|
||||||
|
|
||||||
// Invoke network
|
// Invoke network
|
||||||
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
|
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
|
||||||
@@ -149,6 +150,7 @@ void Game::Tick()
|
|||||||
m_SoundSystem->Update(dt);
|
m_SoundSystem->Update(dt);
|
||||||
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
||||||
m_Renderer->Draw(*m_RenderFrame);
|
m_Renderer->Draw(*m_RenderFrame);
|
||||||
|
m_RenderFrame->Clear();
|
||||||
GLERROR("Game::Tick m_Renderer->Draw");
|
GLERROR("Game::Tick m_Renderer->Draw");
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
m_EventBroker->Clear();
|
m_EventBroker->Clear();
|
||||||
|
|||||||
Reference in New Issue
Block a user