Refactor scene, environment, entity, and child entity saving for clear and faster execution

This commit is contained in:
Arnau Alier Torres 2025-04-21 12:36:29 +02:00
parent d1a99961b1
commit fddb88a9b2
37 changed files with 2071 additions and 1857 deletions

View File

@ -4,12 +4,16 @@
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <stdint.h> #include <stdint.h>
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#include "Deer/Log.h"
#include "glm/glm.hpp" #include "glm/glm.hpp"
#include "glm/gtc/quaternion.hpp" #include "glm/gtc/quaternion.hpp"
#define ENTITY_MAX_CHILDREN 64
namespace Deer { namespace Deer {
class ComponentScriptInstance; class ComponentScriptInstance;
@ -33,12 +37,44 @@ namespace Deer {
}; };
struct RelationshipComponent { struct RelationshipComponent {
uint32_t parent_UID = 0; uint16_t parent_id = 0;
std::vector<uint32_t> children; uint16_t childCount = 0;
// Note: Since the root(id : 0) can't be a children, we will use 0 as
// null or empty
std::array<uint16_t, ENTITY_MAX_CHILDREN> childrens{};
inline uint16_t getChildrenId(size_t i) {
DEER_CORE_ASSERT(i >= 0 && i < childCount && childrens[i] != 0,
"Invalid child request {0}", i);
return childrens[i];
}
inline bool addChildrenId(uint16_t childId) {
if (childCount >= ENTITY_MAX_CHILDREN) return false;
childrens[childCount] = childId;
childCount++;
return true;
}
inline void removeChildren(uint16_t childId) {
uint16_t childPosition = 0;
for (int i = 0; i < childCount; i++) {
if (childrens[i] == childId) {
childPosition = i;
break;
}
}
// Move all childs one position
for (int i = childPosition + 1; i < childCount; i++) {
childrens[i - 1] = childrens[i];
}
childrens[childCount - 1] = 0;
childCount--;
}
RelationshipComponent() = default; RelationshipComponent() = default;
RelationshipComponent(const RelationshipComponent&) = default; RelationshipComponent(const RelationshipComponent&) = default;
RelationshipComponent(uint32_t parent) : parent_UID(parent) {} RelationshipComponent(uint16_t _parent) : parent_id(_parent) {}
}; };
struct TransformComponent { struct TransformComponent {

View File

@ -1,11 +1,13 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <array>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "Deer/Components.h" #include "Deer/Components.h"
#include "Deer/Log.h" #include "Deer/Log.h"
#include "Deer/Memory.h"
#include "entt/entt.hpp" #include "entt/entt.hpp"
#ifdef DEER_RENDER #ifdef DEER_RENDER
@ -13,54 +15,88 @@
#include "DeerRender/SceneCamera.h" #include "DeerRender/SceneCamera.h"
#endif #endif
#define ENVIRONMENT_MAX_ENTITIES 2048
namespace Deer { namespace Deer {
class Entity; class Entity;
using EntityMap = std::unordered_map<uint32_t, Entity>;
class Environment { class Environment {
///////// NOTES ///////////
// - The entity id means the position in a array defined in Environment
// - The entity id is relative to a Environment so it can be a complete
// diferent entity in other environments
// - The entity number 0 is allways the root
// - There is a limit defined by ENVIRONMENT_MAX_ENTITIES of how many
// entities can be in an Environment
///////// NOTES ///////////
public: public:
Environment(); Environment();
~Environment(); ~Environment();
// This class can not be copyed
Environment(const Environment&) = delete;
Environment& operator=(Environment&) = delete;
// Clears all entities
void clear(); void clear();
#ifdef DEER_RENDER // Obtains the entity
void render(SceneCamera& camera); Entity& getEntity(uint16_t id) const;
#endif bool entityExists(uint16_t id) const;
uint16_t getEntityCount() const { return m_entityCount; }
Entity& getEntity(uint32_t id); // Creates a entity child at root
Entity& createEntity(const std::string& name = std::string()); Entity& createEntity(const std::string& name = "");
Entity& createEntityWithId(uint16_t id, const std::string& name = "");
void destroyEntity(uint16_t id);
// Special behaviour
Entity createEmptyEntity(); Entity createEmptyEntity();
// FEO // FEO
uint32_t tryGetMainCamera(); uint16_t tryGetMainCamera();
void setMainCamera(Entity& entity); void setMainCamera(Entity& entity);
Entity& getRoot(); // Obtains the entity that is on the root of the environment
inline Entity& getRoot() { return getEntity(0); }
public: #ifdef DEER_RENDER
void render(SceneCamera& camera);
#endif
entt::registry m_registry; entt::registry m_registry;
EntityMap m_entities;
uint32_t m_rootEntity = 0;
uint32_t m_mainCamera = 0;
private: private:
uint32_t m_idCreationOffset = 0; uint16_t m_mainCamera = 0;
inline uint32_t pullEntityID() { // To avoid inecessary loop we set this variable that means that smaller
// id's than this numbers are not null, empty or used
uint16_t m_idCreationOffset = 0;
// Since we don't initialize Entity in the big array for performance we
// want to keep track the ones we initialized defined by this value, it
// the id is greater it means that any information that it has can't be
// seen as valid
uint16_t m_maxIdValue = 0;
// Number of entities that exists inside
uint16_t m_entityCount = 0;
// This is where we save the entities, in a const list defined by
// ENVIRONMENT_MAX_ENTITIES, we have to make sure this system is as fast
// as possible
Scope<std::array<Entity, ENVIRONMENT_MAX_ENTITIES>> entities;
inline uint16_t pullEntityID() {
m_idCreationOffset++; m_idCreationOffset++;
if (m_idCreationOffset > m_maxIdValue)
m_maxIdValue = m_idCreationOffset;
return m_idCreationOffset; return m_idCreationOffset;
} }
friend class Entity; friend class Entity;
}; };
// Warning: This calss does not initialize for performance
class Entity { class Entity {
public: public:
// This class can not be copied
Entity(const Entity&) = delete;
Entity() {} Entity() {}
static Entity nullEntity;
template <typename T, typename... Args> template <typename T, typename... Args>
T& addComponent(Args&&... args) const { T& addComponent(Args&&... args) const {
DEER_CORE_ASSERT( DEER_CORE_ASSERT(
@ -97,45 +133,33 @@ namespace Deer {
Entity& duplicate(); Entity& duplicate();
void destroy(); void destroy();
Entity& getParent(); uint16_t getId() const { return m_entityID; }
inline uint32_t getParentUID() { return m_parentUID; } Entity& getParent() const;
inline uint16_t getParentId() const { return m_parentID; }
// TODO, enable transfer entitys from difrent enviroments // TODO, enable transfer entitys from difrent enviroments
void setParent(Entity& parent); void setParent(Entity& parent);
bool isDescendant(Entity& parent); bool isDescendantOf(Entity& parent) const;
uint32_t getParentUID() const { return m_parentUID; }
uint32_t getUID() const { return m_entityUID; }
Environment* getEnvironment() const { return m_environment; } Environment* getEnvironment() const { return m_environment; }
std::vector<uint32_t>& getChildren();
bool isRoot() { return m_isRoot; } bool isRoot() const { return m_entityID == 0; }
glm::mat4 getWorldMatrix(); glm::mat4 getWorldMatrix();
glm::mat4 getRelativeMatrix(); glm::mat4 getRelativeMatrix();
void updateInternalVars(); void updateInternalVars();
inline bool isValid() const { inline bool isValid() const { return m_exists; }
return m_entityUID != 0 && m_environment != nullptr &&
m_environment->m_registry.valid(m_entityHandle);
}
inline bool operator==(const Entity& b) const {
return m_environment == b.m_environment &&
m_entityUID == b.m_entityUID;
}
private: private:
Entity(entt::entity handle, Environment* scene);
bool removeChild(Entity& child);
entt::entity m_entityHandle = entt::null;
Environment* m_environment = nullptr; Environment* m_environment = nullptr;
uint32_t m_entityUID = 0; entt::entity m_entityHandle = entt::null;
uint32_t m_parentUID = 0; uint16_t m_entityID = 0;
bool m_isRoot = false; uint16_t m_parentID = 0;
bool m_exists = false;
Entity(entt::entity handle, Environment* scene, uint16_t entityID);
friend class Environment; friend class Environment;
friend class std::unordered_map<uint32_t, Entity>;
}; };
} // namespace Deer } // namespace Deer

View File

@ -46,6 +46,7 @@ namespace Deer {
#define DEER_CORE_ASSERT(condition, ...) \ #define DEER_CORE_ASSERT(condition, ...) \
if (!(condition)) { \ if (!(condition)) { \
Deer::Log::getCoreLogger()->error(__VA_ARGS__); \ Deer::Log::getCoreLogger()->error(__VA_ARGS__); \
__builtin_trap(); \
} }
#define DEER_SCRIPT_ASSERT(condition, ...) \ #define DEER_SCRIPT_ASSERT(condition, ...) \
if (!(condition)) { \ if (!(condition)) { \

View File

@ -18,6 +18,9 @@ namespace Deer {
class Scene { class Scene {
public: public:
Scene(); Scene();
~Scene();
Scene(const Scene&) = delete;
Scene operator=(Scene&) = delete;
void createVoxelWorld(const VoxelWorldProps&); void createVoxelWorld(const VoxelWorldProps&);
void deleteVoxelWorld(); void deleteVoxelWorld();
@ -28,13 +31,16 @@ namespace Deer {
void endExecution(); void endExecution();
public: public:
inline Ref<Environment>& getMainEnviroment() { return m_enviroment; } inline Environment& getMainEnviroment() { return *m_enviroment; }
inline Ref<VoxelWorld>& getVoxelWorld() { return m_voxelWorld; } inline VoxelWorld& getVoxelWorld() { return *m_voxelWorld; }
inline bool isVoxelWorldInitialized() {
return m_voxelWorld != nullptr;
}
inline bool getExecutingState() { return m_isExecuting; } inline bool getExecutingState() { return m_isExecuting; }
private: private:
Ref<Environment> m_enviroment; Scope<Environment> m_enviroment;
Ref<VoxelWorld> m_voxelWorld; Scope<VoxelWorld> m_voxelWorld;
bool m_isExecuting = false; bool m_isExecuting = false;
#ifdef DEER_RENDER #ifdef DEER_RENDER
@ -49,13 +55,10 @@ namespace Deer {
}; };
namespace SceneDataStore { namespace SceneDataStore {
Scene loadScene(const Path& name); void loadScene(Scene& scene, const Path& name);
void exportScene(const Scene& scene, const Path& name);
void deleteSceneJson(const Path& name); void exportRuntimeScene(const Scene& scene);
void exportSceneJson(Scene& scene, const Path& name); void importRuntimeScene(Scene& scene);
void exportScenesBin();
void exportRuntimeScene(Scene& scene);
Scene importRuntimeScene();
} // namespace SceneDataStore } // namespace SceneDataStore
} // namespace Deer } // namespace Deer

View File

@ -148,6 +148,7 @@ namespace Deer {
// Warning: Do not change the voxel data content since that could make // Warning: Do not change the voxel data content since that could make
// undefined behaviour // undefined behaviour
VoxelWorld(const VoxelWorldProps &props); VoxelWorld(const VoxelWorldProps &props);
~VoxelWorld();
// This class can not be copyed // This class can not be copyed
// TODO: Make a function to duplicate a voxel World // TODO: Make a function to duplicate a voxel World
VoxelWorld(const VoxelWorld &) = delete; VoxelWorld(const VoxelWorld &) = delete;

View File

@ -1,108 +1,90 @@
#include "Deer/Enviroment.h"
#include "Deer/Components.h" #include "Deer/Components.h"
#include "Deer/Enviroment.h"
namespace Deer { namespace Deer {
Entity Entity::nullEntity = Entity(); Entity::Entity(entt::entity handle, Environment* scene, uint16_t entityID)
: m_entityHandle(handle),
Entity::Entity(entt::entity handle, Environment* scene) m_environment(scene),
: m_entityHandle(handle), m_environment(scene) { m_entityID(entityID),
} m_exists(true) {}
bool Entity::removeChild(Entity& child) {
DEER_CORE_ASSERT(child.m_environment == m_environment, "Can not remove childrens from diferent enviroments");
std::vector<uint32_t>& children = getChildren();
auto it = std::find(children.begin(), children.end(), child.m_entityUID);
if (it != children.end())
{
children.erase(it);
return true;
}
return false;
}
void Entity::setParent(Entity& parent) { void Entity::setParent(Entity& parent) {
DEER_CORE_ASSERT(parent.m_environment == m_environment , "Can not set parent from diferent enviroments"); DEER_CORE_ASSERT(isValid(), "Entity is not valid");
DEER_CORE_ASSERT(!isRoot(), "Can not set parent to root"); DEER_CORE_ASSERT(parent.m_environment == m_environment,
"Can not set parent from diferent enviroments");
DEER_CORE_ASSERT(parent.isValid(), "Parent is not valid"); DEER_CORE_ASSERT(parent.isValid(), "Parent is not valid");
if (parent.getId() == getId()) return;
if (m_parentUID == parent.m_entityUID)
return;
if (m_parentUID != 0){
Entity& current_parent = getParent(); Entity& current_parent = getParent();
if (parent.isDescendant(*this)) { if (parent.isDescendantOf(*this)) {
return; return;
} }
current_parent.removeChild(*this); if (!parent.getComponent<RelationshipComponent>().addChildrenId(
getId())) {
DEER_CORE_ERROR(
"Max child count!!!, could not set parent {0} to entity {1}",
parent.getComponent<TagComponent>().tag.c_str(),
getComponent<TagComponent>().tag.c_str());
return;
} }
m_parentUID = parent.m_entityUID; m_parentID = parent.getId();
getComponent<RelationshipComponent>().parent_UID = parent.m_entityUID; current_parent.getComponent<RelationshipComponent>().removeChildren(
parent.getChildren().push_back(m_entityUID); getId());
getComponent<RelationshipComponent>().parent_id = parent.getId();
} }
bool Entity::isDescendant(Entity& parent) { bool Entity::isDescendantOf(Entity& parent) const {
if (m_entityUID == parent.m_entityUID) DEER_CORE_ASSERT(isValid(), "Entity is not valid");
return true; if (getId() == parent.getId()) return true;
if (isRoot()) return false;
if (isRoot()) return getParent().isDescendantOf(parent);
return false;
return getParent().isDescendant(parent);
} }
Entity& Entity::duplicate() { Entity& Entity::duplicate() {
Entity& creation = m_environment->createEntity(getComponent<TagComponent>().tag + "(d)"); DEER_CORE_ASSERT(isValid(), "Entity is not valid");
Entity& creation = m_environment->createEntity(
getComponent<TagComponent>().tag + "(d)");
creation.getComponent<TransformComponent>() = getComponent<TransformComponent>(); creation.setParent(getParent());
Entity& parent = m_environment->getEntity(m_parentUID);
creation.setParent(parent); creation.getComponent<TransformComponent>() =
getComponent<TransformComponent>();
#ifdef DEER_RENDER #ifdef DEER_RENDER
if (m_environment->m_registry.any_of<MeshRenderComponent>(m_entityHandle)) if (m_environment->m_registry.any_of<MeshRenderComponent>(
creation.addComponent<MeshRenderComponent>(getComponent<MeshRenderComponent>()); m_entityHandle))
creation.addComponent<MeshRenderComponent>(
getComponent<MeshRenderComponent>());
if (m_environment->m_registry.any_of<CameraComponent>(m_entityHandle)) if (m_environment->m_registry.any_of<CameraComponent>(m_entityHandle))
creation.addComponent<CameraComponent>(getComponent<CameraComponent>()); creation.addComponent<CameraComponent>(
getComponent<CameraComponent>());
if (m_environment->m_registry.any_of<TextureBindingComponent>(m_entityHandle)) if (m_environment->m_registry.any_of<TextureBindingComponent>(
creation.addComponent<TextureBindingComponent>(getComponent<TextureBindingComponent>()); m_entityHandle))
creation.addComponent<TextureBindingComponent>(
getComponent<TextureBindingComponent>());
#endif #endif
return creation; return creation;
} }
void Entity::destroy() { void Entity::destroy() {
DEER_CORE_ASSERT(isValid(), "Entity is not valid");
DEER_CORE_ASSERT(!isRoot(), "Can not destroy the root"); DEER_CORE_ASSERT(!isRoot(), "Can not destroy the root");
getParent().removeChild(*this); m_environment->destroyEntity(getId());
if (m_environment->tryGetMainCamera() == m_entityUID)
m_environment->setMainCamera(nullEntity);
for (auto entt : getChildren()) {
m_environment->getEntity(entt).destroy();
} }
m_environment->m_registry.destroy(m_entityHandle); Entity& Entity::getParent() const {
m_entityHandle = entt::null; DEER_CORE_ASSERT(isValid(), "Entity is not valid");
m_environment = nullptr; return m_environment->getEntity(m_parentID);
m_entityUID = 0;
}
Entity& Entity::getParent() {
return m_environment->getEntity(m_parentUID);
}
std::vector<uint32_t>& Entity::getChildren() {
return getComponent<RelationshipComponent>().children;
} }
glm::mat4 Entity::getWorldMatrix() { glm::mat4 Entity::getWorldMatrix() {
if (isRoot()) if (isRoot()) return glm::mat4(1.0f);
return glm::mat4(1.0f);
return getParent().getWorldMatrix() * getRelativeMatrix(); return getParent().getWorldMatrix() * getRelativeMatrix();
} }
@ -110,18 +92,4 @@ namespace Deer {
glm::mat4 Entity::getRelativeMatrix() { glm::mat4 Entity::getRelativeMatrix() {
return getComponent<TransformComponent>().getMatrix(); return getComponent<TransformComponent>().getMatrix();
} }
} // namespace Deer
void Entity::updateInternalVars() {
TagComponent& tag = getComponent<TagComponent>();
RelationshipComponent& relation = getComponent<RelationshipComponent>();
m_entityUID = tag.entityUID;
m_parentUID = relation.parent_UID;
m_isRoot = relation.parent_UID == 0;
if (m_isRoot)
m_environment->m_rootEntity = tag.entityUID;
m_environment->m_entities[tag.entityUID] = *this;
}
}

View File

@ -1,88 +1,134 @@
#include "Deer/Enviroment.h" #include "Deer/Enviroment.h"
#include "Deer/Application.h" #include "Deer/Application.h"
#include "Deer/Asset.h" #include "Deer/Asset.h"
#include "Deer/Components.h" #include "Deer/Components.h"
#include "Deer/Log.h"
#include "DeerRender/Render/Render.h" #include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h" #include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h" #include "DeerRender/Render/Texture.h"
#include "Deer/Log.h"
namespace Deer { namespace Deer {
Environment::Environment() { Environment::Environment() {
entities = MakeScope<std::array<Entity, ENVIRONMENT_MAX_ENTITIES>>();
clear(); clear();
} }
Environment::~Environment() { } Environment::~Environment() {}
void Environment::clear() { void Environment::clear() {
// Clear all existing entities and map // Clear all existing entities and map
m_registry.clear(); m_registry.clear();
m_entities.clear();
m_rootEntity = 0;
m_mainCamera = 0; m_mainCamera = 0;
m_idCreationOffset = 0; m_idCreationOffset = 0;
m_maxIdValue = 0;
// We set it to one because we count root
m_entityCount = 1;
m_rootEntity = pullEntityID(); createEntityWithId(0, "root");
entt::entity rootEntity = m_registry.create();
Entity entity = { rootEntity, this };
entity.addComponent<TagComponent>("root", m_rootEntity);
entity.addComponent<RelationshipComponent>();
entity.addComponent<TransformComponent>();
entity.m_isRoot = true;
entity.m_entityUID = m_rootEntity;
m_entities.insert({ m_rootEntity, entity });
} }
Entity& Environment::getEntity(uint32_t id) { Entity& Environment::getEntity(uint16_t id) const {
DEER_CORE_ASSERT(m_entities.contains(id), "Entity id : {0} does not exist", id); DEER_CORE_ASSERT(entityExists(id), "Entity id {0} does not exist", id);
return m_entities[id]; Entity& refEntity = (*entities)[id];
return refEntity;
} }
Entity& Environment::createEntity(const std::string& name) bool Environment::entityExists(uint16_t id) const {
{ if (id < 0) return false;
uint32_t id; if (id > m_maxIdValue) return false;
if (id >= ENVIRONMENT_MAX_ENTITIES) return false;
Entity& refEntity = (*entities)[id];
return refEntity.isValid();
}
Entity& Environment::createEntity(const std::string& name) {
uint16_t id;
do { do {
id = pullEntityID(); id = pullEntityID();
} while (m_entities.contains(id)); DEER_CORE_ASSERT(id < ENVIRONMENT_MAX_ENTITIES,
"Fatal error, max number of entities exited");
} while (entityExists(id));
entt::entity entityID = m_registry.create(); entt::entity entityID = m_registry.create();
Entity entity = { entityID, this }; Entity& entity = (*entities)[id];
entity = {entityID, this, id};
entity.addComponent<TagComponent>(name, id); entity.addComponent<TagComponent>(name, id);
entity.addComponent<RelationshipComponent>(); entity.addComponent<RelationshipComponent>();
entity.addComponent<TransformComponent>(); entity.addComponent<TransformComponent>();
entity.m_exists = true;
entity.m_entityUID = id; m_entityCount++;
entity.setParent(getRoot()); entity.m_parentID = 0;
if (!getRoot().getComponent<RelationshipComponent>().addChildrenId(
m_entities.insert({ id, entity }); id)) {
return m_entities[id]; DEER_CORE_ERROR("Root is full!");
} }
Entity Environment::createEmptyEntity() {
entt::entity entityID = m_registry.create();
Entity entity = { entityID, this };
return entity; return entity;
} }
uint32_t Environment::tryGetMainCamera() { Entity& Environment::createEntityWithId(uint16_t id,
return m_mainCamera; const std::string& name) {
// We want to initialize all entities that are not initialized to a
// default state of invalid
for (int i = m_maxIdValue + 1; i < id; i++) {
Entity& nullEntity = (*entities)[i];
nullEntity.m_exists = false;
} }
if (m_maxIdValue < id) m_maxIdValue = id;
Entity& entity = (*entities)[id];
entt::entity entityID = m_registry.create();
entity = {entityID, this, id};
entity.m_exists = true;
entity.addComponent<TagComponent>(name, id);
entity.addComponent<RelationshipComponent>();
entity.addComponent<TransformComponent>();
m_entityCount++;
if (id != 0) {
if (!getRoot().getComponent<RelationshipComponent>().addChildrenId(
id)) {
DEER_CORE_ERROR("Root is full!");
}
}
return entity;
}
void Environment::destroyEntity(uint16_t entityID) {
DEER_CORE_ASSERT(entityExists(entityID), "Entity id {0} does not exist",
entityID);
DEER_CORE_ASSERT(entityID == 0, "Can not destroy root");
Entity& entity = (*entities)[entityID];
entity.getParent().getComponent<RelationshipComponent>().removeChildren(
entityID);
RelationshipComponent& relationship =
entity.getComponent<RelationshipComponent>();
// We want to delete all childrens
for (int i = 0; i < relationship.childCount; i++) {
uint16_t childID = relationship.getChildrenId(i);
destroyEntity(childID);
}
if (m_mainCamera == entityID) m_mainCamera = 0;
if (entityID <= m_idCreationOffset) m_idCreationOffset = entityID - 1;
m_registry.destroy(entity.m_entityHandle);
entity.m_exists = false;
m_entityCount--;
}
uint16_t Environment::tryGetMainCamera() { return m_mainCamera; }
void Environment::setMainCamera(Entity& entity) { void Environment::setMainCamera(Entity& entity) {
if (!entity.isValid()) if (!entity.isValid()) m_mainCamera = 0;
m_mainCamera = 0;
m_mainCamera = entity.m_entityUID; m_mainCamera = entity.getId();
} }
} // namespace Deer
Entity& Environment::getRoot() {
return m_entities[m_rootEntity];
}
}

View File

@ -1,22 +1,23 @@
#include "Deer/Scene.h" #include "Deer/Scene.h"
#include "Deer/Memory.h"
#include "Deer/Log.h" #include "Deer/ComponentScript.h"
#include "Deer/VoxelWorld.h" #include "Deer/Components.h"
#include "Deer/Enviroment.h" #include "Deer/Enviroment.h"
#include "Deer/Log.h"
#include "Deer/Memory.h"
#include "Deer/ScriptEngine.h"
#include "Deer/VoxelWorld.h"
#include "Deer/Voxels/Chunk.h" #include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h" #include "Deer/Voxels/Layer.h"
#include "Deer/ScriptEngine.h"
#include "Deer/Components.h"
#include "Deer/ComponentScript.h"
#ifdef DEER_RENDER #ifdef DEER_RENDER
#include "DeerRender/Voxels/VoxelWorldRenderData.h" #include "DeerRender/Voxels/VoxelWorldRenderData.h"
#endif #endif
namespace Deer { namespace Deer {
Scene::Scene() { Scene::Scene() {
m_enviroment = Ref<Environment>(new Environment()); m_enviroment = MakeScope<Environment>();
m_voxelWorld = nullptr;
} }
void Scene::beginExecution() { void Scene::beginExecution() {
@ -27,13 +28,16 @@ namespace Deer {
ScriptEngine::beginExecutionContext(this); ScriptEngine::beginExecutionContext(this);
// Instantiate all the scripts // Instantiate all the scripts
auto view = m_enviroment->m_registry.view<ScriptComponent, TagComponent>(); auto view =
m_enviroment->m_registry.view<ScriptComponent, TagComponent>();
for (auto& entID : view) { for (auto& entID : view) {
auto& tagComponent = view.get<TagComponent>(entID); auto& tagComponent = view.get<TagComponent>(entID);
auto& componentScript = view.get<ScriptComponent>(entID); auto& componentScript = view.get<ScriptComponent>(entID);
Entity& entity = m_enviroment->getEntity(tagComponent.entityUID); Entity& entity = m_enviroment->getEntity(tagComponent.entityUID);
componentScript.roeInstance = ScriptEngine::createComponentScriptInstance(componentScript.scriptID, entity); componentScript.roeInstance =
ScriptEngine::createComponentScriptInstance(
componentScript.scriptID, entity);
componentScript.roeInstance->start(); componentScript.roeInstance->start();
} }
@ -63,15 +67,13 @@ namespace Deer {
} }
void Scene::createVoxelWorld(const VoxelWorldProps& props) { void Scene::createVoxelWorld(const VoxelWorldProps& props) {
m_voxelWorld = Ref<VoxelWorld>(new VoxelWorld(props)); m_voxelWorld = MakeScope<VoxelWorld>(props);
} }
void Scene::deleteVoxelWorld() { void Scene::deleteVoxelWorld() { m_voxelWorld.reset(); }
m_voxelWorld.reset();
}
void Scene::clear() { void Scene::clear() {
m_enviroment->clear(); m_enviroment->clear();
m_voxelWorld.reset(); m_voxelWorld.reset();
} }
} } // namespace Deer

View File

@ -1,130 +1,74 @@
#include <sstream>
#include <string>
#include <vector>
#include "Deer/Scene.h" #include "Deer/Scene.h"
#include "Deer/Scene/Serialization/Serialization.h"
#include "cereal/archives/json.hpp" #include "cereal/archives/json.hpp"
#include "cereal/archives/portable_binary.hpp" #include "cereal/archives/portable_binary.hpp"
#include "Deer/Scene/Serialization/Serialization.h"
#include <vector>
#include <string>
#include <sstream>
namespace Deer { namespace Deer {
Scene loadSceneJson(uint8_t* data, uint32_t size);
Scene loadSceneBin(uint8_t* data, uint32_t size);
Scene SceneDataStore::loadScene(const Path& name) { void SceneDataStore::loadScene(Scene& scene, const Path& name) {
Path realName; Path realName;
realName = Path(DEER_SCENE_PATH) / (name.string() + ".dscn"); realName = Path(DEER_SCENE_PATH) / (name.string() + ".dscn");
uint32_t size; uint32_t size;
uint8_t* data = DataStore::readFile(realName, &size); uint8_t* data = DataStore::readFile(realName, &size);
Scene scene_data;
scene_data = loadSceneJson(data, size);
delete[] data;
return scene_data;
}
Scene loadSceneJson(uint8_t* data, uint32_t size) {
std::string strData((char*)data, size); std::string strData((char*)data, size);
std::istringstream stream(strData); std::istringstream stream(strData);
Scene scene;
{ {
cereal::JSONInputArchive archive(stream); cereal::JSONInputArchive archive(stream);
archive(cereal::make_nvp("scene", scene)); archive(cereal::make_nvp("scene", scene));
} }
return scene; delete[] data;
} }
void SceneDataStore::exportScene(const Scene& scene, const Path& name) {
Scene loadSceneBin(uint8_t* data, uint32_t size) { Path realName;
std::string strData((char*)data, size); realName = Path(DEER_SCENE_PATH) / (name.string() + ".dscn");
std::istringstream stream(strData);
Scene scene;
{
cereal::PortableBinaryInputArchive archive(stream);
archive(cereal::make_nvp("scene", scene));
}
return scene;
}
void SceneDataStore::deleteSceneJson(const Path& name) {
DataStore::deleteFile((Path(DEER_SCENE_PATH) / (name.generic_string() + ".dscn")));
}
void SceneDataStore::exportSceneJson(Scene& scene, const Path& name) {
is_server_serialization = false;
std::stringstream output; std::stringstream output;
{ {
cereal::JSONOutputArchive archive(output); cereal::JSONOutputArchive archive(output);
archive(cereal::make_nvp("scene", scene)); archive(cereal::make_nvp("scene", scene));
} }
Path savePath = Path(DEER_SCENE_PATH) / toLowerCasePath((name.generic_string() + ".dscn"));
std::string_view view = output.view(); std::string_view view = output.view();
DataStore::saveFile(savePath, (uint8_t*)view.data(), view.size()); DataStore::saveFile(realName, (uint8_t*)view.data(), view.size());
} }
void exportSceneBin(Scene& scene, const Path& name) { void SceneDataStore::exportRuntimeScene(const Scene& scene) {
is_server_serialization = false; Path realName;
realName = Path(DEER_TEMP_PATH) / ("temp_scene.dbscn");
std::stringstream output; std::stringstream output;
{ {
cereal::PortableBinaryOutputArchive archive(output); cereal::PortableBinaryOutputArchive archive(output);
archive(cereal::make_nvp("scene", scene)); archive(cereal::make_nvp("scene", scene));
} }
Path savePath = Path(DEER_BIN_PATH) / Path(DEER_SCENE_PATH) / toLowerCasePath((name.generic_string() + ".dbscn"));
std::string_view view = output.view(); std::string_view view = output.view();
DataStore::saveFile(savePath, (uint8_t*)view.data(), view.size()); DataStore::saveFile(realName, (uint8_t*)view.data(), view.size());
} }
void SceneDataStore::importRuntimeScene(Scene& scene) {
Path realName;
realName = Path(DEER_TEMP_PATH) / ("temp_scene.dbscn");
void SceneDataStore::exportScenesBin() {
std::vector<Path> scenes = DataStore::getFiles(DEER_SCENE_PATH, ".dscn");
for (Path& scene_path : scenes) {
uint32_t size; uint32_t size;
uint8_t* data = DataStore::readFile(scene_path, &size); uint8_t* data = DataStore::readFile(realName, &size);
Scene scene_data = loadSceneJson(data, size); std::string strData((char*)data, size);
delete[] data; std::istringstream stream(strData);
Path name = scene_path.lexically_relative(DEER_SCENE_PATH);
name = name.root_path() / name.stem();
exportSceneBin(scene_data, name);
}
}
void SceneDataStore::exportRuntimeScene(Scene& scene) {
std::stringstream output;
{ {
cereal::PortableBinaryOutputArchive archive(output); cereal::PortableBinaryInputArchive archive(stream);
archive(cereal::make_nvp("scene", scene)); archive(cereal::make_nvp("scene", scene));
} }
Path savePath = Path(DEER_TEMP_PATH) / "scene_runtime.dbscn";
std::string_view view = output.view();
DataStore::saveFile(savePath, (uint8_t*)view.data(), view.size());
}
Scene SceneDataStore::importRuntimeScene() {
Path loadPath = Path(DEER_TEMP_PATH) / "scene_runtime.dbscn";
uint32_t size;
uint8_t* data = DataStore::readFile(loadPath, &size);
Scene scene_data = loadSceneBin(data, size);
delete[] data; delete[] data;
return scene_data;
} }
}
} // namespace Deer

View File

@ -3,12 +3,13 @@
namespace Deer { namespace Deer {
// RELATIONSHIP COMPONENT // RELATIONSHIP COMPONENT
template<class Archive> template <class Archive>
void serialize(Archive& archive, void serialize(Archive& archive, RelationshipComponent& relationship) {
RelationshipComponent& relationship) { archive(cereal::make_nvp("parentId", relationship.parent_id));
archive(cereal::make_nvp("parentUID", relationship.parent_UID));
archive(cereal::make_nvp("childrensUIDs", relationship.children));
archive(cereal::make_size_tag(
static_cast<cereal::size_type>(relationship.childCount)));
for (int i = 0; i < relationship.childCount; i++)
archive(relationship.childrens[i]);
} }
} } // namespace Deer

View File

@ -1,83 +1,91 @@
#pragma once #pragma once
#include "Deer/Components.h" #include "Deer/Components.h"
#include "Deer/Enviroment.h"
#include "Deer/Scene/Serialization/SerializationGlobalVars.h" #include "Deer/Scene/Serialization/SerializationGlobalVars.h"
#include "EntitySerializationStruct.h"
namespace Deer { namespace Deer {
template <class Archive, typename T> template <class Archive, typename T>
void saveComponent(Archive& archive, const std::string& componentName, Entity const& m_entity) { void saveComponent(Archive& archive, const std::string& componentName,
Entity const& m_entity) {
bool hasComponent = m_entity.hasComponent<T>(); bool hasComponent = m_entity.hasComponent<T>();
archive(cereal::make_nvp(("has_" + componentName).c_str(), hasComponent)); archive(
cereal::make_nvp(("has_" + componentName).c_str(), hasComponent));
if (hasComponent) { if (hasComponent) {
T& component = m_entity.getComponent<T>(); const T& component = m_entity.getComponent<T>();
archive(cereal::make_nvp(componentName.c_str(), component)); archive(cereal::make_nvp(componentName.c_str(), component));
} }
} }
template <class Archive, typename T> template <class Archive, typename T>
void loadComponent(Archive& archive, const std::string& componentName, Entity const& m_entity) { void loadComponent(Archive& archive, const std::string& componentName,
Entity const& m_entity) {
bool hasComponent; bool hasComponent;
archive(cereal::make_nvp(("has_" + componentName).c_str(), hasComponent)); archive(
cereal::make_nvp(("has_" + componentName).c_str(), hasComponent));
if (hasComponent) { if (hasComponent) {
T& component = m_entity.addComponent<T>(); T& component = m_entity.addComponent<T>();
archive(cereal::make_nvp(componentName.c_str(), component)); archive(cereal::make_nvp(componentName.c_str(), component));
} }
} }
// ENTITY // ENTITY
template<class Archive> template <class Archive>
void save(Archive& archive, void save(Archive& archive, EntitySerializationStruct const& m_entity) {
Entity const& m_entity) { const Entity& entity = m_entity.env->getEntity(m_entity.entityID);
uint32_t id = m_entity.getUID(); const TagComponent& name = entity.getComponent<TagComponent>();
archive(cereal::make_nvp("id", m_entity.entityID));
TagComponent& name = m_entity.getComponent<TagComponent>();
archive(cereal::make_nvp("id", id));
archive(cereal::make_nvp("name", name.tag)); archive(cereal::make_nvp("name", name.tag));
TransformComponent& transform = m_entity.getComponent<TransformComponent>(); const TransformComponent& transform =
entity.getComponent<TransformComponent>();
archive(cereal::make_nvp("transform", transform)); archive(cereal::make_nvp("transform", transform));
RelationshipComponent& relation = m_entity.getComponent<RelationshipComponent>(); const RelationshipComponent& relation =
entity.getComponent<RelationshipComponent>();
archive(cereal::make_nvp("relationship", relation)); archive(cereal::make_nvp("relationship", relation));
#ifdef DEER_RENDER #ifdef DEER_RENDER
if (!is_server_serialization) { if (!is_server_serialization) {
saveComponent<Archive, MeshRenderComponent>(archive, "meshRenderComponent", m_entity); saveComponent<Archive, MeshRenderComponent>(
saveComponent<Archive, CameraComponent>(archive, "cameraComponent", m_entity); archive, "meshRenderComponent", entity);
saveComponent<Archive, TextureBindingComponent>(archive, "textureBindingComponent", m_entity); saveComponent<Archive, CameraComponent>(archive, "cameraComponent",
entity);
saveComponent<Archive, TextureBindingComponent>(
archive, "textureBindingComponent", entity);
} }
#endif #endif
saveComponent<Archive, ScriptComponent>(archive, "scriptComponent", m_entity); saveComponent<Archive, ScriptComponent>(archive, "scriptComponent",
entity);
} }
template<class Archive> template <class Archive>
void load(Archive& archive, void load(Archive& archive, EntitySerializationStruct& m_entity) {
Entity& m_entity) { uint16_t id;
uint32_t id;
std::string name; std::string name;
archive(cereal::make_nvp("id", id)); archive(cereal::make_nvp("id", id));
archive(cereal::make_nvp("name", name)); archive(cereal::make_nvp("name", name));
m_entity.addComponent<TagComponent>() = TagComponent(name, id);
TransformComponent& transform = m_entity.addComponent<TransformComponent>();
archive(cereal::make_nvp("transform", transform));
RelationshipComponent& relationship = m_entity.addComponent<RelationshipComponent>();
archive(cereal::make_nvp("relationship", relationship));
Entity& entity = m_entity.env->createEntityWithId(id);
archive(cereal::make_nvp("transform",
entity.getComponent<TransformComponent>()));
RelationshipComponent& rc =
entity.getComponent<RelationshipComponent>();
archive(cereal::make_nvp("relationship", rc));
entity.setParent(m_entity.env->getEntity(rc.parent_id));
#ifdef DEER_RENDER #ifdef DEER_RENDER
if (!is_server_serialization) { if (!is_server_serialization) {
loadComponent<Archive, MeshRenderComponent>(archive, "meshRenderComponent", m_entity); loadComponent<Archive, MeshRenderComponent>(
loadComponent<Archive, CameraComponent>(archive, "cameraComponent", m_entity); archive, "meshRenderComponent", entity);
loadComponent<Archive, TextureBindingComponent>(archive, "textureBindingComponent", m_entity); loadComponent<Archive, CameraComponent>(archive, "cameraComponent",
entity);
loadComponent<Archive, TextureBindingComponent>(
archive, "textureBindingComponent", entity);
} }
#endif #endif
loadComponent<Archive, ScriptComponent>(archive, "scriptComponent", m_entity); loadComponent<Archive, ScriptComponent>(archive, "scriptComponent",
entity);
m_entity.updateInternalVars();
} }
} } // namespace Deer

View File

@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
namespace Deer {
class Environment;
struct EntitySerializationStruct {
uint16_t entityID;
Environment* env;
};
} // namespace Deer

View File

@ -1,76 +1,57 @@
#pragma once #pragma once
#include <cstdint>
#include "Deer/Enviroment.h"
#include <vector> #include <vector>
#include "Deer/Enviroment.h"
#include "EntitySerializationStruct.h"
namespace Deer { namespace Deer {
struct EntityVector_Environment { struct EnvironmentEntity {
std::vector<Entity> entities; Environment& environment;
const Ref<Environment>& environment; EnvironmentEntity(Environment& env) : environment(env) {}
EntityVector_Environment(const Ref<Environment>& _environment)
: environment(_environment) { }
}; };
template<class Archive> template <class Archive>
void save(Archive& archive, void save(Archive& archive, const Deer::Environment& environment) {
Ref<Environment> const& m_environment) { EnvironmentEntity envEnt(const_cast<Deer::Environment&>(environment));
EntityVector_Environment entityMap(m_environment); archive(cereal::make_nvp("entities", envEnt));
auto view = m_environment->m_registry.view<TagComponent>();
for (auto entity : view) {
TagComponent& tag = view.get<TagComponent>(entity);
entityMap.entities.push_back(m_environment->getEntity(tag.entityUID));
} }
// Sort to avoid conflicts template <class Archive>
std::sort(entityMap.entities.begin(), entityMap.entities.end(), [](Entity& a, Entity& b) { void load(Archive& archive, Deer::Environment& environment) {
return a.getUID() < b.getUID(); EnvironmentEntity envEnt(environment);
}); archive(cereal::make_nvp("entities", envEnt));
uint32_t mainCameraUID = m_environment->tryGetMainCamera();
archive(cereal::make_nvp("entities", entityMap));
archive(cereal::make_nvp("mainCameraUID", mainCameraUID));
} }
template<class Archive> template <class Archive>
void load(Archive& archive, void save(Archive& archive, EnvironmentEntity const& m_entities) {
Ref<Environment>& m_environment) { archive(cereal::make_size_tag(static_cast<cereal::size_type>(
EntityVector_Environment entityMap(m_environment); m_entities.environment.getEntityCount())));
uint32_t mainCameraUID;
archive(cereal::make_nvp("entities", entityMap));
archive(cereal::make_nvp("mainCameraUID", mainCameraUID));
if (mainCameraUID != 0)
m_environment->setMainCamera(m_environment->getEntity(mainCameraUID));
for (uint16_t i = 0; i < m_entities.environment.getEntityCount(); i++) {
while (!m_entities.environment.entityExists(i)) {
i++;
} }
// ENVIRONMENT EntitySerializationStruct serializationStruct;
template<class Archive> serializationStruct.env =
void save(Archive& archive, const_cast<Environment*>(&m_entities.environment);
EntityVector_Environment const& m_entityVector) { serializationStruct.entityID = i;
archive(cereal::make_size_tag(static_cast<cereal::size_type>(m_entityVector.entities.size()))); // number of elements archive(serializationStruct);
for (auto&& v : m_entityVector.entities) }
archive(v);
} }
template<class Archive> template <class Archive>
void load(Archive& archive, void load(Archive& archive, EnvironmentEntity& m_entities) {
EntityVector_Environment& m_entityVector) {
cereal::size_type size; cereal::size_type size;
archive(cereal::make_size_tag(size)); archive(cereal::make_size_tag(size));
m_entityVector.entities.resize(static_cast<std::size_t>(size)); for (int i = 0; i < size; i++) {
for (auto& v : m_entityVector.entities) { EntitySerializationStruct serializationStruct;
v = m_entityVector.environment->createEmptyEntity(); serializationStruct.env = &m_entities.environment;
archive(v);
archive(serializationStruct);
} }
} }
} } // namespace Deer

View File

@ -1,12 +1,10 @@
#pragma once #pragma once
#include "Deer/Scene.h" #include "Deer/Scene.h"
namespace Deer { namespace Deer {
template<class Archive> template <class Archive>
void serialize(Archive& archive, void serialize(Archive& archive, Scene& m_scene) {
Scene& m_scene) { archive(
cereal::make_nvp("main_environment", m_scene.getMainEnviroment()));
archive(cereal::make_nvp("main_environment", m_scene.getMainEnviroment()));
} }
} } // namespace Deer

View File

@ -1,28 +1,26 @@
#pragma once #pragma once
#include "Deer/Asset.h" #include "Deer/Asset.h"
#include "cereal/cereal.hpp" #include "cereal/cereal.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/string.hpp" #include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
// Serialization Vars // Serialization Vars
#include "Deer/Scene/Serialization/SerializationGlobalVars.h" #include "Deer/Scene/Serialization/SerializationGlobalVars.h"
// GENERICS // GENERICS
#include "Deer/Scene/Serialization/Vec3Serialization.h"
#include "Deer/Scene/Serialization/QuatSerialization.h" #include "Deer/Scene/Serialization/QuatSerialization.h"
#include "Deer/Scene/Serialization/Vec3Serialization.h"
// SCENE SPECIFIC // SCENE SPECIFIC
#include "Deer/Scene/Serialization/SceneSerialization.h"
#include "Deer/Scene/Serialization/EnvironmentSerialization.h"
#include "Deer/Scene/Serialization/EntitySerialization.h" #include "Deer/Scene/Serialization/EntitySerialization.h"
#include "Deer/Scene/Serialization/EnvironmentSerialization.h"
#include "Deer/Scene/Serialization/SceneSerialization.h"
// COMPONENTS SPECIFIC // COMPONENTS SPECIFIC
#include "Deer/Scene/Serialization/Components/TransformComponentSerialization.h"
#include "Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h" #include "Deer/Scene/Serialization/Components/RelationshipComponentSerialization.h"
#include "Deer/Scene/Serialization/Components/ScriptComponentSerialization.h" #include "Deer/Scene/Serialization/Components/ScriptComponentSerialization.h"
#include "Deer/Scene/Serialization/Components/TransformComponentSerialization.h"
// RENDER SPECIFIC // RENDER SPECIFIC
#ifdef DEER_RENDER #ifdef DEER_RENDER

View File

@ -1,20 +1,17 @@
#include "Deer/ScriptEngine.h" #include "Deer/ScriptEngine.h"
#include "Deer/Log.h"
#include "Deer/Enviroment.h"
#include "angelscript.h"
#include "scriptbuilder.h"
#include "scriptstdstring.h"
#include "scriptmath.h"
#include "ScriptEngineFunctions.h"
#include "Deer/ComponentScript.h"
#include "Deer/Scene.h"
#include <filesystem> #include <filesystem>
#include "Deer/ComponentScript.h"
#include "Deer/Enviroment.h"
#include "Deer/Log.h"
#include "Deer/Scene.h"
#include "ScriptEngineFunctions.h"
#include "angelscript.h"
#include "scriptbuilder.h"
#include "scriptmath.h"
#include "scriptstdstring.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace Deer { namespace Deer {
@ -28,24 +25,22 @@ namespace Deer {
asIScriptContext* m_context; asIScriptContext* m_context;
ComponentScriptMap m_componentScripts; ComponentScriptMap m_componentScripts;
void loadModuleFolder(const std::filesystem::path& modulePath, const char* moduleName); void loadModuleFolder(const std::filesystem::path& modulePath,
const char* moduleName);
void registerBaseComponents(); void registerBaseComponents();
} } // namespace ScriptEngine
void ScriptEngine::shutdownScriptEngine() { void ScriptEngine::shutdownScriptEngine() { m_componentScripts.clear(); }
m_componentScripts.clear();
}
void ScriptEngine::beginExecutionContext(Scene* executingScene) { void ScriptEngine::beginExecutionContext(Scene* executingScene) {
m_scene = executingScene; m_scene = executingScene;
m_context = m_scriptEngine->CreateContext(); m_context = m_scriptEngine->CreateContext();
} }
void ScriptEngine::endExecutionContext() { void ScriptEngine::endExecutionContext() { m_context->Release(); }
m_context->Release();
}
void ScriptEngine::compileScriptEngine(const std::filesystem::path& modulePath) { void ScriptEngine::compileScriptEngine(
const std::filesystem::path& modulePath) {
m_scriptEngine = asCreateScriptEngine(); m_scriptEngine = asCreateScriptEngine();
m_isCompilationValid = true; m_isCompilationValid = true;
@ -53,7 +48,8 @@ namespace Deer {
loadModuleFolder(modulePath, "Deer"); loadModuleFolder(modulePath, "Deer");
m_scriptModule = m_scriptEngine->GetModule("Deer"); m_scriptModule = m_scriptEngine->GetModule("Deer");
asITypeInfo* m_deerScript = m_scriptModule->GetTypeInfoByName("ComponentScript"); asITypeInfo* m_deerScript =
m_scriptModule->GetTypeInfoByName("ComponentScript");
int classCount = m_scriptModule->GetObjectTypeCount(); int classCount = m_scriptModule->GetObjectTypeCount();
for (int i = 0; i < classCount; i++) { for (int i = 0; i < classCount; i++) {
@ -64,12 +60,13 @@ namespace Deer {
if (parent == m_deerScript) { if (parent == m_deerScript) {
ComponentScript componentScript(type); ComponentScript componentScript(type);
m_componentScripts.insert({ scriptID, componentScript }); m_componentScripts.insert({scriptID, componentScript});
} }
} }
} }
Ref<ComponentScriptInstance> ScriptEngine::createComponentScriptInstance(const std::string& scriptID, Entity& scriptEntity) { Ref<ComponentScriptInstance> ScriptEngine::createComponentScriptInstance(
const std::string& scriptID, Entity& scriptEntity) {
ComponentScript& script = getComponentScript(scriptID); ComponentScript& script = getComponentScript(scriptID);
asITypeInfo* type = script.getTypeInfo(); asITypeInfo* type = script.getTypeInfo();
@ -78,34 +75,43 @@ namespace Deer {
std::string factoryString(script.getName()); std::string factoryString(script.getName());
factoryString = factoryString + " @" + script.getName() + "()"; factoryString = factoryString + " @" + script.getName() + "()";
asIScriptFunction* function = type->GetFactoryByDecl(factoryString.c_str()); asIScriptFunction* function =
type->GetFactoryByDecl(factoryString.c_str());
if (!function) { if (!function) {
DEER_SCRIPT_ERROR("Function constructor not found for class {0}", script.getName()); DEER_SCRIPT_ERROR("Function constructor not found for class {0}",
script.getName());
return nullptr; return nullptr;
} }
int r = m_context->Prepare(function); int r = m_context->Prepare(function);
if (r < 0) { if (r < 0) {
DEER_SCRIPT_ERROR("Failed to prepare constructor context for class {0}", script.getName()); DEER_SCRIPT_ERROR(
"Failed to prepare constructor context for class {0}",
script.getName());
return nullptr; return nullptr;
} }
r = m_context->Execute(); r = m_context->Execute();
if (r < 0) { if (r < 0) {
DEER_SCRIPT_ERROR("Failed to execute constructor for class {0}", script.getName()); DEER_SCRIPT_ERROR("Failed to execute constructor for class {0}",
script.getName());
return nullptr; return nullptr;
} }
asIScriptObject* obj = *(asIScriptObject**)m_context->GetAddressOfReturnValue(); asIScriptObject* obj =
*(asIScriptObject**)m_context->GetAddressOfReturnValue();
obj->AddRef(); obj->AddRef();
int entityPosition = script.getAttribute("entity").internalID; int entityPosition = script.getAttribute("entity").internalID;
unsigned int* entityValue = (unsigned int*)obj->GetAddressOfProperty(entityPosition); unsigned int* entityValue =
(unsigned int*)obj->GetAddressOfProperty(entityPosition);
*entityValue = scriptEntity.getUID(); *entityValue = scriptEntity.getId();
asIScriptFunction* updateFunction = type->GetMethodByDecl("void update()"); asIScriptFunction* updateFunction =
asIScriptFunction* startFunction = type->GetMethodByDecl("void start()"); type->GetMethodByDecl("void update()");
asIScriptFunction* startFunction =
type->GetMethodByDecl("void start()");
instance->m_updateFunction = updateFunction; instance->m_updateFunction = updateFunction;
instance->m_startFuction = startFunction; instance->m_startFuction = startFunction;
instance->m_object = obj; instance->m_object = obj;
@ -113,30 +119,41 @@ namespace Deer {
return Ref<ComponentScriptInstance>(instance); return Ref<ComponentScriptInstance>(instance);
} }
void ScriptEngine::loadModuleFolder(const std::filesystem::path& modulePath, const char* moduleName) { void ScriptEngine::loadModuleFolder(const std::filesystem::path& modulePath,
const char* moduleName) {
CScriptBuilder builder; CScriptBuilder builder;
int r = builder.StartNewModule(m_scriptEngine, moduleName); int r = builder.StartNewModule(m_scriptEngine, moduleName);
DEER_SCRIPT_ASSERT(r >= 0, "Unrecoverable error while starting a new module. {0}", moduleName); DEER_SCRIPT_ASSERT(
r >= 0, "Unrecoverable error while starting a new module. {0}",
moduleName);
try { try {
DEER_CORE_INFO("=== Loading Scripts ==="); DEER_CORE_INFO("=== Loading Scripts ===");
for (const auto& entry : fs::recursive_directory_iterator(modulePath)) { for (const auto& entry :
if (fs::is_regular_file(entry) && entry.path().extension() == ".as") { fs::recursive_directory_iterator(modulePath)) {
if (fs::is_regular_file(entry) &&
entry.path().extension() == ".as") {
r = builder.AddSectionFromFile(
entry.path().generic_string().c_str());
DEER_SCRIPT_ASSERT(r >= 0,
"Please correct the errors in the "
"script and try again. {0}",
entry.path().generic_string().c_str());
r = builder.AddSectionFromFile(entry.path().generic_string().c_str()); DEER_CORE_TRACE(" {0}",
DEER_SCRIPT_ASSERT(r >= 0, "Please correct the errors in the script and try again. {0}", entry.path().generic_string().c_str()); entry.path().filename().string().c_str());
DEER_CORE_TRACE(" {0}", entry.path().filename().string().c_str());
} }
} }
} catch (const fs::filesystem_error& e) { } catch (const fs::filesystem_error& e) {
DEER_CORE_ERROR("Error while loading scripts, error: {0}", e.what()); DEER_CORE_ERROR("Error while loading scripts, error: {0}",
e.what());
} }
r = builder.BuildModule(); r = builder.BuildModule();
if (r < 0) { if (r < 0) {
DEER_SCRIPT_INFO("Please correct the errors in the script and try again."); DEER_SCRIPT_INFO(
"Please correct the errors in the script and try again.");
m_isCompilationValid = false; m_isCompilationValid = false;
} }
} }
@ -154,4 +171,4 @@ namespace Deer {
registerInputFunctions(m_scriptEngine); registerInputFunctions(m_scriptEngine);
registerEntityTransformFunctions(m_scriptEngine); registerEntityTransformFunctions(m_scriptEngine);
} }
} } // namespace Deer

View File

@ -1,34 +1,31 @@
#include "ScriptEngineFunctions.h" #include "ScriptEngineFunctions.h"
#include "Deer/Scene.h"
#include "Deer/Enviroment.h" #include "Deer/Enviroment.h"
#include "Deer/ScriptEngine.h"
#include "angelscript.h"
#include "Deer/Log.h" #include "Deer/Log.h"
#include "Deer/Scene.h"
#include "Deer/ScriptEngine.h"
#include "DeerRender/Input.h" #include "DeerRender/Input.h"
#include "angelscript.h"
#include "glm/glm.hpp" #include "glm/glm.hpp"
namespace Deer { namespace Deer {
void messageCallback(const asSMessageInfo* msg, void* param) { void messageCallback(const asSMessageInfo* msg, void* param) {
if (msg->type == asMSGTYPE_WARNING) { if (msg->type == asMSGTYPE_WARNING) {
DEER_SCRIPT_WARN("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section); DEER_SCRIPT_WARN("({0} {1}) : {2} {3}", msg->row, msg->col,
} msg->message, msg->section);
else if (msg->type == asMSGTYPE_ERROR) { } else if (msg->type == asMSGTYPE_ERROR) {
DEER_SCRIPT_ERROR("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section); DEER_SCRIPT_ERROR("({0} {1}) : {2} {3}", msg->row, msg->col,
} msg->message, msg->section);
else if (msg->type == asMSGTYPE_INFORMATION) { } else if (msg->type == asMSGTYPE_INFORMATION) {
DEER_SCRIPT_INFO("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section); DEER_SCRIPT_INFO("({0} {1}) : {2} {3}", msg->row, msg->col,
} msg->message, msg->section);
else { } else {
DEER_SCRIPT_WARN("({0} {1}) : {2} {3}", msg->row, msg->col, msg->message, msg->section); DEER_SCRIPT_WARN("({0} {1}) : {2} {3}", msg->row, msg->col,
msg->message, msg->section);
} }
} }
void print(std::string& msg) { void print(std::string& msg) { DEER_SCRIPT_INFO(msg.c_str()); }
DEER_SCRIPT_INFO(msg.c_str());
}
glm::vec3 getEntityPosition(uint32_t& entityUID) { glm::vec3 getEntityPosition(uint32_t& entityUID) {
if (entityUID == 0 || entityUID == 1) { if (entityUID == 0 || entityUID == 1) {
@ -36,8 +33,8 @@ namespace Deer {
return glm::vec3(); return glm::vec3();
} }
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment(); Environment& m_environment = ScriptEngine::m_scene->getMainEnviroment();
Entity& entt = m_environment->getEntity(entityUID); Entity& entt = m_environment.getEntity(entityUID);
return entt.getComponent<TransformComponent>().position; return entt.getComponent<TransformComponent>().position;
} }
@ -48,8 +45,8 @@ namespace Deer {
return; return;
} }
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment(); Environment& m_environment = ScriptEngine::m_scene->getMainEnviroment();
Entity& entt = m_environment->getEntity(entityUID); Entity& entt = m_environment.getEntity(entityUID);
entt.getComponent<TransformComponent>().position = position; entt.getComponent<TransformComponent>().position = position;
} }
@ -60,8 +57,8 @@ namespace Deer {
return glm::vec3(); return glm::vec3();
} }
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment(); Environment& m_environment = ScriptEngine::m_scene->getMainEnviroment();
Entity& entt = m_environment->getEntity(entityUID); Entity& entt = m_environment.getEntity(entityUID);
return entt.getComponent<TransformComponent>().scale; return entt.getComponent<TransformComponent>().scale;
} }
@ -72,8 +69,8 @@ namespace Deer {
return; return;
} }
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment(); Environment& m_environment = ScriptEngine::m_scene->getMainEnviroment();
Entity& entt = m_environment->getEntity(entityUID); Entity& entt = m_environment.getEntity(entityUID);
entt.getComponent<TransformComponent>().scale = scale; entt.getComponent<TransformComponent>().scale = scale;
} }
@ -84,118 +81,169 @@ namespace Deer {
return 0; return 0;
} }
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment(); Environment& m_environment = ScriptEngine::m_scene->getMainEnviroment();
Entity& entt = m_environment->getEntity(entityUID); Entity& entt = m_environment.getEntity(entityUID);
return entt.getParentUID(); return entt.getParentId();
} }
bool isEntityValid(uint32_t& entityUID) { bool isEntityValid(uint32_t& entityUID) {
if (entityUID == 0 || entityUID == 1) if (entityUID == 0 || entityUID == 1) return false;
return false;
Ref<Environment>& m_environment = ScriptEngine::m_scene->getMainEnviroment(); Environment& m_environment = ScriptEngine::m_scene->getMainEnviroment();
Entity& entt = m_environment->getEntity(entityUID); Entity& entt = m_environment.getEntity(entityUID);
return entt.isValid(); return entt.isValid();
} }
void registerVec3(asIScriptEngine* engine) { void registerVec3(asIScriptEngine* engine) {
engine->RegisterObjectType("Vec3", sizeof(glm::vec3), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<glm::vec3>() | asOBJ_APP_CLASS_ALLFLOATS); engine->RegisterObjectType("Vec3", sizeof(glm::vec3),
asOBJ_VALUE | asOBJ_POD |
asGetTypeTraits<glm::vec3>() |
asOBJ_APP_CLASS_ALLFLOATS);
engine->RegisterObjectBehaviour("Vec3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR([](void* memory) { engine->RegisterObjectBehaviour(
new (memory) glm::vec3(); "Vec3", asBEHAVE_CONSTRUCT, "void f()",
}, (void*), void), asCALL_CDECL_OBJLAST); asFUNCTIONPR([](void* memory) { new (memory) glm::vec3(); },
engine->RegisterObjectBehaviour("Vec3", asBEHAVE_CONSTRUCT, "void f(float, float = 0, float = 0)", asFUNCTIONPR([](float x, float y, float z, void* memory) { (void*), void),
new (memory) glm::vec3(x, y, z); asCALL_CDECL_OBJLAST);
}, (float, float, float, void*), void), asCALL_CDECL_OBJLAST); engine->RegisterObjectBehaviour(
engine->RegisterObjectProperty("Vec3", "float x", asOFFSET(glm::vec3, x)); "Vec3", asBEHAVE_CONSTRUCT, "void f(float, float = 0, float = 0)",
engine->RegisterObjectProperty("Vec3", "float y", asOFFSET(glm::vec3, y)); asFUNCTIONPR([](float x, float y, float z,
engine->RegisterObjectProperty("Vec3", "float z", asOFFSET(glm::vec3, z)); void* memory) { new (memory) glm::vec3(x, y, z); },
(float, float, float, void*), void),
asCALL_CDECL_OBJLAST);
engine->RegisterObjectProperty("Vec3", "float x",
asOFFSET(glm::vec3, x));
engine->RegisterObjectProperty("Vec3", "float y",
asOFFSET(glm::vec3, y));
engine->RegisterObjectProperty("Vec3", "float z",
asOFFSET(glm::vec3, z));
engine->RegisterObjectMethod("Vec3", "Vec3 opAdd(const Vec3 &in) const", engine->RegisterObjectMethod(
asFUNCTIONPR([](const glm::vec3& a, const glm::vec3& b) -> glm::vec3 { "Vec3", "Vec3 opAdd(const Vec3 &in) const",
return a + b; asFUNCTIONPR([](const glm::vec3& a,
}, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST); const glm::vec3& b) -> glm::vec3 { return a + b; },
(const glm::vec3&, const glm::vec3&), glm::vec3),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "Vec3 opSub(const Vec3 &in) const", engine->RegisterObjectMethod(
asFUNCTIONPR([](const glm::vec3& a, const glm::vec3& b) { "Vec3", "Vec3 opSub(const Vec3 &in) const",
return a - b; asFUNCTIONPR(
}, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST); [](const glm::vec3& a, const glm::vec3& b) { return a - b; },
(const glm::vec3&, const glm::vec3&), glm::vec3),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "Vec3 opMul(float) const", engine->RegisterObjectMethod(
asFUNCTIONPR([](const glm::vec3& a, float scalar) { "Vec3", "Vec3 opMul(float) const",
return a * scalar; asFUNCTIONPR(
}, (const glm::vec3&, float), glm::vec3), asCALL_CDECL_OBJFIRST); [](const glm::vec3& a, float scalar) { return a * scalar; },
(const glm::vec3&, float), glm::vec3),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "Vec3 opDiv(float) const", engine->RegisterObjectMethod(
asFUNCTIONPR([](const glm::vec3& a, float scalar) { "Vec3", "Vec3 opDiv(float) const",
return a / scalar; asFUNCTIONPR(
}, (const glm::vec3&, float), glm::vec3), asCALL_CDECL_OBJFIRST); [](const glm::vec3& a, float scalar) { return a / scalar; },
(const glm::vec3&, float), glm::vec3),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "Vec3 normalize() const", engine->RegisterObjectMethod(
asFUNCTIONPR(glm::normalize, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST); "Vec3", "Vec3 normalize() const",
asFUNCTIONPR(glm::normalize, (const glm::vec3&), glm::vec3),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "float getMagnitude() const", engine->RegisterObjectMethod(
asFUNCTIONPR(glm::length, (const glm::vec3&), float), asCALL_CDECL_OBJFIRST); "Vec3", "float getMagnitude() const",
asFUNCTIONPR(glm::length, (const glm::vec3&), float),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "Vec3 opNeg() const", engine->RegisterObjectMethod(
asFUNCTIONPR([](const glm::vec3& a) { "Vec3", "Vec3 opNeg() const",
return -a; asFUNCTIONPR([](const glm::vec3& a) { return -a; },
}, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST); (const glm::vec3&), glm::vec3),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "bool opEquals(const Vec3 &in) const", engine->RegisterObjectMethod(
asFUNCTIONPR([](const glm::vec3& a, const glm::vec3& b) { "Vec3", "bool opEquals(const Vec3 &in) const",
return a == b; asFUNCTIONPR(
}, (const glm::vec3&, const glm::vec3&), bool), asCALL_CDECL_OBJFIRST); [](const glm::vec3& a, const glm::vec3& b) { return a == b; },
(const glm::vec3&, const glm::vec3&), bool),
asCALL_CDECL_OBJFIRST);
engine->RegisterObjectMethod("Vec3", "string opImplConv() const", engine->RegisterObjectMethod("Vec3", "string opImplConv() const",
asFUNCTIONPR([](const glm::vec3& a) { asFUNCTIONPR(
// Example string conversion using glm (you may need to format it) [](const glm::vec3& a) {
// Example string conversion using
// glm (you may need to format it)
char buffer[64]; char buffer[64];
snprintf(buffer, sizeof(buffer), "(%.2f, %.2f, %.2f)", a.x, a.y, a.z); snprintf(buffer, sizeof(buffer),
"(%.2f, %.2f, %.2f)", a.x,
a.y, a.z);
return std::string(buffer); return std::string(buffer);
}, (const glm::vec3&), std::string), asCALL_CDECL_OBJFIRST); },
(const glm::vec3&), std::string),
asCALL_CDECL_OBJFIRST);
} }
void registerEntity(asIScriptEngine* engine) { void registerEntity(asIScriptEngine* engine) {
engine->RegisterObjectType("Entity", sizeof(unsigned int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); engine->RegisterObjectType(
"Entity", sizeof(unsigned int),
asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);
engine->RegisterObjectProperty("Entity", "uint uint32_t", 0); engine->RegisterObjectProperty("Entity", "uint uint32_t", 0);
engine->RegisterObjectMethod("Entity", "Entity getParent()", asFUNCTION(Deer::getEntityParent), asCALL_CDECL_OBJLAST); engine->RegisterObjectMethod("Entity", "Entity getParent()",
engine->RegisterObjectMethod("Entity", "bool isValid()", asFUNCTION(Deer::isEntityValid), asCALL_CDECL_OBJLAST); asFUNCTION(Deer::getEntityParent),
asCALL_CDECL_OBJLAST);
engine->RegisterGlobalFunction("Entity getEntity(uint)", asFUNCTIONPR([](uint32_t id) { engine->RegisterObjectMethod("Entity", "bool isValid()",
return id; asFUNCTION(Deer::isEntityValid),
}, (uint32_t), uint32_t), asCALL_CDECL); asCALL_CDECL_OBJLAST);
engine->RegisterGlobalFunction(
"Entity getEntity(uint)",
asFUNCTIONPR([](uint32_t id) { return id; }, (uint32_t), uint32_t),
asCALL_CDECL);
} }
void registerDeerFunctions(asIScriptEngine* scriptEngine) { void registerDeerFunctions(asIScriptEngine* scriptEngine) {
int r = scriptEngine->SetMessageCallback(asFUNCTION(Deer::messageCallback), 0, asCALL_CDECL); int r = scriptEngine->SetMessageCallback(
asFUNCTION(Deer::messageCallback), 0, asCALL_CDECL);
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up angel script"); DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up angel script");
r = scriptEngine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Deer::print), asCALL_CDECL); r = scriptEngine->RegisterGlobalFunction("void print(const string &in)",
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void print(const string &in)"); asFUNCTION(Deer::print),
asCALL_CDECL);
DEER_SCRIPT_ASSERT(r >= 0,
"Error in seting up void print(const string &in)");
} }
void registerInputFunctions(asIScriptEngine* scriptEngine) { void registerInputFunctions(asIScriptEngine* scriptEngine) {
int r = scriptEngine->RegisterGlobalFunction("bool isKeyPressed(int)", asFUNCTION(Deer::Input::isKeyPressed), asCALL_CDECL); int r = scriptEngine->RegisterGlobalFunction(
"bool isKeyPressed(int)", asFUNCTION(Deer::Input::isKeyPressed),
asCALL_CDECL);
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up bool isKeyPressed(int)"); DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up bool isKeyPressed(int)");
} }
void registerEntityTransformFunctions(asIScriptEngine* scriptEngine) { void registerEntityTransformFunctions(asIScriptEngine* scriptEngine) {
int r = scriptEngine->RegisterObjectMethod("Entity", "Vec3 getPosition()", asFUNCTION(Deer::getEntityPosition), asCALL_CDECL_OBJLAST); int r = scriptEngine->RegisterObjectMethod(
"Entity", "Vec3 getPosition()", asFUNCTION(Deer::getEntityPosition),
asCALL_CDECL_OBJLAST);
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up Vec3 getPosition()"); DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up Vec3 getPosition()");
scriptEngine->RegisterObjectMethod("Entity", "void setPosition(Vec3)", asFUNCTION(Deer::setEntityPosition), asCALL_CDECL_OBJLAST); scriptEngine->RegisterObjectMethod("Entity", "void setPosition(Vec3)",
asFUNCTION(Deer::setEntityPosition),
asCALL_CDECL_OBJLAST);
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void setPosition(Vec3)"); DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void setPosition(Vec3)");
r = scriptEngine->RegisterObjectMethod("Entity", "Vec3 getScale()", asFUNCTION(Deer::getEntityScale), asCALL_CDECL_OBJLAST); r = scriptEngine->RegisterObjectMethod("Entity", "Vec3 getScale()",
asFUNCTION(Deer::getEntityScale),
asCALL_CDECL_OBJLAST);
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up Vec3 getScale()"); DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up Vec3 getScale()");
scriptEngine->RegisterObjectMethod("Entity", "void setScale(Vec3)", asFUNCTION(Deer::setEntityScale), asCALL_CDECL_OBJLAST); scriptEngine->RegisterObjectMethod("Entity", "void setScale(Vec3)",
asFUNCTION(Deer::setEntityScale),
asCALL_CDECL_OBJLAST);
DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void setScale(Vec3)"); DEER_SCRIPT_ASSERT(r >= 0, "Error in seting up void setScale(Vec3)");
} }
} } // namespace Deer

View File

@ -1,4 +1,5 @@
#include "Deer/VoxelWorld.h" #include "Deer/VoxelWorld.h"
#include "Deer/Log.h" #include "Deer/Log.h"
#include "Deer/Voxels/Chunk.h" #include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h" #include "Deer/Voxels/Layer.h"
@ -8,19 +9,22 @@
#endif #endif
#include <math.h> #include <math.h>
#include <cmath> #include <cmath>
#include <vector> #include <vector>
namespace Deer { namespace Deer {
VoxelWorld::VoxelWorld(const VoxelWorldProps& props) VoxelWorld::VoxelWorld(const VoxelWorldProps& props) : m_worldProps(props) {
: m_worldProps(props) {
m_chunks = MakeScope<Chunk[]>(m_worldProps.getChunkCount()); m_chunks = MakeScope<Chunk[]>(m_worldProps.getChunkCount());
m_layers = MakeScope<Layer[]>(m_worldProps.getLayerCount()); m_layers = MakeScope<Layer[]>(m_worldProps.getLayerCount());
#ifdef DEER_RENDER #ifdef DEER_RENDER
m_renderData = MakeScope<VoxelWorldRenderData>(m_worldProps.getChunkCount()); m_renderData =
MakeScope<VoxelWorldRenderData>(m_worldProps.getChunkCount());
#endif #endif
} }
VoxelWorld::~VoxelWorld() {}
uint16_t VoxelWorld::calculateLayerVoxelHeight(int x, int z) { uint16_t VoxelWorld::calculateLayerVoxelHeight(int x, int z) {
LayerVoxelID layerVoxelID; LayerVoxelID layerVoxelID;
LayerID layerID; LayerID layerID;
@ -32,7 +36,8 @@ namespace Deer {
chunkID.y = y; chunkID.y = y;
Chunk& chunk = m_chunks[m_worldProps.getWorldChunkID(chunkID)]; Chunk& chunk = m_chunks[m_worldProps.getWorldChunkID(chunkID)];
uint8_t chunkVoxelHeight = chunk.calculateLayerVoxelHeight(layerVoxelID); uint8_t chunkVoxelHeight =
chunk.calculateLayerVoxelHeight(layerVoxelID);
if (chunkVoxelHeight != 0) { if (chunkVoxelHeight != 0) {
return chunkVoxelHeight + chunkID.y * CHUNK_SIZE_Y; return chunkVoxelHeight + chunkID.y * CHUNK_SIZE_Y;
@ -40,4 +45,4 @@ namespace Deer {
} }
return 0; return 0;
} }
} } // namespace Deer

View File

@ -1,20 +1,22 @@
#include "Deer/Scene.h" #include "Deer/Scene.h"
#include "Deer/Enviroment.h"
#include "Deer/Components.h" #include "Deer/Components.h"
#include "Deer/Enviroment.h"
#include "Deer/VoxelWorld.h" #include "Deer/VoxelWorld.h"
#include "DeerRender/Render/RenderCommand.h" #include "DeerRender/Render/RenderCommand.h"
#include "Deer/Enviroment.h"
namespace Deer { namespace Deer {
Scene::~Scene() {}
void Scene::render() { void Scene::render() {
uint32_t mainCamera = m_enviroment->tryGetMainCamera(); uint32_t mainCamera = m_enviroment->tryGetMainCamera();
if (mainCamera == 0) if (mainCamera == 0) return;
return;
Entity& m_cameraEntity = m_enviroment->getEntity(mainCamera); Entity& m_cameraEntity = m_enviroment->getEntity(mainCamera);
SceneCamera sceneCamera; SceneCamera sceneCamera;
sceneCamera.camera = m_cameraEntity.getComponent<CameraComponent>(); sceneCamera.camera = m_cameraEntity.getComponent<CameraComponent>();
sceneCamera.transform = m_cameraEntity.getComponent<TransformComponent>(); sceneCamera.transform =
m_cameraEntity.getComponent<TransformComponent>();
Scene::render(sceneCamera); Scene::render(sceneCamera);
} }
@ -22,10 +24,9 @@ namespace Deer {
void Scene::render(SceneCamera sceneCamera) { void Scene::render(SceneCamera sceneCamera) {
RenderCommand::setDepthBuffer(true); RenderCommand::setDepthBuffer(true);
m_enviroment->render(sceneCamera); m_enviroment->render(sceneCamera);
if (m_voxelWorld) if (m_voxelWorld) m_voxelWorld->render(sceneCamera);
m_voxelWorld->render(sceneCamera);
RenderCommand::setDepthBuffer(false); RenderCommand::setDepthBuffer(false);
m_gizmoRenderer.render(sceneCamera); m_gizmoRenderer.render(sceneCamera);
} }
} } // namespace Deer

View File

@ -1,13 +1,12 @@
#pragma once #pragma once
#include <queue>
#include <unordered_set>
#include <vector>
#include "Deer/Memory.h" #include "Deer/Memory.h"
#include "Deer/Voxel.h" #include "Deer/Voxel.h"
#include "DeerRender/Render/VertexArray.h" #include "DeerRender/Render/VertexArray.h"
#include <queue>
#include <vector>
#include <unordered_set>
namespace Deer { namespace Deer {
struct ChunkRender { struct ChunkRender {
Ref<VertexArray> solidVoxel; Ref<VertexArray> solidVoxel;
@ -41,6 +40,7 @@ namespace Deer {
void addChunk(ChunkID); void addChunk(ChunkID);
ChunkID pullChunk(); ChunkID pullChunk();
bool hasChunk(); bool hasChunk();
private: private:
std::queue<ChunkID> m_updateOrder; std::queue<ChunkID> m_updateOrder;
std::unordered_set<ChunkID, ChunkIDHash> m_containingChunks; std::unordered_set<ChunkID, ChunkIDHash> m_containingChunks;
@ -62,4 +62,4 @@ namespace Deer {
std::queue<VoxelCordinates> voxelLightPropagation; std::queue<VoxelCordinates> voxelLightPropagation;
std::vector<VoxelCordinates> tmp_voxelLightSource; std::vector<VoxelCordinates> tmp_voxelLightSource;
}; };
} } // namespace Deer

View File

@ -12,8 +12,8 @@
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions : // furnished to do so, subject to the following conditions :
// //
// The above copyright notice and this permission notice shall be included in all // The above copyright notice and this permission notice shall be included in
// copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -26,17 +26,20 @@
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
// History : // History :
// 2019/11/03 View gizmo // 2019/11/03 View gizmo
// 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by source matrix scales. local/world rotation and translation fixed. Display message is incorrect (X: ... Y:...) in local mode. // 2016/09/11 Behind camera culling. Scaling Delta matrix not multiplied by
// 2016/09/09 Hatched negative axis. Snapping. Documentation update. // source matrix scales. local/world rotation and translation fixed. Display
// 2016/09/04 Axis switch and translation plan autohiding. Scale transform stability improved // message is incorrect (X: ... Y:...) in local mode. 2016/09/09 Hatched
// 2016/09/01 Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing scale and translation/rotation gives bad results. // negative axis. Snapping. Documentation update. 2016/09/04 Axis switch and
// 2016/08/31 First version // translation plan autohiding. Scale transform stability improved 2016/09/01
// Mogwai changed to Manipulate. Draw debug cube. Fixed inverted scale. Mixing
// scale and translation/rotation gives bad results. 2016/08/31 First version
// //
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
// Future (no order): // Future (no order):
// //
// - Multi view // - Multi view
// - display rotation/translation/scale infos in local/world space and not only local // - display rotation/translation/scale infos in local/world space and not only
// local
// - finish local/world matrix application // - finish local/world matrix application
// - OPERATION as bitmask // - OPERATION as bitmask
// //
@ -111,16 +114,17 @@ void EditTransform(const Camera& camera, matrix_t& matrix)
#define IMGUI_API #define IMGUI_API
#endif #endif
namespace ImGuizmo namespace ImGuizmo {
{ // call inside your own window and before Manipulate() in order to draw
// call inside your own window and before Manipulate() in order to draw gizmo to that window. // gizmo to that window. Or pass a specific ImDrawList to draw to (e.g.
// Or pass a specific ImDrawList to draw to (e.g. ImGui::GetForegroundDrawList()). // ImGui::GetForegroundDrawList()).
IMGUI_API void SetDrawlist(ImDrawList* drawlist = nullptr); IMGUI_API void SetDrawlist(ImDrawList *drawlist = nullptr);
// call BeginFrame right after ImGui_XXXX_NewFrame(); // call BeginFrame right after ImGui_XXXX_NewFrame();
IMGUI_API void BeginFrame(); IMGUI_API void BeginFrame();
// return true if mouse cursor is over any gizmo control (axis, plan or screen component) // return true if mouse cursor is over any gizmo control (axis, plan or
// screen component)
IMGUI_API bool IsOver(); IMGUI_API bool IsOver();
// return true if mouse IsOver or if the gizmo is in moving state // return true if mouse IsOver or if the gizmo is in moving state
@ -130,58 +134,71 @@ namespace ImGuizmo
// gizmo is rendered with gray half transparent color when disabled // gizmo is rendered with gray half transparent color when disabled
IMGUI_API void Enable(bool enable); IMGUI_API void Enable(bool enable);
// helper functions for manualy editing translation/rotation/scale with an input float // helper functions for manualy editing translation/rotation/scale with an
// translation, rotation and scale float points to 3 floats each // input float translation, rotation and scale float points to 3 floats each
// Angles are in degrees (more suitable for human editing) // Angles are in degrees (more suitable for human editing)
// example: // example:
// float matrixTranslation[3], matrixRotation[3], matrixScale[3]; // float matrixTranslation[3], matrixRotation[3], matrixScale[3];
// ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation, matrixRotation, matrixScale); // ImGuizmo::DecomposeMatrixToComponents(gizmoMatrix.m16, matrixTranslation,
// ImGui::InputFloat3("Tr", matrixTranslation, 3); // matrixRotation, matrixScale); ImGui::InputFloat3("Tr", matrixTranslation,
// ImGui::InputFloat3("Rt", matrixRotation, 3); // 3); ImGui::InputFloat3("Rt", matrixRotation, 3); ImGui::InputFloat3("Sc",
// ImGui::InputFloat3("Sc", matrixScale, 3); // matrixScale, 3);
// ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, gizmoMatrix.m16); // ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation,
// matrixRotation, matrixScale, gizmoMatrix.m16);
// //
// These functions have some numerical stability issues for now. Use with caution. // These functions have some numerical stability issues for now. Use with
IMGUI_API void DecomposeMatrixToComponents(const float *matrix, float *translation, float *rotation, float *scale); // caution.
IMGUI_API void RecomposeMatrixFromComponents(const float *translation, const float *rotation, const float *scale, float *matrix); IMGUI_API void DecomposeMatrixToComponents(const float *matrix,
float *translation,
float *rotation, float *scale);
IMGUI_API void RecomposeMatrixFromComponents(const float *translation,
const float *rotation,
const float *scale,
float *matrix);
IMGUI_API void SetRect(float x, float y, float width, float height); IMGUI_API void SetRect(float x, float y, float width, float height);
// default is false // default is false
IMGUI_API void SetOrthographic(bool isOrthographic); IMGUI_API void SetOrthographic(bool isOrthographic);
// Render a cube with face color corresponding to face normal. Usefull for debug/tests // Render a cube with face color corresponding to face normal. Usefull for
IMGUI_API void DrawCubes(const float *view, const float *projection, const float *matrices, int matrixCount); // debug/tests
IMGUI_API void DrawGrid(const float *view, const float *projection, const float *matrix, const float gridSize); IMGUI_API void DrawCubes(const float *view, const float *projection,
const float *matrices, int matrixCount);
IMGUI_API void DrawGrid(const float *view, const float *projection,
const float *matrix, const float gridSize);
// call it when you want a gizmo // call it when you want a gizmo
// Needs view and projection matrices. // Needs view and projection matrices.
// matrix parameter is the source matrix (where will be gizmo be drawn) and might be transformed by the function. Return deltaMatrix is optional // matrix parameter is the source matrix (where will be gizmo be drawn) and
// might be transformed by the function. Return deltaMatrix is optional
// translation is applied in world space // translation is applied in world space
enum OPERATION enum OPERATION {
{
TRANSLATE, TRANSLATE,
ROTATE, ROTATE,
SCALE, SCALE,
BOUNDS, BOUNDS,
}; };
enum MODE enum MODE { LOCAL, WORLD };
{
LOCAL,
WORLD
};
IMGUI_API bool Manipulate(const float *view, const float *projection, OPERATION operation, MODE mode, float *matrix, float *deltaMatrix = NULL, float *snap = NULL, float *localBounds = NULL, float *boundsSnap = NULL); IMGUI_API bool Manipulate(const float *view, const float *projection,
OPERATION operation, MODE mode, float *matrix,
float *deltaMatrix = NULL, float *snap = NULL,
float *localBounds = NULL,
float *boundsSnap = NULL);
// //
// Please note that this cubeview is patented by Autodesk : https://patents.google.com/patent/US7782319B2/en // Please note that this cubeview is patented by Autodesk :
// It seems to be a defensive patent in the US. I don't think it will bring troubles using it as // https://patents.google.com/patent/US7782319B2/en It seems to be a
// other software are using the same mechanics. But just in case, you are now warned! // defensive patent in the US. I don't think it will bring troubles using it
// as other software are using the same mechanics. But just in case, you are
// now warned!
// //
IMGUI_API void ViewManipulate(float* view, float length, ImVec2 position, ImVec2 size, ImU32 backgroundColor); IMGUI_API void ViewManipulate(float *view, float length, ImVec2 position,
ImVec2 size, ImU32 backgroundColor);
IMGUI_API void SetID(int id); IMGUI_API void SetID(int id);
// return true if the cursor is over the operation's gizmo // return true if the cursor is over the operation's gizmo
IMGUI_API bool IsOver(OPERATION op); IMGUI_API bool IsOver(OPERATION op);
IMGUI_API void SetGizmoSizeClipSpace(float value); IMGUI_API void SetGizmoSizeClipSpace(float value);
}; }; // namespace ImGuizmo

View File

@ -1,27 +1,26 @@
#include "DeerStudio.h" #include "DeerStudio.h"
#include "Deer/Voxel.h"
#include "Deer/VoxelWorld.h" #include <functional>
#include "Deer/DataStore.h" #include "Deer/DataStore.h"
#include "Deer/Scene.h" #include "Deer/Scene.h"
#include "Deer/ScriptEngine.h" #include "Deer/ScriptEngine.h"
#include "Deer/Voxel.h"
#include "DeerStudio/Editor/PropertiesPannel.h" #include "Deer/VoxelWorld.h"
#include "DeerStudio/Editor/GamePannel.h" #include "DeerStudio/Editor/GamePannel.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Editor/PropertiesPannel.h"
#include "DeerStudio/Editor/SceneExplorer.h" #include "DeerStudio/Editor/SceneExplorer.h"
#include "DeerStudio/Editor/Terrain/TerrainEditor.h"
#include "DeerStudio/Editor/TreePannel.h" #include "DeerStudio/Editor/TreePannel.h"
#include "DeerStudio/Editor/Viewport.h" #include "DeerStudio/Editor/Viewport.h"
#include "DeerStudio/Editor/Terrain/TerrainEditor.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Project.h" #include "DeerStudio/Project.h"
#include "Style.h" #include "Style.h"
#include <functional>
namespace Deer { namespace Deer {
int DeerStudioApplication::onPreInit() { int DeerStudioApplication::onPreInit() {
Path projectPath = Application::m_window->folderDialog(nullptr); Path projectPath = Application::m_window->folderDialog(nullptr);
if (projectPath.empty()) if (projectPath.empty()) return 1;
return 1;
DataStore::rootPath = projectPath; DataStore::rootPath = projectPath;
VoxelData::createExampleVoxelData(); VoxelData::createExampleVoxelData();
@ -34,7 +33,8 @@ namespace Deer {
int DeerStudioApplication::onInit() { int DeerStudioApplication::onInit() {
VoxelData::generateTextureAtlas(); VoxelData::generateTextureAtlas();
VoxelData::loadVoxelsShaders(); VoxelData::loadVoxelsShaders();
ScriptEngine::compileScriptEngine(DataStore::rootPath / std::filesystem::path("scripts")); ScriptEngine::compileScriptEngine(DataStore::rootPath /
std::filesystem::path("scripts"));
Icons::setupIcons(); Icons::setupIcons();
@ -47,10 +47,10 @@ namespace Deer {
strcpy(filenameFLoc, fLoc.c_str()); strcpy(filenameFLoc, fLoc.c_str());
io.IniFilename = filenameFLoc; io.IniFilename = filenameFLoc;
ImFontConfig cnfg; ImFontConfig cnfg;
//cnfg.SizePixels = 26 // cnfg.SizePixels = 26
Path rfPath = DataStore::rootPath / "editor/fonts/Roboto-Regular.ttf"; Path rfPath = DataStore::rootPath / "editor/fonts/Roboto-Regular.ttf";
io.Fonts->AddFontFromFileTTF(rfPath.generic_string().c_str(), 18); io.Fonts->AddFontFromFileTTF(rfPath.generic_string().c_str(), 18);
//io.Fonts->AddFontDefault(&cnfg); // io.Fonts->AddFontDefault(&cnfg);
setNatureStyle(); setNatureStyle();
@ -81,13 +81,12 @@ namespace Deer {
void DeerStudioApplication::onUpdate(Timestep delta) { void DeerStudioApplication::onUpdate(Timestep delta) {
if (Project::m_scene.getExecutingState()) if (Project::m_scene.getExecutingState())
Project::m_scene.updateInternalVars(); Project::m_scene.updateInternalVars();
if (Project::m_scene.getVoxelWorld()) if (Project::m_scene.isVoxelWorldInitialized())
Project::m_scene.getVoxelWorld()->bakeNextChunk(); Project::m_scene.getVoxelWorld().bakeNextChunk();
} }
void DeerStudioApplication::onEvent(Event& e) { void DeerStudioApplication::onEvent(Event& e) {
for (auto& pannel : pannels) for (auto& pannel : pannels) pannel->onEventCallback(e);
pannel->onEventCallback(e);
viewport_onEvent(e); viewport_onEvent(e);
} }
@ -97,15 +96,19 @@ namespace Deer {
static bool opt_padding = false; static bool opt_padding = false;
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None; static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; ImGuiWindowFlags window_flags =
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
{ {
const ImGuiViewport* viewport = ImGui::GetMainViewport(); const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos); ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize); ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID); ImGui::SetNextWindowViewport(viewport->ID);
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; window_flags |= ImGuiWindowFlags_NoTitleBar |
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoNavFocus;
window_flags |= ImGuiWindowFlags_NoBackground; window_flags |= ImGuiWindowFlags_NoBackground;
} }
@ -130,8 +133,9 @@ namespace Deer {
} }
// ---- PANNELS ----- // ---- PANNELS -----
//sceneExplorer_onImGUI(); // sceneExplorer_onImGUI();
//treePannel_onImGui(); TreePannel::treePannel_onImGui();
PropertiesPannel::propertiesPannel_onImgui();
TerrainEditor::terrainEditor_onImGui(); TerrainEditor::terrainEditor_onImGui();
viewport_onImGui(); viewport_onImGui();
// ---- PANNELS ----- // ---- PANNELS -----
@ -143,29 +147,19 @@ namespace Deer {
void DeerStudioApplication::drawMenuBar() { void DeerStudioApplication::drawMenuBar() {
if (ImGui::BeginMenu("Project")) { if (ImGui::BeginMenu("Project")) {
if (ImGui::MenuItem("New project")) { if (ImGui::MenuItem("New project")) {
// TODO
} }
if (ImGui::MenuItem("Open project")) { if (ImGui::MenuItem("Open project")) {
// TODO
} }
if (ImGui::MenuItem("Save project")) { if (ImGui::MenuItem("Save project")) {
// TODO
} }
if (ImGui::MenuItem("Save project as...")) { if (ImGui::MenuItem("Save project as...")) {
// TODO
} }
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("Create binaries")) { if (ImGui::MenuItem("Create binaries")) {
} }
if (ImGui::MenuItem("Export project")) { if (ImGui::MenuItem("Export project")) {
SceneDataStore::exportScenesBin();
std::vector<Path> scenes = DataStore::getFiles("scenes", ".dbscn");
DataStore::compressFiles(scenes, "bin/scene_data");
} }
if (ImGui::MenuItem("Project settings")) { if (ImGui::MenuItem("Project settings")) {
// TODO
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -174,20 +168,22 @@ namespace Deer {
if (ImGui::MenuItem("New scene")) { if (ImGui::MenuItem("New scene")) {
// TODO // TODO
Project::m_scene.clear(); Project::m_scene.clear();
SceneDataStore::exportSceneJson(Project::m_scene, "new_scene"); SceneDataStore::exportScene(Project::m_scene, "new_scene");
} }
//if (Project::m_sceneSerializer->getCurrentScenePath() != "_NO_INITIALIZED_" && ImGui::MenuItem("Save scene")) { // if (Project::m_sceneSerializer->getCurrentScenePath() !=
// "_NO_INITIALIZED_" && ImGui::MenuItem("Save scene")) {
// Project::m_sceneSerializer->serialize(Project::m_sceneSerializer->getCurrentScenePath()); // Project::m_sceneSerializer->serialize(Project::m_sceneSerializer->getCurrentScenePath());
//} // }
if (ImGui::MenuItem("Save scene")) { if (ImGui::MenuItem("Save scene")) {
SceneDataStore::exportSceneJson(Project::m_scene, "saved_scene"); SceneDataStore::exportScene(Project::m_scene, "saved_scene");
} }
if (ImGui::MenuItem("Save scene as...")) { if (ImGui::MenuItem("Save scene as...")) {
// TODO // TODO
} }
if (ImGui::MenuItem("Load scene")) { if (ImGui::MenuItem("Load scene")) {
//Project::m_scene.swap(SceneDataStore::loadScene("new_scene")); // Project::m_scene.swap(SceneDataStore::loadScene("new_scene"));
//SceneDataStore::exportSceneJson(Project::m_scene, "new_scene"); // SceneDataStore::exportScene(Project::m_scene,
// "new_scene");
} }
if (ImGui::MenuItem("Scene settings")) { if (ImGui::MenuItem("Scene settings")) {
// TODO // TODO
@ -217,9 +213,11 @@ namespace Deer {
} }
if (ImGui::BeginMenu("Scripts")) { if (ImGui::BeginMenu("Scripts")) {
if (ImGui::MenuItem("Reload scripts") && !Project::m_scene.getExecutingState()) { if (ImGui::MenuItem("Reload scripts") &&
!Project::m_scene.getExecutingState()) {
ScriptEngine::shutdownScriptEngine(); ScriptEngine::shutdownScriptEngine();
ScriptEngine::compileScriptEngine(std::filesystem::path("scripts")); ScriptEngine::compileScriptEngine(
std::filesystem::path("scripts"));
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -237,10 +235,7 @@ namespace Deer {
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
void DeerStudioApplication::onChangeScene() { void DeerStudioApplication::onChangeScene() { ActiveEntity::clear(); }
ActiveEntity::clear(); } // namespace Deer
}
}

View File

@ -1,18 +1,17 @@
#include "GamePannel.h" #include "GamePannel.h"
#include "DeerStudio/Project.h"
#include "Deer/Enviroment.h"
#include "Deer/Scene.h"
#include "Deer/ScriptEngine.h"
#include "imgui.h"
#include <filesystem> #include <filesystem>
#include "Deer/Enviroment.h"
#include "Deer/Scene.h"
#include "Deer/ScriptEngine.h"
#include "DeerStudio/Project.h"
#include "imgui.h"
namespace Deer { namespace Deer {
GamePannel::GamePannel() { GamePannel::GamePannel() {
FrameBufferSpecification fbSpecs = FrameBufferSpecification(100, 100, { TextureBufferType::RGBA8 }, 1, false); FrameBufferSpecification fbSpecs = FrameBufferSpecification(
100, 100, {TextureBufferType::RGBA8}, 1, false);
m_frameBuffer = FrameBuffer::create(fbSpecs); m_frameBuffer = FrameBuffer::create(fbSpecs);
} }
@ -21,22 +20,23 @@ namespace Deer {
ImGui::Begin("Game Window"); ImGui::Begin("Game Window");
ImGui::PopStyleVar(); ImGui::PopStyleVar();
Ref<Environment> environment = Project::m_scene.getMainEnviroment(); Environment& environment = Project::m_scene.getMainEnviroment();
uint32_t cameraUID = environment->tryGetMainCamera(); uint32_t cameraUID = environment.tryGetMainCamera();
if (cameraUID == 0) { if (cameraUID == 0) {
ImGui::TextColored(ImVec4(.3f, .3f, .8f, 1.0f), "There is no camera"); ImGui::TextColored(ImVec4(.3f, .3f, .8f, 1.0f),
"There is no camera");
if (!Project::m_scene.getExecutingState()) { if (!Project::m_scene.getExecutingState()) {
if (ScriptEngine::isCompilationValid() && ImGui::Button("Execute")) { if (ScriptEngine::isCompilationValid() &&
ImGui::Button("Execute")) {
SceneDataStore::exportRuntimeScene(Project::m_scene); SceneDataStore::exportRuntimeScene(Project::m_scene);
Project::m_scene.beginExecution(); Project::m_scene.beginExecution();
} }
} } else {
else {
if (ImGui::Button("Stop")) { if (ImGui::Button("Stop")) {
Project::m_scene.endExecution(); Project::m_scene.endExecution();
Project::m_scene = SceneDataStore::importRuntimeScene(); SceneDataStore::importRuntimeScene(Project::m_scene);
} }
} }
@ -44,8 +44,9 @@ namespace Deer {
return; return;
} }
Entity& cameraEntity = environment->getEntity(cameraUID); Entity& cameraEntity = environment.getEntity(cameraUID);
CameraComponent& cameraComponent = cameraEntity.getComponent<CameraComponent>(); CameraComponent& cameraComponent =
cameraEntity.getComponent<CameraComponent>();
ImVec2 contentRegionMin = ImGui::GetWindowContentRegionMin(); ImVec2 contentRegionMin = ImGui::GetWindowContentRegionMin();
ImVec2 pos = ImGui::GetWindowPos(); ImVec2 pos = ImGui::GetWindowPos();
@ -55,7 +56,7 @@ namespace Deer {
ImVec2 cursorPos = ImGui::GetCursorPos(); ImVec2 cursorPos = ImGui::GetCursorPos();
if (m_lastWindowSize != *(glm::vec2*)&windowSize) { if (m_lastWindowSize != *(glm::vec2*)&windowSize) {
m_lastWindowSize = { windowSize.x, windowSize.y }; m_lastWindowSize = {windowSize.x, windowSize.y};
m_frameBuffer->resize(windowSize.x, windowSize.y); m_frameBuffer->resize(windowSize.x, windowSize.y);
cameraComponent.aspect = windowSize.x / windowSize.y; cameraComponent.aspect = windowSize.x / windowSize.y;
@ -63,29 +64,30 @@ namespace Deer {
m_frameBuffer->bind(); m_frameBuffer->bind();
m_frameBuffer->clear(); m_frameBuffer->clear();
unsigned char clearColor[4]{ 0, 0, 0, 255 }; unsigned char clearColor[4]{0, 0, 0, 255};
m_frameBuffer->clearBuffer(0, &clearColor); m_frameBuffer->clearBuffer(0, &clearColor);
Project::m_scene.render(); Project::m_scene.render();
m_frameBuffer->unbind(); m_frameBuffer->unbind();
ImGui::Image((void*)(uint64_t)m_frameBuffer->getTextureBufferID(0), windowSize, ImVec2(0, 1), ImVec2(1, 0)); ImGui::Image((void*)(uint64_t)m_frameBuffer->getTextureBufferID(0),
windowSize, ImVec2(0, 1), ImVec2(1, 0));
ImGui::SetCursorPos(cursorPos); ImGui::SetCursorPos(cursorPos);
if (!Project::m_scene.getExecutingState()) { if (!Project::m_scene.getExecutingState()) {
if (ScriptEngine::isCompilationValid() && ImGui::Button("Execute")) { if (ScriptEngine::isCompilationValid() &&
ImGui::Button("Execute")) {
SceneDataStore::exportRuntimeScene(Project::m_scene); SceneDataStore::exportRuntimeScene(Project::m_scene);
Project::m_scene.beginExecution(); Project::m_scene.beginExecution();
} }
} } else {
else {
if (ImGui::Button("Stop")) { if (ImGui::Button("Stop")) {
Project::m_scene.endExecution(); Project::m_scene.endExecution();
Project::m_scene = SceneDataStore::importRuntimeScene(); SceneDataStore::importRuntimeScene(Project::m_scene);
} }
} }
ImGui::End(); ImGui::End();
} }
} } // namespace Deer

View File

@ -1,22 +1,35 @@
#include "PropertiesPannel.h" #include "PropertiesPannel.h"
#include "DeerStudio/Project.h"
#include "DeerRender/Input.h"
#include "DeerRender/KeyCodes.h"
#include "DeerRender/Render/Texture.h"
#include "Deer/Asset.h" #include "Deer/Asset.h"
#include "Deer/ScriptEngine.h" #include "Deer/ScriptEngine.h"
#include "DeerRender/Input.h"
#include "DeerRender/KeyCodes.h"
#include "DeerRender/Render/Texture.h"
#include "DeerStudio/Project.h"
#include "imgui.h" #include "imgui.h"
namespace Deer { namespace Deer {
bool* getIsEditingState(ImGuiID id) namespace PropertiesPannel {
{ void addComponentContext();
template <typename T>
bool collapsingComponentHeader(const std::string& componentName,
bool canDelete = true);
template <typename T>
void addComponentButton(const std::string& componentName);
void addScriptButton(const std::string& scriptID);
void drawMagicSlider(const std::string& text, float* value);
void drawMagicSlider3f(const std::string& text, float* value,
float defaultValue = 0);
} // namespace PropertiesPannel
bool* getIsEditingState(ImGuiID id) {
ImGuiStorage* storage = ImGui::GetStateStorage(); ImGuiStorage* storage = ImGui::GetStateStorage();
void* ptr = storage->GetVoidPtr(id); void* ptr = storage->GetVoidPtr(id);
if (ptr) if (ptr) return (bool*)ptr;
return (bool*)ptr;
// If state doesn't exist, initialize it // If state doesn't exist, initialize it
bool* state = new bool(false); bool* state = new bool(false);
@ -24,7 +37,7 @@ namespace Deer {
return state; return state;
} }
void PropertiesPannel::onImGui() { void PropertiesPannel::propertiesPannel_onImgui() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20));
ImGui::Begin("Properties"); ImGui::Begin("Properties");
@ -49,7 +62,8 @@ namespace Deer {
addComponentContext(); addComponentContext();
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
if (collapsingComponentHeader<TransformComponent>("Transform Component", false)) { if (collapsingComponentHeader<TransformComponent>("Transform Component",
false)) {
auto& transform = activeEntity.getComponent<TransformComponent>(); auto& transform = activeEntity.getComponent<TransformComponent>();
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
ImGui::Indent(); ImGui::Indent();
@ -58,12 +72,10 @@ namespace Deer {
glm::vec3 rotation = transform.getEulerAngles(); glm::vec3 rotation = transform.getEulerAngles();
glm::vec3 lastRotation = rotation; glm::vec3 lastRotation = rotation;
drawMagicSlider3f("Rotation", &rotation.x, 0); drawMagicSlider3f("Rotation", &rotation.x, 0);
if (rotation != lastRotation) if (rotation != lastRotation) transform.setEulerAngles(rotation);
transform.setEulerAngles(rotation);
drawMagicSlider3f("Scale", &transform.scale.x, 1); drawMagicSlider3f("Scale", &transform.scale.x, 1);
if (rotation != lastRotation) if (rotation != lastRotation) transform.setEulerAngles(rotation);
transform.setEulerAngles(rotation);
ImGui::Unindent(); ImGui::Unindent();
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
@ -90,7 +102,8 @@ namespace Deer {
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
} }
if (collapsingComponentHeader<MeshRenderComponent>("Mesh Render Component")) { if (collapsingComponentHeader<MeshRenderComponent>(
"Mesh Render Component")) {
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
ImGui::Indent(); ImGui::Indent();
@ -101,15 +114,19 @@ namespace Deer {
if (mesh.meshAssetID == 0) if (mesh.meshAssetID == 0)
meshName = " null "; meshName = " null ";
else else
meshName = AssetManager::getAssetLocation(mesh.meshAssetID).generic_string(); meshName = AssetManager::getAssetLocation(mesh.meshAssetID)
.generic_string();
ImGui::Text("Mesh : "); ImGui::Text("Mesh : ");
ImGui::SameLine(); ImGui::SameLine();
ImGui::Button(meshName.c_str()); ImGui::Button(meshName.c_str());
if (ImGui::BeginDragDropTarget()) { if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_MESH")) { if (const ImGuiPayload* payload =
std::string receivedData = std::string((const char*)payload->Data); ImGui::AcceptDragDropPayload("_MESH")) {
mesh.meshAssetID = AssetManager::loadAsset<Mesh>(receivedData); std::string receivedData =
std::string((const char*)payload->Data);
mesh.meshAssetID =
AssetManager::loadAsset<Mesh>(receivedData);
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@ -119,15 +136,19 @@ namespace Deer {
if (mesh.shaderAssetID == 0) if (mesh.shaderAssetID == 0)
shaderName = " null "; shaderName = " null ";
else else
shaderName = AssetManager::getAssetLocation(mesh.shaderAssetID).generic_string(); shaderName = AssetManager::getAssetLocation(mesh.shaderAssetID)
.generic_string();
ImGui::Text("Shader : "); ImGui::Text("Shader : ");
ImGui::SameLine(); ImGui::SameLine();
ImGui::Button(shaderName.c_str()); ImGui::Button(shaderName.c_str());
if (ImGui::BeginDragDropTarget()) { if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_SHADER")) { if (const ImGuiPayload* payload =
std::string receivedData = std::string((const char*)payload->Data); ImGui::AcceptDragDropPayload("_SHADER")) {
mesh.shaderAssetID = AssetManager::loadAsset<Shader>(receivedData); std::string receivedData =
std::string((const char*)payload->Data);
mesh.shaderAssetID =
AssetManager::loadAsset<Shader>(receivedData);
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@ -136,23 +157,26 @@ namespace Deer {
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
} }
if (collapsingComponentHeader<TextureBindingComponent>("Texture Binding Component")) if (collapsingComponentHeader<TextureBindingComponent>(
{ "Texture Binding Component")) {
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
ImGui::Indent(); ImGui::Indent();
TextureBindingComponent& textureBinding = activeEntity.getComponent<TextureBindingComponent>(); TextureBindingComponent& textureBinding =
activeEntity.getComponent<TextureBindingComponent>();
int textureBindingCount = 0; int textureBindingCount = 0;
for (int x = 0; x < MAX_TEXTURE_BINDINGS; x++) { for (int x = 0; x < MAX_TEXTURE_BINDINGS; x++) {
if (textureBinding.textureAssetID[x] == 0) if (textureBinding.textureAssetID[x] == 0) continue;
continue;
ImGui::PushID(x); ImGui::PushID(x);
textureBindingCount++; textureBindingCount++;
std::string textureBindingName = AssetManager::getAssetLocation(textureBinding.textureAssetID[x]).generic_string(); std::string textureBindingName =
AssetManager::getAssetLocation(
textureBinding.textureAssetID[x])
.generic_string();
int currentID = textureBinding.textureBindID[x]; int currentID = textureBinding.textureBindID[x];
ImGui::Text("Texture : "); ImGui::Text("Texture : ");
@ -160,11 +184,14 @@ namespace Deer {
ImGui::Button(textureBindingName.c_str()); ImGui::Button(textureBindingName.c_str());
if (ImGui::BeginDragDropTarget()) { if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_TEXTURE2D")) { if (const ImGuiPayload* payload =
std::string receivedData = std::string((const char*)payload->Data); ImGui::AcceptDragDropPayload("_TEXTURE2D")) {
std::string receivedData =
std::string((const char*)payload->Data);
textureBinding.textureAssetID[x] textureBinding.textureAssetID[x] =
= AssetManager::loadAsset<Texture2D>(std::filesystem::path(receivedData)); AssetManager::loadAsset<Texture2D>(
std::filesystem::path(receivedData));
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@ -173,7 +200,9 @@ namespace Deer {
ImGui::SameLine(); ImGui::SameLine();
ImGui::InputInt("#bindingInputID", &currentID, 0); ImGui::InputInt("#bindingInputID", &currentID, 0);
currentID = (currentID < 0) ? 0 : (currentID > 12) ? 12 : currentID; currentID = (currentID < 0) ? 0
: (currentID > 12) ? 12
: currentID;
textureBinding.textureBindID[x] = currentID; textureBinding.textureBindID[x] = currentID;
if (ImGui::Button("Delete texture binding")) if (ImGui::Button("Delete texture binding"))
@ -189,18 +218,20 @@ namespace Deer {
ImGui::Button("Add texture binding"); ImGui::Button("Add texture binding");
if (ImGui::BeginDragDropTarget()) { if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_TEXTURE2D")) { if (const ImGuiPayload* payload =
std::string receivedData = std::string((const char*)payload->Data); ImGui::AcceptDragDropPayload("_TEXTURE2D")) {
std::string receivedData =
std::string((const char*)payload->Data);
for (int x = 0; x < 4; x++) { for (int x = 0; x < 4; x++) {
if (textureBinding.textureAssetID[x] != 0) if (textureBinding.textureAssetID[x] != 0) continue;
continue;
textureBinding.textureAssetID[x] = AssetManager::loadAsset<Texture2D>(std::filesystem::path(receivedData)); textureBinding.textureAssetID[x] =
AssetManager::loadAsset<Texture2D>(
std::filesystem::path(receivedData));
textureBinding.textureBindID[x] = 0; textureBinding.textureBindID[x] = 0;
break; break;
} }
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@ -210,15 +241,15 @@ namespace Deer {
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
} }
if (collapsingComponentHeader<CameraComponent>("Camera Component")) if (collapsingComponentHeader<CameraComponent>("Camera Component")) {
{
ImGui::Dummy(ImVec2(0.0f, 10.0f)); ImGui::Dummy(ImVec2(0.0f, 10.0f));
ImGui::Indent(); ImGui::Indent();
auto& camera = activeEntity.getComponent<CameraComponent>(); auto& camera = activeEntity.getComponent<CameraComponent>();
uint32_t currentMainCamera = activeEntity.getEnvironment()->tryGetMainCamera(); uint32_t currentMainCamera =
if (currentMainCamera == activeEntity.getUID()) activeEntity.getEnvironment()->tryGetMainCamera();
if (currentMainCamera == activeEntity.getId())
ImGui::Button("This is the main camera"); ImGui::Button("This is the main camera");
else if (ImGui::Button("Set main camera")) { else if (ImGui::Button("Set main camera")) {
activeEntity.getEnvironment()->setMainCamera(activeEntity); activeEntity.getEnvironment()->setMainCamera(activeEntity);
@ -238,13 +269,14 @@ namespace Deer {
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
void PropertiesPannel::drawMagicSlider(const std::string& text, float* value) { void PropertiesPannel::drawMagicSlider(const std::string& text,
float* value) {
ImGuiID id = ImGui::GetID(text.c_str()); ImGuiID id = ImGui::GetID(text.c_str());
bool* isEditing = getIsEditingState(id); bool* isEditing = getIsEditingState(id);
if (*isEditing) if (*isEditing) {
{ if (ImGui::InputFloat(text.c_str(), value, 0.0f, 0.0f, "%.3f",
if (ImGui::InputFloat(text.c_str(), value, 0.0f, 0.0f, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue)) ImGuiInputTextFlags_EnterReturnsTrue))
*isEditing = false; *isEditing = false;
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0))
@ -256,26 +288,32 @@ namespace Deer {
ImGui::DragFloat(text.c_str(), value, 0.05f, 0.0f, 0.0f, "%.3f", ImGui::DragFloat(text.c_str(), value, 0.05f, 0.0f, 0.0f, "%.3f",
ImGuiSliderFlags_NoRoundToFormat); ImGuiSliderFlags_NoRoundToFormat);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) if (ImGui::IsItemHovered() &&
ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
*isEditing = true; *isEditing = true;
} }
void PropertiesPannel::drawMagicSlider3f(const std::string& text, float* value, float defaultValue) { void PropertiesPannel::drawMagicSlider3f(const std::string& text,
float* value, float defaultValue) {
ImGui::Columns(4, 0, false); ImGui::Columns(4, 0, false);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2()); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); // Set FrameRounding to 0 for hard edges ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,
0.0f); // Set FrameRounding to 0 for hard edges
ImGui::Text("%s", text.c_str()); ImGui::Text("%s", text.c_str());
ImGui::NextColumn(); ImGui::NextColumn();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.2f, 0.2f, 1.0f)); // Red background ImGui::PushStyleColor(
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.6f, 0.2f, 0.2f, 1.0f)); // Darker red when hovered ImGuiCol_Button, ImVec4(0.7f, 0.2f, 0.2f, 1.0f)); // Red background
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.4f, 0.2f, 0.2f, 1.0f)); // Even darker red when active ImGui::PushStyleColor(
ImGuiCol_ButtonHovered,
ImVec4(0.6f, 0.2f, 0.2f, 1.0f)); // Darker red when hovered
ImGui::PushStyleColor(
ImGuiCol_ButtonActive,
ImVec4(0.4f, 0.2f, 0.2f, 1.0f)); // Even darker red when active
if (ImGui::Button((" X ##" + text).c_str())) if (ImGui::Button((" X ##" + text).c_str())) *value = defaultValue;
*value = defaultValue;
ImGui::SameLine(); ImGui::SameLine();
@ -283,27 +321,36 @@ namespace Deer {
drawMagicSlider("##" + text + "_x", value); drawMagicSlider("##" + text + "_x", value);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.7f, 0.2f, 1.0f)); // Green background ImGui::PushStyleColor(
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.2f, 0.6f, 0.2f, 1.0f)); // Darker green when hovered ImGuiCol_Button,
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.2f, 0.4f, 0.2f, 1.0f)); // Even darker green when active ImVec4(0.2f, 0.7f, 0.2f, 1.0f)); // Green background
ImGui::PushStyleColor(
ImGuiCol_ButtonHovered,
ImVec4(0.2f, 0.6f, 0.2f, 1.0f)); // Darker green when hovered
ImGui::PushStyleColor(
ImGuiCol_ButtonActive,
ImVec4(0.2f, 0.4f, 0.2f, 1.0f)); // Even darker green when active
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::Button((" Y ##" + text).c_str())) if (ImGui::Button((" Y ##" + text).c_str())) value[1] = defaultValue;
value[1] = defaultValue;
ImGui::SameLine(); ImGui::SameLine();
ImGui::PopStyleColor(3); // Restore original style ImGui::PopStyleColor(3); // Restore original style
drawMagicSlider("##" + text + "_y", &value[1]); drawMagicSlider("##" + text + "_y", &value[1]);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.2f, 0.7f, 1.0f)); // Blue background ImGui::PushStyleColor(
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.2f, 0.2f, 0.6f, 1.0f)); // Darker blue when hovered ImGuiCol_Button,
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.2f, 0.2f, 0.4f, 1.0f)); // Even darker blue when active ImVec4(0.2f, 0.2f, 0.7f, 1.0f)); // Blue background
ImGui::PushStyleColor(
ImGuiCol_ButtonHovered,
ImVec4(0.2f, 0.2f, 0.6f, 1.0f)); // Darker blue when hovered
ImGui::PushStyleColor(
ImGuiCol_ButtonActive,
ImVec4(0.2f, 0.2f, 0.4f, 1.0f)); // Even darker blue when active
ImGui::NextColumn(); ImGui::NextColumn();
if (ImGui::Button((" Z ##" + text).c_str())) if (ImGui::Button((" Z ##" + text).c_str())) value[2] = defaultValue;
value[2] = defaultValue;
ImGui::SameLine(); ImGui::SameLine();
ImGui::PopStyleColor(3); // Restore original style ImGui::PopStyleColor(3); // Restore original style
@ -311,19 +358,21 @@ namespace Deer {
drawMagicSlider("##" + text + "_z", &value[2]); drawMagicSlider("##" + text + "_z", &value[2]);
ImGui::Columns(); ImGui::Columns();
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
} }
void PropertiesPannel::addComponentContext() { void PropertiesPannel::addComponentContext() {
float buttonWidth =
float buttonWidth = ImGui::CalcTextSize(" + add Component ").x; // Example button width ImGui::CalcTextSize(" + add Component ").x; // Example button width
float windowWidth = ImGui::GetWindowSize().x; float windowWidth = ImGui::GetWindowSize().x;
float availableWidth = windowWidth - ImGui::GetCursorPosX(); float availableWidth = windowWidth - ImGui::GetCursorPosX();
// Place button at the right, with some padding (e.g., 10px) // Place button at the right, with some padding (e.g., 10px)
ImGui::SetCursorPosX(windowWidth - buttonWidth - 20); ImGui::SetCursorPosX(windowWidth - buttonWidth - 20);
if (ImGui::Button(" + add Component ")) {//, ImVec2(ImGui::GetWindowContentRegionWidth(), 40) if (ImGui::Button(
" + add Component ")) { //,
// ImVec2(ImGui::GetWindowContentRegionWidth(),
// 40)
// Opens a popup window when the button is clicked // Opens a popup window when the button is clicked
ImGui::OpenPopup("Add Component Popup"); ImGui::OpenPopup("Add Component Popup");
} }
@ -331,15 +380,13 @@ namespace Deer {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
ImGui::SetNextWindowSize(ImVec2(240, 200)); ImGui::SetNextWindowSize(ImVec2(240, 200));
// Create the popup window // Create the popup window
if (ImGui::BeginPopup("Add Component Popup")) if (ImGui::BeginPopup("Add Component Popup")) {
{
addComponentButton<MeshRenderComponent>("Mesh Render Component"); addComponentButton<MeshRenderComponent>("Mesh Render Component");
addComponentButton<TextureBindingComponent>("Texture Binding Component"); addComponentButton<TextureBindingComponent>(
"Texture Binding Component");
addComponentButton<CameraComponent>("Camera Component"); addComponentButton<CameraComponent>("Camera Component");
if (ImGui::BeginMenu("Scripts")) { if (ImGui::BeginMenu("Scripts")) {
for (auto& script : ScriptEngine::getComponentScripts()) for (auto& script : ScriptEngine::getComponentScripts())
addScriptButton(script.first.c_str()); addScriptButton(script.first.c_str());
@ -351,14 +398,16 @@ namespace Deer {
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
template<typename T> template <typename T>
inline bool PropertiesPannel::collapsingComponentHeader(const std::string& componentName, bool canDelete) inline bool PropertiesPannel::collapsingComponentHeader(
{ const std::string& componentName, bool canDelete) {
if (!ActiveEntity::shareComponent<T>()) if (!ActiveEntity::shareComponent<T>()) return false;
return false;
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_OpenOnArrow; ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_CollapsingHeader |
bool collapsingHeader = ActiveEntity::shareComponent<T>() && ImGui::TreeNodeEx(componentName.c_str(), flags); ImGuiTreeNodeFlags_DefaultOpen |
ImGuiTreeNodeFlags_OpenOnArrow;
bool collapsingHeader = ActiveEntity::shareComponent<T>() &&
ImGui::TreeNodeEx(componentName.c_str(), flags);
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup(componentName.c_str()); ImGui::OpenPopup(componentName.c_str());
@ -366,7 +415,6 @@ namespace Deer {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
if (ImGui::BeginPopup(componentName.c_str())) { if (ImGui::BeginPopup(componentName.c_str())) {
if (ImGui::Selectable("reset")) { if (ImGui::Selectable("reset")) {
for (auto& entity : ActiveEntity::entities) for (auto& entity : ActiveEntity::entities)
entity->getComponent<T>() = T(); entity->getComponent<T>() = T();
@ -393,9 +441,11 @@ namespace Deer {
} }
void PropertiesPannel::addScriptButton(const std::string& scriptID) { void PropertiesPannel::addScriptButton(const std::string& scriptID) {
ImGuiSelectableFlags selectableFlag = (ActiveEntity::shareComponent<ScriptComponent>()) ? ImGuiSelectableFlags_Disabled : ImGuiSelectableFlags_None; ImGuiSelectableFlags selectableFlag =
(ActiveEntity::shareComponent<ScriptComponent>())
? ImGuiSelectableFlags_Disabled
: ImGuiSelectableFlags_None;
if (ImGui::Selectable(scriptID.c_str(), false, selectableFlag)) { if (ImGui::Selectable(scriptID.c_str(), false, selectableFlag)) {
for (auto& entity : ActiveEntity::entities) { for (auto& entity : ActiveEntity::entities) {
if (!entity->hasComponent<ScriptComponent>()) if (!entity->hasComponent<ScriptComponent>())
entity->addComponent<ScriptComponent>(scriptID); entity->addComponent<ScriptComponent>(scriptID);
@ -405,19 +455,18 @@ namespace Deer {
} }
} }
template<typename T> template <typename T>
void PropertiesPannel::addComponentButton(const std::string& componentName) void PropertiesPannel::addComponentButton(
{ const std::string& componentName) {
ImGuiSelectableFlags selectableFlag = (ActiveEntity::shareComponent<T>()) ? ImGuiSelectableFlags_Disabled : ImGuiSelectableFlags_None; ImGuiSelectableFlags selectableFlag =
(ActiveEntity::shareComponent<T>()) ? ImGuiSelectableFlags_Disabled
: ImGuiSelectableFlags_None;
if (ImGui::Selectable(componentName.c_str(), false, selectableFlag)) { if (ImGui::Selectable(componentName.c_str(), false, selectableFlag)) {
for (auto& entity : ActiveEntity::entities) { for (auto& entity : ActiveEntity::entities) {
if (!entity->hasComponent<T>()) if (!entity->hasComponent<T>()) entity->addComponent<T>();
entity->addComponent<T>();
} }
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
} }
} } // namespace Deer

View File

@ -1,31 +1,10 @@
#pragma once #pragma once
#include "DeerStudio/Editor/EditorPannel.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "Deer/Memory.h" #include "Deer/Memory.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "DeerStudio/Editor/EditorPannel.h"
namespace Deer { namespace Deer {
class PropertiesPannel : public EditorPannel { namespace PropertiesPannel {
public: void propertiesPannel_onImgui();
PropertiesPannel() { } } // namespace PropertiesPannel
void onImGui() override; } // namespace Deer
private:
void addComponentContext();
private:
template<typename T>
bool collapsingComponentHeader(const std::string& componentName, bool canDelete = true);
template<typename T>
void addComponentButton(const std::string& componentName);
void addScriptButton(const std::string& scriptID);
void drawMagicSlider(const std::string& text, float* value);
void drawMagicSlider3f(const std::string& text, float* value, float defaultValue = 0);
};
}

View File

@ -1,22 +1,19 @@
#include "SceneExplorer.h" #include "SceneExplorer.h"
#include "DeerStudio/Project.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "Deer/Path.h"
#include "Deer/DataStore.h"
#include "Deer/Scene.h"
#include "Deer/Log.h"
#include "DeerRender/Render/Texture.h"
#include "Icons.h"
#include "EditorUtils.h"
#include "imgui.h"
#include <regex> #include <regex>
#include <string> #include <string>
#include "Deer/DataStore.h"
#include "Deer/Log.h"
#include "Deer/Path.h"
#include "Deer/Scene.h"
#include "DeerRender/Render/Texture.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "DeerStudio/Project.h"
#include "EditorUtils.h"
#include "Icons.h"
#include "imgui.h"
namespace Deer { namespace Deer {
Path m_currentScenePath("null"); Path m_currentScenePath("null");
Path m_currentSceneName; Path m_currentSceneName;
@ -50,7 +47,8 @@ namespace Deer {
if (m_currentSceneName == "") if (m_currentSceneName == "")
ImGui::OpenPopup("SAVE_SCENE_NAME"); ImGui::OpenPopup("SAVE_SCENE_NAME");
else else
SceneDataStore::exportSceneJson(Project::m_scene, m_currentSceneName); SceneDataStore::exportScene(Project::m_scene,
m_currentSceneName);
} }
if (ImGui::MenuItem("Save as")) { if (ImGui::MenuItem("Save as")) {
@ -69,9 +67,13 @@ namespace Deer {
} }
stringInputPopup<saveSceneName>("SAVE_SCENE_NAME", "Scene name"); stringInputPopup<saveSceneName>("SAVE_SCENE_NAME", "Scene name");
stringInputPopup<createFolderName>("CREATE_SCENE_FOLDER", "Folder name"); stringInputPopup<createFolderName>("CREATE_SCENE_FOLDER",
saveInputPopup<saveBeforeCreatingNew>("SAVE_SCENE_BEFORE_CREATING_NEW", "Do you want to save the scene before creating new?"); "Folder name");
stringInputPopup<saveSceneNameBeforeCreatingNew>("SAVE_SCENE_NAME_CREATE_NEW", "Scene name"); saveInputPopup<saveBeforeCreatingNew>(
"SAVE_SCENE_BEFORE_CREATING_NEW",
"Do you want to save the scene before creating new?");
stringInputPopup<saveSceneNameBeforeCreatingNew>(
"SAVE_SCENE_NAME_CREATE_NEW", "Scene name");
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
@ -80,34 +82,44 @@ namespace Deer {
ImGui::TextDisabled("Active Scene : "); ImGui::TextDisabled("Active Scene : ");
ImGui::SameLine(); ImGui::SameLine();
ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.7f, 1), "%s", m_currentSceneName.generic_string().c_str()); ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.7f, 1), "%s",
m_currentSceneName.generic_string().c_str());
setupColumns(ICON_MIN_SIZE + 80); setupColumns(ICON_MIN_SIZE + 80);
if (m_currentScenePath != DEER_SCENE_PATH) { if (m_currentScenePath != DEER_SCENE_PATH) {
drawSceneExplorerFolder(".."); drawSceneExplorerFolder("..");
float cursorOffset = (ICON_MIN_SIZE - ImGui::CalcTextSize("..").x) / 2; float cursorOffset =
ImGui::SetCursorPos(ImVec2(cursorOffset + ImGui::GetCursorPos().x, ImGui::GetCursorPos().y)); (ICON_MIN_SIZE - ImGui::CalcTextSize("..").x) / 2;
ImGui::SetCursorPos(ImVec2(cursorOffset + ImGui::GetCursorPos().x,
ImGui::GetCursorPos().y));
ImGui::Text(".."); ImGui::Text("..");
ImGui::NextColumn(); ImGui::NextColumn();
} }
for (const auto& entry : std::filesystem::directory_iterator(m_currentScenePath)) { for (const auto& entry :
std::filesystem::directory_iterator(m_currentScenePath)) {
if (entry.is_directory()) if (entry.is_directory())
drawSceneExplorerFolder(entry.path()); drawSceneExplorerFolder(entry.path());
else { else {
std::string extension = entry.path().filename().extension().string(); std::string extension =
if (extension != ".dscn") entry.path().filename().extension().string();
continue; if (extension != ".dscn") continue;
Path sceneName = entry.path().parent_path().lexically_relative(DEER_SCENE_PATH) / entry.path().stem(); Path sceneName = entry.path().parent_path().lexically_relative(
DEER_SCENE_PATH) /
entry.path().stem();
drawSceneExplorerScene(sceneName); drawSceneExplorerScene(sceneName);
} }
float cursorOffset = (ICON_MIN_SIZE - ImGui::CalcTextSize(entry.path().stem().string().c_str()).x) / 2; float cursorOffset =
ImGui::SetCursorPos(ImVec2(cursorOffset + ImGui::GetCursorPos().x, ImGui::GetCursorPos().y)); (ICON_MIN_SIZE -
ImGui::CalcTextSize(entry.path().stem().string().c_str()).x) /
2;
ImGui::SetCursorPos(ImVec2(cursorOffset + ImGui::GetCursorPos().x,
ImGui::GetCursorPos().y));
ImGui::Text("%s", entry.path().stem().string().c_str()); ImGui::Text("%s", entry.path().stem().string().c_str());
ImGui::NextColumn(); ImGui::NextColumn();
@ -116,14 +128,16 @@ namespace Deer {
saveSceneBeforeLoadingPopup(); saveSceneBeforeLoadingPopup();
sceneDialogPopup(); sceneDialogPopup();
deleteInputPopup<deleteScene>("DELETE_SCENE", "Are you sure you want to delete the scene?"); deleteInputPopup<deleteScene>(
"DELETE_SCENE", "Are you sure you want to delete the scene?");
ImGui::End(); ImGui::End();
} }
void drawSceneExplorerFolder(const Path& path) { void drawSceneExplorerFolder(const Path& path) {
ImGui::Image((void*)(uint64_t)Icons::folder_icon->getTextureID(), ImVec2(ICON_MIN_SIZE, ICON_MIN_SIZE), ImVec2(0, 1), ImVec2(1, 0)); ImGui::Image((void*)(uint64_t)Icons::folder_icon->getTextureID(),
ImVec2(ICON_MIN_SIZE, ICON_MIN_SIZE), ImVec2(0, 1),
ImVec2(1, 0));
if (ImGui::IsItemClicked(0) && ImGui::IsMouseDoubleClicked(0)) { if (ImGui::IsItemClicked(0) && ImGui::IsMouseDoubleClicked(0)) {
if (path == "..") if (path == "..")
@ -131,11 +145,12 @@ namespace Deer {
else else
m_currentScenePath = path; m_currentScenePath = path;
} }
} }
void drawSceneExplorerScene(const Path& path) { void drawSceneExplorerScene(const Path& path) {
ImGui::Image((void*)(uint64_t)Icons::scene_icon->getTextureID(), ImVec2(ICON_MIN_SIZE, ICON_MIN_SIZE), ImVec2(0, 1), ImVec2(1, 0)); ImGui::Image((void*)(uint64_t)Icons::scene_icon->getTextureID(),
ImVec2(ICON_MIN_SIZE, ICON_MIN_SIZE), ImVec2(0, 1),
ImVec2(1, 0));
if (ImGui::IsItemClicked(0) && ImGui::IsMouseDoubleClicked(0)) { if (ImGui::IsItemClicked(0) && ImGui::IsMouseDoubleClicked(0)) {
ImGui::OpenPopup("SAVE_SCENE_BEFORE_LOADING"); ImGui::OpenPopup("SAVE_SCENE_BEFORE_LOADING");
@ -161,7 +176,7 @@ namespace Deer {
void saveSceneBeforeLoadingPopup() { void saveSceneBeforeLoadingPopup() {
if (ImGui::BeginPopup("SAVE_SCENE_BEFORE_LOADING")) { if (ImGui::BeginPopup("SAVE_SCENE_BEFORE_LOADING")) {
if (m_currentSceneName == "") { if (m_currentSceneName == "") {
Project::m_scene = SceneDataStore::loadScene(m_loadSceneName); SceneDataStore::loadScene(Project::m_scene, m_loadSceneName);
m_currentSceneName = m_loadSceneName; m_currentSceneName = m_loadSceneName;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
@ -180,17 +195,18 @@ namespace Deer {
if (save) { if (save) {
ActiveEntity::clear(); ActiveEntity::clear();
SceneDataStore::exportSceneJson(Project::m_scene, m_currentSceneName); SceneDataStore::exportScene(Project::m_scene,
Project::m_scene = SceneDataStore::loadScene(m_loadSceneName); m_currentSceneName);
SceneDataStore::loadScene(Project::m_scene, m_loadSceneName);
m_currentSceneName = m_loadSceneName;
ImGui::CloseCurrentPopup();
} else if (dont_save) {
ActiveEntity::clear();
SceneDataStore::loadScene(Project::m_scene, m_loadSceneName);
m_currentSceneName = m_loadSceneName; m_currentSceneName = m_loadSceneName;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
else if (dont_save) { if (cancel) {
ActiveEntity::clear();
Project::m_scene = SceneDataStore::loadScene(m_loadSceneName);
m_currentSceneName = m_loadSceneName;
ImGui::CloseCurrentPopup();
} if (cancel) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
@ -199,7 +215,6 @@ namespace Deer {
} }
void sceneDialogPopup() { void sceneDialogPopup() {
if (ImGui::BeginPopup("SCENE_DIALOG")) { if (ImGui::BeginPopup("SCENE_DIALOG")) {
if (ImGui::MenuItem("Rename Scene")) { if (ImGui::MenuItem("Rename Scene")) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
@ -217,9 +232,8 @@ namespace Deer {
} }
} }
void deleteScene() { // Implement delete scene
SceneDataStore::deleteSceneJson(m_deleteSceneName); void deleteScene() {}
}
void createFolderName(const std::string& name) { void createFolderName(const std::string& name) {
std::string correctInput = sanitizeInput(name); std::string correctInput = sanitizeInput(name);
@ -235,10 +249,12 @@ namespace Deer {
if (m_currentScenePath == DEER_SCENE_PATH) if (m_currentScenePath == DEER_SCENE_PATH)
fullName = correctInput; fullName = correctInput;
else else
fullName = m_currentScenePath.lexically_relative(DEER_SCENE_PATH) / correctInput; fullName =
m_currentScenePath.lexically_relative(DEER_SCENE_PATH) /
correctInput;
m_currentSceneName = fullName; m_currentSceneName = fullName;
SceneDataStore::exportSceneJson(Project::m_scene, fullName); SceneDataStore::exportScene(Project::m_scene, fullName);
} }
} }
void saveBeforeCreatingNew(bool save) { void saveBeforeCreatingNew(bool save) {
@ -246,17 +262,16 @@ namespace Deer {
if (m_currentSceneName == "") { if (m_currentSceneName == "") {
ImGui::OpenPopup("SAVE_SCENE_NAME_CREATE_NEW"); ImGui::OpenPopup("SAVE_SCENE_NAME_CREATE_NEW");
return; return;
} } else {
else {
ActiveEntity::clear(); ActiveEntity::clear();
SceneDataStore::exportSceneJson(Project::m_scene, m_currentSceneName); SceneDataStore::exportScene(Project::m_scene,
Project::m_scene = Scene(); m_currentSceneName);
Project::m_scene.clear();
m_currentSceneName = Path(); m_currentSceneName = Path();
} }
} } else {
else {
ActiveEntity::clear(); ActiveEntity::clear();
Project::m_scene = Scene(); Project::m_scene.clear();
m_currentSceneName = Path(); m_currentSceneName = Path();
} }
} }
@ -268,12 +283,14 @@ namespace Deer {
if (m_currentScenePath == DEER_SCENE_PATH) if (m_currentScenePath == DEER_SCENE_PATH)
fullName = correctInput; fullName = correctInput;
else else
fullName = m_currentScenePath.lexically_relative(DEER_SCENE_PATH) / correctInput; fullName =
m_currentScenePath.lexically_relative(DEER_SCENE_PATH) /
correctInput;
SceneDataStore::exportSceneJson(Project::m_scene, fullName); SceneDataStore::exportScene(Project::m_scene, fullName);
ActiveEntity::clear(); ActiveEntity::clear();
Project::m_scene = Scene(); Project::m_scene.clear();
m_currentSceneName = Path(); m_currentSceneName = Path();
} }
} }
} } // namespace Deer

View File

@ -24,8 +24,7 @@ namespace Deer {
void TerrainEditor::terrainEditor_onImGui() { void TerrainEditor::terrainEditor_onImGui() {
ImGui::Begin("Terrain Editor"); ImGui::Begin("Terrain Editor");
Ref<VoxelWorld>& voxelWorld = Project::m_scene.getVoxelWorld(); if (!Project::m_scene.isVoxelWorldInitialized()) {
if (voxelWorld == nullptr) {
if (ImGui::Button("Create Voxel World")) { if (ImGui::Button("Create Voxel World")) {
ImGui::OpenPopup(TERRAIN_EDITOR_CREATE_VOXEL_WORLD_POPUP_NAME); ImGui::OpenPopup(TERRAIN_EDITOR_CREATE_VOXEL_WORLD_POPUP_NAME);
} }
@ -35,6 +34,7 @@ namespace Deer {
return; return;
} }
VoxelWorld& voxelWorld = Project::m_scene.getVoxelWorld();
ImGui::Text("Edit mode: "); ImGui::Text("Edit mode: ");
setupColumns(ICON_BTN_MIN_SIZE + 16); setupColumns(ICON_BTN_MIN_SIZE + 16);

View File

@ -1,24 +1,21 @@
#include "TerrainEditor.h"
#include "DeerStudio/Project.h"
#include "DeerStudio/Editor/Viewport.h"
#include "DeerStudio/Editor/EditorUtils.h"
#include "DeerStudio/Editor/Icons.h"
#include "Deer/Log.h" #include "Deer/Log.h"
#include "Deer/Scene.h"
#include "Deer/Voxel.h" #include "Deer/Voxel.h"
#include "Deer/VoxelWorld.h" #include "Deer/VoxelWorld.h"
#include "Deer/Scene.h"
#include "DeerRender/GizmoRenderer.h" #include "DeerRender/GizmoRenderer.h"
#include "DeerRender/Render/Texture.h" #include "DeerRender/Render/Texture.h"
#include "DeerStudio/Editor/EditorUtils.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Editor/Viewport.h"
#include "DeerStudio/Project.h"
#include "TerrainEditor.h"
#include "imgui.h" #include "imgui.h"
namespace Deer { namespace Deer {
namespace TerrainEditor { namespace TerrainEditor {
VoxelCordinates selectedVoxelStart(-1, -1, -1); VoxelCordinates selectedVoxelStart(-1, -1, -1);
VoxelCordinates selectedVoxelEnd(-1, -1, -1); VoxelCordinates selectedVoxelEnd(-1, -1, -1);
uint8_t voxelSelectMode = 0; uint8_t voxelSelectMode = 0;
} } // namespace TerrainEditor
void TerrainEditor::boxSelect() { void TerrainEditor::boxSelect() {
ImGui::Separator(); ImGui::Separator();
@ -26,37 +23,45 @@ namespace Deer {
ImGui::Text("Select mode: "); ImGui::Text("Select mode: ");
ImGui::SameLine(); ImGui::SameLine();
if (voxelSelectMode == FACE_VOXEL_SELECT) if (voxelSelectMode == FACE_VOXEL_SELECT)
ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.6f, 1.0f), "%s","Face"); ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.6f, 1.0f), "%s", "Face");
else else
ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.6f, 1.0f), "%s","Voxel"); ImGui::TextColored(ImVec4(0.5f, 1.0f, 0.6f, 1.0f), "%s", "Voxel");
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
setupColumns(ICON_BTN_MIN_SIZE + 16); setupColumns(ICON_BTN_MIN_SIZE + 16);
if (iconButton((ImTextureID)(uint64_t)Icons::face_voxel_selection_icon->getTextureID(), ICON_BTN_MIN_SIZE, voxelSelectMode == FACE_VOXEL_SELECT)) { if (iconButton((ImTextureID)(uint64_t)
Icons::face_voxel_selection_icon->getTextureID(),
ICON_BTN_MIN_SIZE,
voxelSelectMode == FACE_VOXEL_SELECT)) {
voxelSelectMode = FACE_VOXEL_SELECT; voxelSelectMode = FACE_VOXEL_SELECT;
} }
ImGui::Text("Face"); ImGui::Text("Face");
ImGui::NextColumn(); ImGui::NextColumn();
if (iconButton((ImTextureID)(uint64_t)Icons::internal_voxel_selection_icon->getTextureID(), ICON_BTN_MIN_SIZE, voxelSelectMode == INTERNAL_VOXEL_SELECT)) { if (iconButton((ImTextureID)(uint64_t)
Icons::internal_voxel_selection_icon->getTextureID(),
ICON_BTN_MIN_SIZE,
voxelSelectMode == INTERNAL_VOXEL_SELECT)) {
voxelSelectMode = INTERNAL_VOXEL_SELECT; voxelSelectMode = INTERNAL_VOXEL_SELECT;
} }
ImGui::Text("Voxel"); ImGui::Text("Voxel");
ImGui::Columns(); ImGui::Columns();
if (!viewportIsActive()) { if (!viewportIsActive()) {
if (selectedVoxelStart.isNull()) if (selectedVoxelStart.isNull()) selectedVoxelStart.makeNull();
selectedVoxelStart.makeNull();
return; return;
} }
if (ImGui::IsMouseDragging(ImGuiMouseButton_Left) || ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { if (ImGui::IsMouseDragging(ImGuiMouseButton_Left) ||
ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
if (voxelSelectMode == FACE_VOXEL_SELECT) { if (voxelSelectMode == FACE_VOXEL_SELECT) {
selectedVoxelEnd = voxelFaceRayCoords; selectedVoxelEnd = voxelFaceRayCoords;
} else { } else {
selectedVoxelEnd = voxelRayCoords; selectedVoxelEnd = voxelRayCoords;
} }
Project::m_scene.getVoxelWorld()->getVoxelWorldProps().clampCordinates(selectedVoxelEnd); Project::m_scene.getVoxelWorld()
.getVoxelWorldProps()
.clampCordinates(selectedVoxelEnd);
} }
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) == 1) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) == 1) {
@ -67,12 +72,10 @@ namespace Deer {
selectedVoxelStart.makeNull(); selectedVoxelStart.makeNull();
selectedVoxelEnd.makeNull(); selectedVoxelEnd.makeNull();
} }
} }
void TerrainEditor::boxSelect_Visuals() { void TerrainEditor::boxSelect_Visuals() {
VoxelWorld& voxelWorld = Project::m_scene.getVoxelWorld();
Ref<VoxelWorld>& voxelWorld = Project::m_scene.getVoxelWorld();
GizmoRenderer& gizmo = Project::m_scene.getMainGizmoRenderer(); GizmoRenderer& gizmo = Project::m_scene.getMainGizmoRenderer();
if (!selectedVoxelStart.isNull() && !selectedVoxelEnd.isNull()) { if (!selectedVoxelStart.isNull() && !selectedVoxelEnd.isNull()) {
@ -110,33 +113,43 @@ namespace Deer {
// Z Face // Z Face
for (int x = min.x; x <= max.x; x++) { for (int x = min.x; x <= max.x; x++) {
for (int y = min.y; y <= max.y; y++) { for (int y = min.y; y <= max.y; y++) {
gizmo.drawVoxelFace(x, y, min.z, debugVoxel, NORMAL_BACK, 5); gizmo.drawVoxelFace(x, y, min.z, debugVoxel, NORMAL_BACK,
gizmo.drawVoxelFace(x, y, max.z, debugVoxel, NORMAL_FRONT, 5); 5);
gizmo.drawVoxelFaceInverted(x, y, min.z, debugInternal, NORMAL_BACK, 4); gizmo.drawVoxelFace(x, y, max.z, debugVoxel, NORMAL_FRONT,
gizmo.drawVoxelFaceInverted(x, y, max.z, debugInternal, NORMAL_FRONT, 4); 5);
gizmo.drawVoxelFaceInverted(x, y, min.z, debugInternal,
NORMAL_BACK, 4);
gizmo.drawVoxelFaceInverted(x, y, max.z, debugInternal,
NORMAL_FRONT, 4);
} }
} }
// Y Face // Y Face
for (int x = min.x; x <= max.x; x++) { for (int x = min.x; x <= max.x; x++) {
for (int z = min.z; z <= max.z; z++) { for (int z = min.z; z <= max.z; z++) {
gizmo.drawVoxelFace(x, min.y, z, debugVoxel, NORMAL_DOWN, 5); gizmo.drawVoxelFace(x, min.y, z, debugVoxel, NORMAL_DOWN,
5);
gizmo.drawVoxelFace(x, max.y, z, debugVoxel, NORMAL_UP, 5); gizmo.drawVoxelFace(x, max.y, z, debugVoxel, NORMAL_UP, 5);
gizmo.drawVoxelFaceInverted(x, min.y, z, debugInternal, NORMAL_DOWN, 4); gizmo.drawVoxelFaceInverted(x, min.y, z, debugInternal,
gizmo.drawVoxelFaceInverted(x, max.y, z, debugInternal, NORMAL_UP, 4); NORMAL_DOWN, 4);
gizmo.drawVoxelFaceInverted(x, max.y, z, debugInternal,
NORMAL_UP, 4);
} }
} }
// X Face // X Face
for (int y = min.y; y <= max.y; y++) { for (int y = min.y; y <= max.y; y++) {
for (int z = min.z; z <= max.z; z++) { for (int z = min.z; z <= max.z; z++) {
gizmo.drawVoxelFace(min.x, y, z, debugVoxel, NORMAL_LEFT, 5); gizmo.drawVoxelFace(min.x, y, z, debugVoxel, NORMAL_LEFT,
gizmo.drawVoxelFace(max.x, y, z, debugVoxel, NORMAL_RIGHT, 5); 5);
gizmo.drawVoxelFaceInverted(min.x, y, z, debugInternal, NORMAL_LEFT, 4); gizmo.drawVoxelFace(max.x, y, z, debugVoxel, NORMAL_RIGHT,
gizmo.drawVoxelFaceInverted(max.x, y, z, debugInternal, NORMAL_RIGHT, 4); 5);
gizmo.drawVoxelFaceInverted(min.x, y, z, debugInternal,
NORMAL_LEFT, 4);
gizmo.drawVoxelFaceInverted(max.x, y, z, debugInternal,
NORMAL_RIGHT, 4);
} }
} }
} }
} }
} } // namespace Deer

View File

@ -84,7 +84,7 @@ namespace Deer {
props.chunkSizeZ = values[2]; props.chunkSizeZ = values[2];
Project::m_scene.createVoxelWorld(props); Project::m_scene.createVoxelWorld(props);
Project::m_scene.getVoxelWorld()->fillVoxels( Project::m_scene.getVoxelWorld().fillVoxels(
VoxelCordinates(0, 0, 0), VoxelCordinates(31, 8, 31), VoxelCordinates(0, 0, 0), VoxelCordinates(31, 8, 31),
Voxel(VoxelData::getVoxelID("wood"))); Voxel(VoxelData::getVoxelID("wood")));

View File

@ -1,40 +1,39 @@
#include "TerrainEditor.h" #include "Deer/Scene.h"
#include "DeerStudio/Project.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Editor/Viewport.h"
#include "DeerStudio/Editor/EditorUtils.h"
#include "Deer/Voxel.h" #include "Deer/Voxel.h"
#include "Deer/VoxelWorld.h" #include "Deer/VoxelWorld.h"
#include "Deer/Scene.h"
#include "DeerRender/GizmoRenderer.h" #include "DeerRender/GizmoRenderer.h"
#include "DeerStudio/Editor/EditorUtils.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Editor/Viewport.h"
#include "DeerStudio/Project.h"
#include "TerrainEditor.h"
#include "imgui.h" #include "imgui.h"
namespace Deer { namespace Deer {
void TerrainEditor::empty() { void TerrainEditor::empty() {
if (!viewportIsActive()) if (!viewportIsActive()) return;
return;
VoxelCordinates selectVoxel; VoxelCordinates selectVoxel;
VoxelCordinates clampedCordinates; VoxelCordinates clampedCordinates;
selectVoxel = voxelRayCoords; selectVoxel = voxelRayCoords;
clampedCordinates = selectVoxel; clampedCordinates = selectVoxel;
Project::m_scene.getVoxelWorld()->getVoxelWorldProps().clampCordinates(clampedCordinates); Project::m_scene.getVoxelWorld().getVoxelWorldProps().clampCordinates(
clampedCordinates);
if (clampedCordinates != selectVoxel) if (clampedCordinates != selectVoxel) return;
return;
VoxelCordinates min = selectedVoxelStart; VoxelCordinates min = selectedVoxelStart;
VoxelCordinates max = selectedVoxelEnd; VoxelCordinates max = selectedVoxelEnd;
if (min.isNull() || max.isNull()) { if (min.isNull() || max.isNull()) {
min = VoxelCordinates(selectVoxel.x - 16, selectVoxel.y - 16, selectVoxel.z - 16); min = VoxelCordinates(selectVoxel.x - 16, selectVoxel.y - 16,
max = VoxelCordinates(selectVoxel.x + 15, selectVoxel.y + 15, selectVoxel.z + 15); selectVoxel.z - 16);
max = VoxelCordinates(selectVoxel.x + 15, selectVoxel.y + 15,
selectVoxel.z + 15);
} }
Project::m_scene.getVoxelWorld()->getVoxelWorldProps().clampAndSetMinMax(min, max); Project::m_scene.getVoxelWorld().getVoxelWorldProps().clampAndSetMinMax(
min, max);
if (selectVoxel.x < min.x || selectVoxel.x > max.x || if (selectVoxel.x < min.x || selectVoxel.x > max.x ||
selectVoxel.y < min.y || selectVoxel.y > max.y || selectVoxel.y < min.y || selectVoxel.y > max.y ||
@ -42,13 +41,16 @@ namespace Deer {
return; return;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
Project::m_scene.getMainGizmoRenderer().drawVoxelFace(clampedCordinates.x, clampedCordinates.y, clampedCordinates.z, Project::m_scene.getMainGizmoRenderer().drawVoxelFace(
clampedCordinates.x, clampedCordinates.y, clampedCordinates.z,
VoxelData::getVoxelID("debug"), i, 0); VoxelData::getVoxelID("debug"), i, 0);
} }
if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left)) { if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left)) {
Voxel voxel = Project::m_scene.getVoxelWorld()->readVoxel(selectVoxel); Voxel voxel =
Project::m_scene.getVoxelWorld()->remplaceVoxels(min, max, voxel, Voxel(0)); Project::m_scene.getVoxelWorld().readVoxel(selectVoxel);
Project::m_scene.getVoxelWorld().remplaceVoxels(min, max, voxel,
Voxel(0));
} }
} }
} } // namespace Deer

View File

@ -52,7 +52,7 @@ namespace Deer {
} }
clampedCordinates = selectVoxel; clampedCordinates = selectVoxel;
Project::m_scene.getVoxelWorld()->getVoxelWorldProps().clampCordinates( Project::m_scene.getVoxelWorld().getVoxelWorldProps().clampCordinates(
clampedCordinates); clampedCordinates);
if (clampedCordinates != selectVoxel) return; if (clampedCordinates != selectVoxel) return;
@ -66,9 +66,8 @@ namespace Deer {
max = VoxelCordinates(selectVoxel.x + 15, selectVoxel.y + 15, max = VoxelCordinates(selectVoxel.x + 15, selectVoxel.y + 15,
selectVoxel.z + 15); selectVoxel.z + 15);
} }
Project::m_scene.getVoxelWorld() Project::m_scene.getVoxelWorld().getVoxelWorldProps().clampAndSetMinMax(
->getVoxelWorldProps() min, max);
.clampAndSetMinMax(min, max);
if (selectVoxel.x < min.x || selectVoxel.x > max.x || if (selectVoxel.x < min.x || selectVoxel.x > max.x ||
selectVoxel.y < min.y || selectVoxel.y > max.y || selectVoxel.y < min.y || selectVoxel.y > max.y ||
@ -83,8 +82,8 @@ namespace Deer {
if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left)) { if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left)) {
Voxel voxel = Voxel voxel =
Project::m_scene.getVoxelWorld()->readVoxel(selectVoxel); Project::m_scene.getVoxelWorld().readVoxel(selectVoxel);
Project::m_scene.getVoxelWorld()->remplaceVoxels( Project::m_scene.getVoxelWorld().remplaceVoxels(
min, max, voxel, Voxel(selectedVoxelID)); min, max, voxel, Voxel(selectedVoxelID));
} }
} }

View File

@ -1,34 +1,42 @@
#include "TerrainEditor.h"
#include "DeerStudio/Project.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Editor/EditorUtils.h"
#include "Deer/Voxel.h"
#include "Deer/Scene.h"
#include "Deer/VoxelWorld.h"
#include "imgui.h"
#include <string> #include <string>
#include "Deer/Scene.h"
#include "Deer/Voxel.h"
#include "Deer/VoxelWorld.h"
#include "DeerStudio/Editor/EditorUtils.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Project.h"
#include "TerrainEditor.h"
#include "imgui.h"
namespace Deer { namespace Deer {
namespace TerrainEditor { namespace TerrainEditor {
void deleteVoxelWorld(); void deleteVoxelWorld();
} }
void TerrainEditor::info() { void TerrainEditor::info() {
Ref<VoxelWorld>& voxelWorld = Project::m_scene.getVoxelWorld(); VoxelWorld& voxelWorld = Project::m_scene.getVoxelWorld();
VoxelWorldProps worldProps = voxelWorld->getVoxelWorldProps(); VoxelWorldProps worldProps = voxelWorld.getVoxelWorldProps();
ImGui::Text("Voxel world chunk and voxel size:"); ImGui::Text("Voxel world chunk and voxel size:");
ImGui::Text(" x: %s chunks -> %s voxels", std::to_string(worldProps.chunkSizeX).c_str(), std::to_string(worldProps.chunkSizeX * CHUNK_SIZE_X).c_str()); ImGui::Text(
ImGui::Text(" y: %s chunks -> %s voxels", std::to_string(worldProps.chunkSizeY).c_str(), std::to_string(worldProps.chunkSizeY * CHUNK_SIZE_Y).c_str()); " x: %s chunks -> %s voxels",
ImGui::Text(" z: %s chunks -> %s voxels", std::to_string(worldProps.chunkSizeZ).c_str(), std::to_string(worldProps.chunkSizeZ * CHUNK_SIZE_Z).c_str()); std::to_string(worldProps.chunkSizeX).c_str(),
std::to_string(worldProps.chunkSizeX * CHUNK_SIZE_X).c_str());
ImGui::Text(
" y: %s chunks -> %s voxels",
std::to_string(worldProps.chunkSizeY).c_str(),
std::to_string(worldProps.chunkSizeY * CHUNK_SIZE_Y).c_str());
ImGui::Text(
" z: %s chunks -> %s voxels",
std::to_string(worldProps.chunkSizeZ).c_str(),
std::to_string(worldProps.chunkSizeZ * CHUNK_SIZE_Z).c_str());
ImGui::Separator(); ImGui::Separator();
int64_t voxelCount = CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z *
int64_t voxelCount = CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z * worldProps.chunkSizeX * worldProps.chunkSizeY * worldProps.chunkSizeZ; worldProps.chunkSizeX * worldProps.chunkSizeY *
worldProps.chunkSizeZ;
int64_t clientSize = voxelCount * (sizeof(Voxel) + sizeof(VoxelLight)); int64_t clientSize = voxelCount * (sizeof(Voxel) + sizeof(VoxelLight));
int64_t serverSize = voxelCount * (sizeof(Voxel)); int64_t serverSize = voxelCount * (sizeof(Voxel));
@ -42,8 +50,10 @@ namespace Deer {
ImGui::Text("%s", "Client theorical max size : "); ImGui::Text("%s", "Client theorical max size : ");
ImGui::Text(" %sB", std::to_string(clientSize).c_str()); ImGui::Text(" %sB", std::to_string(clientSize).c_str());
ImGui::Text(" +%sKB", std::to_string(clientSize / 1024).c_str()); ImGui::Text(" +%sKB", std::to_string(clientSize / 1024).c_str());
ImGui::Text(" +%sMB", std::to_string(clientSize / (1024 * 1024)).c_str()); ImGui::Text(" +%sMB",
ImGui::Text(" +%sGB", std::to_string(clientSize / (1024 * 1024 * 1024)).c_str()); std::to_string(clientSize / (1024 * 1024)).c_str());
ImGui::Text(" +%sGB",
std::to_string(clientSize / (1024 * 1024 * 1024)).c_str());
ImGui::Spacing(); ImGui::Spacing();
ImGui::Separator(); ImGui::Separator();
@ -51,40 +61,39 @@ namespace Deer {
ImGui::Text("%s", "Server theorical max size : "); ImGui::Text("%s", "Server theorical max size : ");
ImGui::Text(" %sB", std::to_string(serverSize).c_str()); ImGui::Text(" %sB", std::to_string(serverSize).c_str());
ImGui::Text(" +%sKB", std::to_string(serverSize / 1024).c_str()); ImGui::Text(" +%sKB", std::to_string(serverSize / 1024).c_str());
ImGui::Text(" +%sMB", std::to_string(serverSize / (1024 * 1024)).c_str()); ImGui::Text(" +%sMB",
ImGui::Text(" +%sGB", std::to_string(serverSize / (1024 * 1024 * 1024)).c_str()); std::to_string(serverSize / (1024 * 1024)).c_str());
ImGui::Text(" +%sGB",
std::to_string(serverSize / (1024 * 1024 * 1024)).c_str());
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing(); ImGui::Spacing();
if (ImGui::Button("Delete voxel world")) { if (ImGui::Button("Delete voxel world")) {
ImGui::OpenPopup("DELETE_VOXEL_WORLD"); ImGui::OpenPopup("DELETE_VOXEL_WORLD");
} }
// TEMP // TEMP
if (ImGui::Button("Create Ceiling")) { if (ImGui::Button("Create Ceiling")) {
Project::m_scene.getVoxelWorld()->fillVoxels( Project::m_scene.getVoxelWorld().fillVoxels(
VoxelCordinates(), VoxelCordinates( VoxelCordinates(),
32 * worldProps.chunkSizeX - 1, VoxelCordinates(32 * worldProps.chunkSizeX - 1, 16,
16,
32 * worldProps.chunkSizeZ - 1), 32 * worldProps.chunkSizeZ - 1),
Voxel(VoxelData::getVoxelID("wood"))); Voxel(VoxelData::getVoxelID("wood")));
Project::m_scene.getVoxelWorld()->fillVoxels( Project::m_scene.getVoxelWorld().fillVoxels(
VoxelCordinates(1, 8, 1), VoxelCordinates(1, 8, 1),
VoxelCordinates( VoxelCordinates(32 * worldProps.chunkSizeX - 2, 15,
32 * worldProps.chunkSizeX - 2,
15,
32 * worldProps.chunkSizeZ - 2), 32 * worldProps.chunkSizeZ - 2),
Voxel(VoxelData::getVoxelID("air"))); Voxel(VoxelData::getVoxelID("air")));
} }
deleteInputPopup<deleteVoxelWorld>("DELETE_VOXEL_WORLD", "Are you sure you want to delete voxel world?"); deleteInputPopup<deleteVoxelWorld>(
"DELETE_VOXEL_WORLD",
"Are you sure you want to delete voxel world?");
} }
void TerrainEditor::deleteVoxelWorld() { void TerrainEditor::deleteVoxelWorld() {
Project::m_scene.deleteVoxelWorld(); Project::m_scene.deleteVoxelWorld();
} }
} } // namespace Deer

View File

@ -42,7 +42,7 @@ namespace Deer {
glm::vec3 rayDir = farPoint - nearPoint; glm::vec3 rayDir = farPoint - nearPoint;
rayDir = glm::normalize(rayDir); rayDir = glm::normalize(rayDir);
VoxelRayResult res = Project::m_scene.getVoxelWorld()->rayCast_editor( VoxelRayResult res = Project::m_scene.getVoxelWorld().rayCast_editor(
viewport_sceneCamera.transform.position, rayDir, 50); viewport_sceneCamera.transform.position, rayDir, 50);
voxelRayCoords.makeNull(); voxelRayCoords.makeNull();
@ -59,7 +59,7 @@ namespace Deer {
if (viewport_isActive && ImGui::GetMouseClickedCount(0) > 0) { if (viewport_isActive && ImGui::GetMouseClickedCount(0) > 0) {
if (terrainEditMode == TerrainEditMode_Substract) { if (terrainEditMode == TerrainEditMode_Substract) {
if (res.hitPos.y >= 0) { if (res.hitPos.y >= 0) {
Project::m_scene.getVoxelWorld()->setVoxel(res.hitPos, Project::m_scene.getVoxelWorld().setVoxel(res.hitPos,
emptyVoxel); emptyVoxel);
} }
} else if (terrainEditMode == TerrainEditMode_Add) { } else if (terrainEditMode == TerrainEditMode_Add) {
@ -68,7 +68,7 @@ namespace Deer {
res.hitPos.y + NORMAL_DIR(1, res.face), res.hitPos.y + NORMAL_DIR(1, res.face),
res.hitPos.z + NORMAL_DIR(2, res.face)); res.hitPos.z + NORMAL_DIR(2, res.face));
Project::m_scene.getVoxelWorld()->setVoxel( Project::m_scene.getVoxelWorld().setVoxel(
position, Voxel(selectedVoxelID)); position, Voxel(selectedVoxelID));
} }
} }

View File

@ -1,17 +1,15 @@
#include "TreePannel.h" #include "TreePannel.h"
#include "DeerStudio/Project.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "Deer/Enviroment.h"
#include "Deer/Scene.h"
#include "DeerRender/Input.h" #include "DeerRender/Input.h"
#include "DeerRender/KeyCodes.h" #include "DeerRender/KeyCodes.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "Deer/Scene.h" #include "DeerStudio/Project.h"
#include "Deer/Enviroment.h"
#include "imgui.h" #include "imgui.h"
namespace Deer { namespace Deer {
namespace TreePannel {
void updateEntity(Entity& entity); void updateEntity(Entity& entity);
void updateReciveDragPayload(Entity& entity); void updateReciveDragPayload(Entity& entity);
bool updateDragPayload(Entity* entity, const std::string& name); bool updateDragPayload(Entity* entity, const std::string& name);
@ -20,24 +18,28 @@ namespace Deer {
bool m_isRightClickHandled; bool m_isRightClickHandled;
Entity* m_contextMenuEntity = nullptr; Entity* m_contextMenuEntity = nullptr;
} // namespace TreePannel
void treePannel_onImGui() { void TreePannel::treePannel_onImGui() {
ImGui::Begin("Tree Pannel", (bool*)0, ImGuiWindowFlags_MenuBar); ImGui::Begin("Tree Pannel", (bool*)0, ImGuiWindowFlags_MenuBar);
m_isRightClickHandled = false; m_isRightClickHandled = false;
Entity& root = Project::m_scene.getMainEnviroment()->getRoot(); Entity& root = Project::m_scene.getMainEnviroment().getRoot();
if (!m_contextMenuEntity) if (!m_contextMenuEntity) m_contextMenuEntity = &root;
m_contextMenuEntity = &root;
if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("New")) { if (ImGui::BeginMenu("New")) {
if (ImGui::MenuItem("Entity")) { if (ImGui::MenuItem("Entity")) {
Entity& entity = Project::m_scene.getMainEnviroment()->createEntity("new entity"); Entity& entity =
Project::m_scene.getMainEnviroment().createEntity(
"new entity");
entity.setParent(root); entity.setParent(root);
} }
if (ImGui::MenuItem("Camera")) { if (ImGui::MenuItem("Camera")) {
Entity& entity = Project::m_scene.getMainEnviroment()->createEntity("new camera"); Entity& entity =
Project::m_scene.getMainEnviroment().createEntity(
"new camera");
entity.addComponent<CameraComponent>(); entity.addComponent<CameraComponent>();
entity.setParent(root); entity.setParent(root);
} }
@ -47,8 +49,14 @@ namespace Deer {
} }
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
for (auto& entityID : Project::m_scene.getMainEnviroment()->getRoot().getChildren()) { RelationshipComponent& relation =
Entity& childEntity = Project::m_scene.getMainEnviroment()->getEntity(entityID); Project::m_scene.getMainEnviroment()
.getRoot()
.getComponent<RelationshipComponent>();
for (int i = 0; i < relation.childCount; i++) {
Entity& childEntity =
Project::m_scene.getMainEnviroment().getEntity(
relation.getChildrenId(i));
updateEntity(childEntity); updateEntity(childEntity);
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@ -61,10 +69,12 @@ namespace Deer {
ImGui::InvisibleButton("DragDropSpace", spaceSize); ImGui::InvisibleButton("DragDropSpace", spaceSize);
updateReciveDragPayload(root); updateReciveDragPayload(root);
if (!m_isRightClickHandled && ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && if (!m_isRightClickHandled &&
ImGui::IsWindowHovered(
ImGuiHoveredFlags_AllowWhenBlockedByPopup |
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right) && ImGui::IsMouseClicked(ImGuiMouseButton_Right) &&
!ImGui::IsAnyItemHovered()) { !ImGui::IsAnyItemHovered()) {
m_contextMenuEntity = &root; m_contextMenuEntity = &root;
ImGui::OpenPopup("Entity Context Menu"); ImGui::OpenPopup("Entity Context Menu");
} }
@ -73,20 +83,22 @@ namespace Deer {
ImGui::End(); ImGui::End();
} }
void TreePannel::updateEntity(Entity& entity) {
void updateEntity(Entity& entity) {
auto& tag = entity.getComponent<TagComponent>(); auto& tag = entity.getComponent<TagComponent>();
auto& relationship = entity.getComponent<RelationshipComponent>(); auto& relationship = entity.getComponent<RelationshipComponent>();
std::string name = (tag.tag == "") ? "-" : tag.tag; std::string name = (tag.tag == "") ? "-" : tag.tag;
const void* entityID = reinterpret_cast<const void*>(static_cast<uintptr_t>(entity.getUID())); const void* entityID = reinterpret_cast<const void*>(
static_cast<uintptr_t>(entity.getId()));
ImGui::Spacing(); ImGui::Spacing();
//End of the tree // End of the tree
if (relationship.children.size() == 0) { if (relationship.childCount == 0) {
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth; ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf |
ImGuiTreeNodeFlags_NoTreePushOnOpen |
ImGuiTreeNodeFlags_SpanFullWidth;
if (ActiveEntity::contains(entity)) if (ActiveEntity::contains(entity))
flags |= ImGuiTreeNodeFlags_Selected; flags |= ImGuiTreeNodeFlags_Selected;
@ -105,7 +117,9 @@ namespace Deer {
return; return;
} }
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanFullWidth; ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnDoubleClick |
ImGuiTreeNodeFlags_OpenOnArrow |
ImGuiTreeNodeFlags_SpanFullWidth;
if (ActiveEntity::contains(entity)) if (ActiveEntity::contains(entity))
flags |= ImGuiTreeNodeFlags_Selected; flags |= ImGuiTreeNodeFlags_Selected;
@ -113,8 +127,7 @@ namespace Deer {
flags |= ImGuiTreeNodeFlags_DefaultOpen; flags |= ImGuiTreeNodeFlags_DefaultOpen;
if (ImGui::TreeNodeEx(entityID, flags, "%s", name.c_str())) { if (ImGui::TreeNodeEx(entityID, flags, "%s", name.c_str())) {
if (!entity.isRoot()) if (!entity.isRoot()) updateDragPayload(&entity, tag.tag);
updateDragPayload(&entity, tag.tag);
updateReciveDragPayload(entity); updateReciveDragPayload(entity);
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
@ -125,17 +138,17 @@ namespace Deer {
clickEntity(entity); clickEntity(entity);
for (auto& entityID : entity.getChildren()) { RelationshipComponent& rc =
updateReciveDragPayload(entity); entity.getComponent<RelationshipComponent>();
for (int i = 0; i < rc.childCount; i++) {
Entity& childEntity = Project::m_scene.getMainEnviroment()->getEntity(entityID); uint16_t childID = rc.getChildrenId(i);
Entity& childEntity =
m_contextMenuEntity->getEnvironment()->getEntity(childID);
updateEntity(childEntity); updateEntity(childEntity);
} }
updateContextMenu(); updateContextMenu();
ImGui::TreePop(); ImGui::TreePop();
} } else {
else {
clickEntity(entity); clickEntity(entity);
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
@ -144,19 +157,18 @@ namespace Deer {
ImGui::OpenPopup("Entity Context Menu"); ImGui::OpenPopup("Entity Context Menu");
} }
if (!entity.isRoot()) if (!entity.isRoot()) updateDragPayload(&entity, tag.tag);
updateDragPayload(&entity, tag.tag);
updateReciveDragPayload(entity); updateReciveDragPayload(entity);
} }
} }
void updateReciveDragPayload(Entity& entity) { void TreePannel::updateReciveDragPayload(Entity& entity) {
if (ImGui::BeginDragDropTarget()) { if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_ENTITY")) { if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload("_ENTITY")) {
Entity* receivedData = *(Entity**)payload->Data; Entity* receivedData = *(Entity**)payload->Data;
if (!entity.isDescendant(*receivedData)) if (!entity.isDescendantOf(*receivedData))
receivedData->setParent(entity); receivedData->setParent(entity);
} }
@ -164,9 +176,9 @@ namespace Deer {
} }
} }
bool updateDragPayload(Entity* entity, const std::string& name) { bool TreePannel::updateDragPayload(Entity* entity,
if (!ImGui::BeginDragDropSource()) const std::string& name) {
return false; if (!ImGui::BeginDragDropSource()) return false;
ImGui::SetDragDropPayload("_ENTITY", &entity, sizeof(Entity*)); ImGui::SetDragDropPayload("_ENTITY", &entity, sizeof(Entity*));
@ -175,9 +187,10 @@ namespace Deer {
return true; return true;
} }
void clickEntity(Entity& entity) { void TreePannel::clickEntity(Entity& entity) {
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) { if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
if (!(Input::isKeyPressed(DEER_KEY_LEFT_CONTROL) || Input::isKeyPressed(DEER_KEY_LEFT_ALT))) if (!(Input::isKeyPressed(DEER_KEY_LEFT_CONTROL) ||
Input::isKeyPressed(DEER_KEY_LEFT_ALT)))
ActiveEntity::clear(); ActiveEntity::clear();
if (Input::isKeyPressed(DEER_KEY_LEFT_ALT)) if (Input::isKeyPressed(DEER_KEY_LEFT_ALT))
@ -187,19 +200,22 @@ namespace Deer {
} }
} }
void updateContextMenu() { void TreePannel::updateContextMenu() {
bool callRename = false; bool callRename = false;
if (ImGui::BeginPopup("Entity Context Menu")) { if (ImGui::BeginPopup("Entity Context Menu")) {
if (ImGui::MenuItem("New Entity")) { if (ImGui::MenuItem("New Entity")) {
Entity& entity = Project::m_scene.getMainEnviroment()->createEntity("new entity"); Entity& entity =
Project::m_scene.getMainEnviroment().createEntity(
"new entity");
entity.setParent(*m_contextMenuEntity); entity.setParent(*m_contextMenuEntity);
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
if (ImGui::MenuItem("New Camera")) { if (ImGui::MenuItem("New Camera")) {
Entity& entity = Project::m_scene.getMainEnviroment()->createEntity("new camera"); Entity& entity =
Project::m_scene.getMainEnviroment().createEntity(
"new camera");
entity.addComponent<CameraComponent>(); entity.addComponent<CameraComponent>();
entity.setParent(*m_contextMenuEntity); entity.setParent(*m_contextMenuEntity);
@ -214,29 +230,31 @@ namespace Deer {
callRename = true; callRename = true;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
if (!m_contextMenuEntity->isRoot() && ImGui::MenuItem("Duplicate")) { if (!m_contextMenuEntity->isRoot() &&
ImGui::MenuItem("Duplicate")) {
m_contextMenuEntity->duplicate(); m_contextMenuEntity->duplicate();
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (callRename) if (callRename) ImGui::OpenPopup("Rename Entity Menu");
ImGui::OpenPopup("Rename Entity Menu");
if (ImGui::BeginPopup("Rename Entity Menu")) { if (ImGui::BeginPopup("Rename Entity Menu")) {
std::string& name =
std::string& name = m_contextMenuEntity->getComponent<TagComponent>().tag; m_contextMenuEntity->getComponent<TagComponent>().tag;
char nameBuffer[256]; char nameBuffer[256];
std::strncpy(nameBuffer, name.c_str(), sizeof(nameBuffer) - 1); std::strncpy(nameBuffer, name.c_str(), sizeof(nameBuffer) - 1);
ImGui::Text("Rename"); ImGui::Text("Rename");
if (ImGui::InputText("##", nameBuffer, 256, ImGuiInputTextFlags_EnterReturnsTrue)) { if (ImGui::InputText("##", nameBuffer, 256,
m_contextMenuEntity->getComponent<TagComponent>().tag = nameBuffer; ImGuiInputTextFlags_EnterReturnsTrue)) {
m_contextMenuEntity->getComponent<TagComponent>().tag =
nameBuffer;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }
} } // namespace Deer

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
namespace Deer { namespace Deer {
namespace TreePannel {
void treePannel_onImGui(); void treePannel_onImGui();
}
} }

View File

@ -1,27 +1,24 @@
#include "Viewport.h" #include "Viewport.h"
#include <string>
#include "Deer/Enviroment.h"
#include "Deer/Scene.h"
#include "DeerRender/Events/KeyEvent.h"
#include "DeerRender/Events/MouseEvent.h"
#include "DeerRender/GizmoRenderer.h"
#include "DeerRender/Input.h"
#include "DeerRender/Render/FrameBuffer.h"
#include "DeerStudio/Editor/ActiveEntity.h" #include "DeerStudio/Editor/ActiveEntity.h"
#include "DeerStudio/Project.h" #include "DeerStudio/Project.h"
#include "glm/glm.hpp"
#include "DeerRender/Render/FrameBuffer.h"
#include "DeerRender/GizmoRenderer.h"
#include "DeerRender/Events/MouseEvent.h"
#include "DeerRender/Events/KeyEvent.h"
#include "DeerRender/Input.h"
#include "Deer/Scene.h"
#include "Deer/Enviroment.h"
#include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp" #include "glm/gtc/type_ptr.hpp"
#include "glm/gtx/matrix_decompose.hpp" #include "glm/gtx/matrix_decompose.hpp"
#include "imgui.h" #include "imgui.h"
// In this order
#include "ImGuizmo.h" #include "ImGuizmo.h"
#include "glm/glm.hpp"
#include <string>
namespace Deer { namespace Deer {
Ref<FrameBuffer> m_frameBuffer; Ref<FrameBuffer> m_frameBuffer;
@ -30,18 +27,15 @@ namespace Deer {
float viewport_relativeXMouse, viewport_relativeYMouse; float viewport_relativeXMouse, viewport_relativeYMouse;
bool viewport_isActive; bool viewport_isActive;
SceneCamera viewport_sceneCamera(TransformComponent(glm::vec3(16, 16, -16)), CameraComponent()); SceneCamera viewport_sceneCamera(TransformComponent(glm::vec3(16, 16, -16)),
CameraComponent());
bool m_lastMousePressedButton1; bool m_lastMousePressedButton1;
bool m_handleClick; bool m_handleClick;
float m_sensitivity = 0.005f; float m_sensitivity = 0.005f;
enum class TransformMode { enum class TransformMode { Translate = 0, Rotate = 1, Scale = 2 };
Translate = 0,
Rotate = 1,
Scale = 2
};
TransformMode m_transformMode = TransformMode::Translate; TransformMode m_transformMode = TransformMode::Translate;
@ -54,7 +48,10 @@ namespace Deer {
processMovment(); processMovment();
if (!m_frameBuffer) { if (!m_frameBuffer) {
m_frameBuffer = FrameBuffer::create(FrameBufferSpecification(100, 100, { TextureBufferType::RGBA8, TextureBufferType::RED_INTEGER }, 4, false)); m_frameBuffer = FrameBuffer::create(FrameBufferSpecification(
100, 100,
{TextureBufferType::RGBA8, TextureBufferType::RED_INTEGER}, 4,
false));
} }
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
@ -64,8 +61,10 @@ namespace Deer {
ImVec2 wPos = ImGui::GetWindowPos(); ImVec2 wPos = ImGui::GetWindowPos();
wPos.y += contentRegionMin.y; wPos.y += contentRegionMin.y;
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) if (ImGui::IsWindowHovered(
&& ImGui::IsMouseClicked(ImGuiMouseButton_Right)) { ImGuiHoveredFlags_AllowWhenBlockedByPopup |
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::SetWindowFocus(); ImGui::SetWindowFocus();
} }
@ -73,16 +72,17 @@ namespace Deer {
ImVec2 windowSize = ImGui::GetContentRegionAvail(); ImVec2 windowSize = ImGui::GetContentRegionAvail();
if (m_lastWindowSize != *(glm::vec2*)&windowSize) { if (m_lastWindowSize != *(glm::vec2*)&windowSize) {
m_lastWindowSize = { windowSize.x, windowSize.y }; m_lastWindowSize = {windowSize.x, windowSize.y};
m_frameBuffer->resize(windowSize.x, windowSize.y); m_frameBuffer->resize(windowSize.x, windowSize.y);
viewport_sceneCamera.camera.aspect = (float)windowSize.x / (float)windowSize.y; viewport_sceneCamera.camera.aspect =
(float)windowSize.x / (float)windowSize.y;
} }
m_frameBuffer->bind(); m_frameBuffer->bind();
m_frameBuffer->clear(); m_frameBuffer->clear();
int clearData = -1; int clearData = -1;
m_frameBuffer->clearBuffer(1, &clearData); m_frameBuffer->clearBuffer(1, &clearData);
unsigned char clearColor[4]{ 15, 10, 10, 255 }; unsigned char clearColor[4]{15, 10, 10, 255};
m_frameBuffer->clearBuffer(0, &clearColor); m_frameBuffer->clearBuffer(0, &clearColor);
ImVec2 mPos = ImGui::GetMousePos(); ImVec2 mPos = ImGui::GetMousePos();
@ -92,8 +92,10 @@ namespace Deer {
Project::m_scene.render(viewport_sceneCamera); Project::m_scene.render(viewport_sceneCamera);
ImGui::Image((void*)(uint64_t)m_frameBuffer->getTextureBufferID(0), windowSize, ImVec2(0, 1), ImVec2(1, 0)); ImGui::Image((void*)(uint64_t)m_frameBuffer->getTextureBufferID(0),
bool isUsingDrawGizmo = drawGizmos(wPos.x, wPos.y, windowSize.x, windowSize.y); windowSize, ImVec2(0, 1), ImVec2(1, 0));
bool isUsingDrawGizmo =
drawGizmos(wPos.x, wPos.y, windowSize.x, windowSize.y);
if (!isUsingDrawGizmo && m_handleClick) { if (!isUsingDrawGizmo && m_handleClick) {
int relativeX, relativeY; int relativeX, relativeY;
@ -102,16 +104,19 @@ namespace Deer {
relativeX = mPos.x - wPos.x; relativeX = mPos.x - wPos.x;
relativeY = windowSize.y - (mPos.y - wPos.y); relativeY = windowSize.y - (mPos.y - wPos.y);
if (relativeX >= 0 && relativeX < windowSize.x && if (relativeX >= 0 && relativeX < windowSize.x && relativeY >= 0 &&
relativeY >= 0 && relativeY < windowSize.y) { relativeY < windowSize.y) {
int id = m_frameBuffer->getTextureBufferPixel(1, relativeX,
relativeY);
int id = m_frameBuffer->getTextureBufferPixel(1, relativeX, relativeY); if (!(Input::isKeyPressed(DEER_KEY_LEFT_CONTROL) ||
Input::isKeyPressed(DEER_KEY_LEFT_ALT)))
if (!(Input::isKeyPressed(DEER_KEY_LEFT_CONTROL) || Input::isKeyPressed(DEER_KEY_LEFT_ALT)))
ActiveEntity::clear(); ActiveEntity::clear();
if (id >= 0) { if (id >= 0) {
Entity& selectedEntity = Project::m_scene.getMainEnviroment()->getEntity((uint32_t)id); Entity& selectedEntity =
Project::m_scene.getMainEnviroment().getEntity(
(uint32_t)id);
ActiveEntity::addEntity(selectedEntity); ActiveEntity::addEntity(selectedEntity);
} }
} }
@ -125,32 +130,35 @@ namespace Deer {
} }
void processMovment() { void processMovment() {
if (!viewport_isActive) if (!viewport_isActive) return;
return;
if (!Input::isKeyPressed(DEER_KEY_LEFT_CONTROL)) { if (!Input::isKeyPressed(DEER_KEY_LEFT_CONTROL)) {
float vel = 1.5f; float vel = 1.5f;
if (Input::isKeyPressed(DEER_KEY_LEFT_SHIFT)) if (Input::isKeyPressed(DEER_KEY_LEFT_SHIFT)) vel = 8;
vel = 8; if (Input::isKeyPressed(DEER_KEY_LEFT_ALT)) vel = 1.0f;
if (Input::isKeyPressed(DEER_KEY_LEFT_ALT))
vel = 1.0f;
if (Input::isKeyPressed(DEER_KEY_W)) if (Input::isKeyPressed(DEER_KEY_W))
viewport_sceneCamera.transform.position += viewport_sceneCamera.transform.rotation * glm::vec3(0, 0, 1) * 0.02f * vel; viewport_sceneCamera.transform.position +=
viewport_sceneCamera.transform.rotation *
glm::vec3(0, 0, 1) * 0.02f * vel;
if (Input::isKeyPressed(DEER_KEY_S)) if (Input::isKeyPressed(DEER_KEY_S))
viewport_sceneCamera.transform.position += viewport_sceneCamera.transform.rotation * glm::vec3(0, 0, -1) * 0.02f * vel; viewport_sceneCamera.transform.position +=
viewport_sceneCamera.transform.rotation *
glm::vec3(0, 0, -1) * 0.02f * vel;
if (Input::isKeyPressed(DEER_KEY_D)) if (Input::isKeyPressed(DEER_KEY_D))
viewport_sceneCamera.transform.position += viewport_sceneCamera.transform.rotation * glm::vec3(1, 0, 0) * 0.02f * vel; viewport_sceneCamera.transform.position +=
viewport_sceneCamera.transform.rotation *
glm::vec3(1, 0, 0) * 0.02f * vel;
if (Input::isKeyPressed(DEER_KEY_A)) if (Input::isKeyPressed(DEER_KEY_A))
viewport_sceneCamera.transform.position += viewport_sceneCamera.transform.rotation * glm::vec3(-1, 0, 0) * 0.02f * vel; viewport_sceneCamera.transform.position +=
viewport_sceneCamera.transform.rotation *
glm::vec3(-1, 0, 0) * 0.02f * vel;
if (Input::isKeyPressed(DEER_KEY_SPACE)) if (Input::isKeyPressed(DEER_KEY_SPACE))
viewport_sceneCamera.transform.position.y += 0.02f; viewport_sceneCamera.transform.position.y += 0.02f;
} }
if (Input::isMouseButtonPressed(DEER_MOUSE_BUTTON_2)) { if (Input::isMouseButtonPressed(DEER_MOUSE_BUTTON_2)) {
@ -161,16 +169,19 @@ namespace Deer {
if (m_lastMousePressedButton1) { if (m_lastMousePressedButton1) {
glm::vec2 mouseDiff = newMousePos - m_lastMousePos; glm::vec2 mouseDiff = newMousePos - m_lastMousePos;
glm::quat pitchQuat = glm::angleAxis(mouseDiff.y * m_sensitivity, glm::vec3(1, 0, 0)); glm::quat pitchQuat = glm::angleAxis(
glm::quat yawQuat = glm::angleAxis(mouseDiff.x * m_sensitivity, glm::vec3(0, 1, 0)); mouseDiff.y * m_sensitivity, glm::vec3(1, 0, 0));
glm::quat yawQuat = glm::angleAxis(mouseDiff.x * m_sensitivity,
glm::vec3(0, 1, 0));
viewport_sceneCamera.transform.rotation = yawQuat * viewport_sceneCamera.transform.rotation * pitchQuat; viewport_sceneCamera.transform.rotation =
yawQuat * viewport_sceneCamera.transform.rotation *
pitchQuat;
} }
m_lastMousePos = newMousePos; m_lastMousePos = newMousePos;
m_lastMousePressedButton1 = true; m_lastMousePressedButton1 = true;
} } else
else
m_lastMousePressedButton1 = false; m_lastMousePressedButton1 = false;
} }
@ -178,30 +189,38 @@ namespace Deer {
ImGuizmo::SetOrthographic(false); ImGuizmo::SetOrthographic(false);
ImGuizmo::SetDrawlist(); ImGuizmo::SetDrawlist();
glm::mat4 camMatrix = glm::inverse(viewport_sceneCamera.transform.getMatrix()); glm::mat4 camMatrix =
glm::mat4 projectionMatrix = viewport_sceneCamera.camera.getMatrix() * glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1)); glm::inverse(viewport_sceneCamera.transform.getMatrix());
glm::mat4 projectionMatrix =
viewport_sceneCamera.camera.getMatrix() *
glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, -1));
ImGuizmo::SetRect(wPosX, wPosY, wSizeX, wSizeY); ImGuizmo::SetRect(wPosX, wPosY, wSizeX, wSizeY);
if (ActiveEntity::count() != 0) { if (ActiveEntity::count() != 0) {
Entity& currentEntity = ActiveEntity::getEntity(0); Entity& currentEntity = ActiveEntity::getEntity(0);
glm::mat4 entity_matrix = currentEntity.getWorldMatrix(); glm::mat4 entity_matrix = currentEntity.getWorldMatrix();
ImGuizmo::OPERATION operations; ImGuizmo::OPERATION operations;
ImGuizmo::Manipulate(glm::value_ptr(camMatrix), glm::value_ptr(projectionMatrix), (ImGuizmo::OPERATION)m_transformMode, ImGuizmo::Manipulate(
ImGuizmo::MODE::LOCAL, glm::value_ptr(entity_matrix)); glm::value_ptr(camMatrix), glm::value_ptr(projectionMatrix),
(ImGuizmo::OPERATION)m_transformMode, ImGuizmo::MODE::LOCAL,
glm::value_ptr(entity_matrix));
if (ImGuizmo::IsUsing()) { if (ImGuizmo::IsUsing()) {
glm::mat4 parentMatrix = currentEntity.getParent().getWorldMatrix(); glm::mat4 parentMatrix =
glm::mat4 relativeMatrix = glm::inverse(parentMatrix) * entity_matrix; currentEntity.getParent().getWorldMatrix();
glm::mat4 relativeMatrix =
glm::inverse(parentMatrix) * entity_matrix;
glm::vec3 skew; glm::vec3 skew;
glm::vec4 perspective; glm::vec4 perspective;
TransformComponent& t = currentEntity.getComponent<TransformComponent>(); TransformComponent& t =
glm::decompose(relativeMatrix, t.scale, t.rotation, t.position, skew, perspective); currentEntity.getComponent<TransformComponent>();
glm::decompose(relativeMatrix, t.scale, t.rotation, t.position,
skew, perspective);
return true; return true;
} }
@ -213,12 +232,12 @@ namespace Deer {
void viewport_onEvent(Event& e) { void viewport_onEvent(Event& e) {
EventDispatcher dispatcher(e); EventDispatcher dispatcher(e);
dispatcher.dispatch<MouseButtonPressedEvent>(Deer::viewport_onClickEvent); dispatcher.dispatch<MouseButtonPressedEvent>(
Deer::viewport_onClickEvent);
dispatcher.dispatch<KeyPressedEvent>(Deer::viewport_onKeyEvent); dispatcher.dispatch<KeyPressedEvent>(Deer::viewport_onKeyEvent);
} }
bool viewport_onClickEvent(MouseButtonPressedEvent mouseEvent) { bool viewport_onClickEvent(MouseButtonPressedEvent mouseEvent) {
if (!viewport_isActive) if (!viewport_isActive) return false;
return false;
if (mouseEvent.getMouseButton() == DEER_MOUSE_BUTTON_1) if (mouseEvent.getMouseButton() == DEER_MOUSE_BUTTON_1)
m_handleClick = true; m_handleClick = true;
@ -226,8 +245,7 @@ namespace Deer {
return false; return false;
} }
bool viewport_onKeyEvent(KeyPressedEvent keyEvent) { bool viewport_onKeyEvent(KeyPressedEvent keyEvent) {
if (!viewport_isActive) if (!viewport_isActive) return false;
return false;
if (Input::isKeyPressed(DEER_KEY_T)) if (Input::isKeyPressed(DEER_KEY_T))
m_transformMode = TransformMode::Translate; m_transformMode = TransformMode::Translate;
@ -236,11 +254,12 @@ namespace Deer {
if (Input::isKeyPressed(DEER_KEY_G)) if (Input::isKeyPressed(DEER_KEY_G))
m_transformMode = TransformMode::Scale; m_transformMode = TransformMode::Scale;
if (Input::isKeyPressed(DEER_KEY_D) && Input::isKeyPressed(DEER_KEY_LEFT_CONTROL)) { if (Input::isKeyPressed(DEER_KEY_D) &&
Input::isKeyPressed(DEER_KEY_LEFT_CONTROL)) {
if (ActiveEntity::count() > 0) if (ActiveEntity::count() > 0)
ActiveEntity::getEntity(0).duplicate(); ActiveEntity::getEntity(0).duplicate();
} }
return false; return false;
} }
} } // namespace Deer

View File

@ -9,19 +9,20 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Properties] [Window][Properties]
Pos=724,240 Pos=2152,24
Size=569,648 Size=408,1347
Collapsed=0 Collapsed=0
DockId=0x00000004,1
[Window][Game Window] [Window][Game Window]
Pos=0,24 Pos=526,24
Size=2150,1347 Size=1624,1347
Collapsed=0 Collapsed=0
DockId=0x00000006,1 DockId=0x00000006,1
[Window][Tree Pannel] [Window][Tree Pannel]
Pos=0,24 Pos=0,24
Size=323,903 Size=524,1347
Collapsed=0 Collapsed=0
DockId=0x00000005,0 DockId=0x00000005,0
@ -32,8 +33,8 @@ Collapsed=0
DockId=0x00000004,0 DockId=0x00000004,0
[Window][Viewport] [Window][Viewport]
Pos=0,24 Pos=526,24
Size=2150,1347 Size=1624,1347
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
@ -47,8 +48,8 @@ DockId=0x00000002,0
DockSpace ID=0xA1672E74 Window=0x4647B76E Pos=0,24 Size=2560,1347 Split=Y DockSpace ID=0xA1672E74 Window=0x4647B76E Pos=0,24 Size=2560,1347 Split=Y
DockNode ID=0x00000001 Parent=0xA1672E74 SizeRef=2560,903 Split=X Selected=0x13926F0B DockNode ID=0x00000001 Parent=0xA1672E74 SizeRef=2560,903 Split=X Selected=0x13926F0B
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=2150,779 Split=X Selected=0x13926F0B DockNode ID=0x00000003 Parent=0x00000001 SizeRef=2150,779 Split=X Selected=0x13926F0B
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=323,779 Selected=0xBD1B42A3 DockNode ID=0x00000005 Parent=0x00000003 SizeRef=524,779 Selected=0xBD1B42A3
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=1599,779 CentralNode=1 Selected=0x13926F0B DockNode ID=0x00000006 Parent=0x00000003 SizeRef=1624,779 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=408,779 Selected=0x2A2C795E DockNode ID=0x00000004 Parent=0x00000001 SizeRef=408,779 Selected=0x2A2C795E
DockNode ID=0x00000002 Parent=0xA1672E74 SizeRef=2560,442 Selected=0xCF339702 DockNode ID=0x00000002 Parent=0xA1672E74 SizeRef=2560,442 Selected=0xCF339702