Basic parent/child relation working with entities

master
Joey Pollack 3 years ago
parent 48594adb03
commit d893849dc3

@ -34,6 +34,10 @@ Core:
✔ Read the window size and position on shutdown and write these to the state file @done (2/8/2022, 4:39:37 PM) ✔ Read the window size and position on shutdown and write these to the state file @done (2/8/2022, 4:39:37 PM)
Graphics: Graphics:
☐ Implement parent transform for all draw methods
☐ Ellipse
☐ Lines
☐ Text
Re-write the renderer: Re-write the renderer:
✔ Implement BeginScene and EndScene - these are called from the World OnRender @done(22-09-07 14:47) ✔ Implement BeginScene and EndScene - these are called from the World OnRender @done(22-09-07 14:47)

@ -131,7 +131,7 @@ namespace lunarium
float parent_idx = -1.0f; float parent_idx = -1.0f;
if (parent_transform != glm::mat4(1.0f)) if (parent_transform != glm::mat4(1.0f))
{ {
if (mQuadData.Parents.size() > 15) if (mQuadData.Parents.size() >= mQuadData.ParentSlots)
Flush(FlushMode::Quads); Flush(FlushMode::Quads);
mQuadData.Parents.push_back(parent_transform); mQuadData.Parents.push_back(parent_transform);

@ -115,6 +115,7 @@ namespace lunarium
const int MaxVertices = MaxQuads * 4; const int MaxVertices = MaxQuads * 4;
const int MaxIndices = MaxQuads * 6; const int MaxIndices = MaxQuads * 6;
const int TextureSlots = 32; const int TextureSlots = 32;
const int ParentSlots = 32;
std::vector<Texture*> LoadedTextures; std::vector<Texture*> LoadedTextures;
Texture* WhiteTexture; Texture* WhiteTexture;

@ -16,7 +16,7 @@ layout (location = 2) flat out int f_tex_index;
layout (location = 3) flat out int f_tex_is_grey; layout (location = 3) flat out int f_tex_is_grey;
uniform mat4 projview; uniform mat4 projview;
uniform mat4 parents[16]; uniform mat4 parents[32];
void main() void main()
{ {

@ -151,6 +151,18 @@ namespace lunarium { namespace editor
void PropertiesView::ShowEntity() void PropertiesView::ShowEntity()
{ {
ImGui::Text("UUID: %ull", (u64)mpSelectedEntity->GetUUID());
char buffer[256] = { 0 };
strcpy(buffer, mpSelectedEntity->GetName().c_str());
ImGui::Text("Name:");
ImGui::SameLine();
if (ImGui::InputText("##Entity Name", buffer, 256))
{
mpSelectedEntity->SetName(buffer);
}
ImGui::Separator();
ImGuiExt::TextCentered("Components"); ImGuiExt::TextCentered("Components");
float spacing_y = 12.0f; float spacing_y = 12.0f;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, spacing_y)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, spacing_y));

@ -16,145 +16,154 @@
#include <editor/editor.h> #include <editor/editor.h>
#include <utils/logger.h> #include <utils/logger.h>
namespace lunarium namespace lunarium { namespace editor
{ {
namespace editor WorldTree::WorldTree(Editor *editor)
: Panel("World Tree", PanelDockZone::DDZ_LEFT, true, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar),
mpEditor(editor),
// TODO: Temp world created here
mpWorld(nullptr),
mpSelectedEntity(nullptr), mNewChild(false), mParentEnt(nullptr)
{ {
WorldTree::WorldTree(Editor *editor) AddPopup(PopUp::NEW_ENTITY, "New Entity", [](Panel *p)
: Panel("World Tree", PanelDockZone::DDZ_LEFT, true, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar), {
mpEditor(editor), WorldTree* pWT = (WorldTree*)p;
// TODO: Temp world created here if (!pWT->mpWorld)
mpWorld(nullptr),
mpSelectedEntity(nullptr)
{
AddPopup(PopUp::NEW_ENTITY, "New Entity", [](Panel *p)
{ {
WorldTree* pWT = (WorldTree*)p; return false;
if (!pWT->mpWorld) }
{
return false; char name_buf[64] = "NewEntity";
} ImGui::TextUnformatted("Entity Name: ");
ImGui::SameLine();
if (ImGui::InputText("##Entity Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue))
{
LUUID id = pWT->mpWorld->CreateEntity();
pWT->mpWorld->GetEntity(id)->SetName(name_buf);
char name_buf[64] = "NewEntity"; if (pWT->mNewChild)
ImGui::TextUnformatted("Entity Name: ");
ImGui::SameLine();
if (ImGui::InputText("##Entity Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue))
{ {
LUUID id = pWT->mpWorld->CreateEntity(); pWT->mParentEnt->AddChild(id);
pWT->mpWorld->GetEntity(id)->AddComponent<TagComponent>();
TagComponent& tc = pWT->mpWorld->GetEntity(id)->GetComponent<TagComponent>();
tc.Info = name_buf;
return false;
} }
if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) pWT->mNewChild = false;
{ pWT->mParentEnt = nullptr;
return false; return false;
} }
return true; if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true))
}).LogIfFailed(Editor::LogCat); {
} pWT->mNewChild = false;
return false;
}
void WorldTree::SetWorld(lunarium::World *pWorld) return true;
{ }).LogIfFailed(Editor::LogCat);
mpWorld = pWorld; }
mpSelectedEntity = nullptr;
}
lunarium::World *WorldTree::GetWorld() void WorldTree::SetWorld(lunarium::World *pWorld)
{
mpWorld = pWorld;
mpSelectedEntity = nullptr;
}
lunarium::World *WorldTree::GetWorld()
{
return mpWorld;
}
void WorldTree::DoFrame()
{
Entity *pSelection = nullptr;
if (!mpWorld)
{ {
return mpWorld;
ImGui::Text("No World Loaded");
return;
} }
void WorldTree::DoFrame() ImGui::SetNextItemOpen(true);
if (ImGui::TreeNode("World Root"))
{ {
Entity *pSelection = nullptr; // List all world entities
if (!mpWorld) // This will fail if we end up implementing child entities
// In that case this needs to become recursive
int idx = 0;
for (auto iter = mpWorld->EntitiesBegin(); !mpWorld->EntitiesIsEnd(iter); iter++, idx++)
{ {
if (!(*iter)->HasComponent<ParentEntityComponent>())
ImGui::Text("No World Loaded"); {
return; ShowEntity((*iter));
}
} }
ImGui::SetNextItemOpen(true); ImGui::TreePop();
}
if (ImGui::TreeNode("World Root"))
{
// List all world entities
// This will fail if we end up implementing child entities
// In that case this needs to become recursive
int idx = 0;
for (auto iter = mpWorld->EntitiesBegin(); !mpWorld->EntitiesIsEnd(iter); iter++, idx++)
{
std::string name = "Entity";
name += std::to_string(idx);
if ((*iter)->HasComponent<TagComponent>())
{
name = (*iter)->GetComponent<TagComponent>().Info;
}
if ((*iter)->HasChildren()) if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered())
{ {
// TODO: Recurse through children mpSelectedEntity = nullptr;
if (ImGui::TreeNode(name.c_str())) mpEditor->OnEntitySelect(nullptr);
{ }
ImGui::TreePop();
}
}
else
{
bool is_selected = false;
if ((*iter) == mpSelectedEntity)
{
is_selected = true;
}
if (ImGui::Selectable(name.c_str(), &is_selected))
{
mpSelectedEntity = (*iter);
if (is_selected)
{
mpEditor->OnEntitySelect(mpSelectedEntity);
}
else
{
mpEditor->OnEntitySelect(nullptr);
mpSelectedEntity = nullptr;
}
}
}
}
ImGui::TreePop(); DoContextMenu();
} }
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered())
void WorldTree::ShowEntity(Entity* pEnt)
{
bool was_clicked = false;
bool was_right_clicked = false;
if (ImGui::TreeNode(pEnt->GetName().c_str()))
{
was_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
was_right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
const std::vector<LUUID>& children = pEnt->GetChildren();
for (auto iter = children.begin(); iter != children.end(); iter++)
{ {
mpSelectedEntity = nullptr; Entity* pe = mpWorld->GetEntity((*iter));
mpEditor->OnEntitySelect(nullptr); ShowEntity(pe);
} }
DoContextMenu(); ImGui::TreePop();
}
else
{
was_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
was_right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
} }
void WorldTree::DoContextMenu() if (was_clicked)
{
mpSelectedEntity = pEnt;
mpEditor->OnEntitySelect(pEnt);
}
if (was_right_clicked)
{ {
if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight)) mNewChild = true;
mParentEnt = pEnt;
}
}
void WorldTree::DoContextMenu()
{
if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight))
{
if (ImGui::Button("Create New Entity"))
{ {
if (ImGui::Button("Create New Entity")) if (!mpWorld)
{ {
if (!mpWorld) Logger::Warn(Editor::LogCat, "Can not create new entity - World pointer is null");
{ }
Logger::Warn(Editor::LogCat, "Can not create new entity - World pointer is null"); else
} {
else OpenPopup(PopUp::NEW_ENTITY).LogIfFailed(Editor::LogCat);
{
OpenPopup(PopUp::NEW_ENTITY).LogIfFailed(Editor::LogCat);
}
} }
ImGui::EndPopup();
} }
ImGui::EndPopup();
} }
} }
}
}}

@ -35,6 +35,9 @@ namespace editor
Editor* mpEditor; Editor* mpEditor;
Entity* mpSelectedEntity; Entity* mpSelectedEntity;
// Helpers
void ShowEntity(Entity* pEnt);
// Context menus // Context menus
void DoContextMenu(); void DoContextMenu();
@ -47,6 +50,9 @@ namespace editor
{ {
NEW_ENTITY, NEW_ENTITY,
}; };
bool mNewChild;
Entity* mParentEnt;
}; };
} }
} }

@ -81,6 +81,18 @@ namespace lunarium
BlockOutComponent() = default; BlockOutComponent() = default;
BlockOutComponent(const BlockOutComponent&) = default; BlockOutComponent(const BlockOutComponent&) = default;
}; };
/////////////////////////////////////////////////////////////////////
// UTILITY COMPONENTS
/////////////////////////////////////////////////////////////////////
// These components are for internal use only. They do not show up in the editor.
struct ParentEntityComponent
{
LUUID parent;
ParentEntityComponent() = default;
ParentEntityComponent(const ParentEntityComponent&) = default;
};
} }
#endif // LUNARIUM_COMPONENTS_H_ #endif // LUNARIUM_COMPONENTS_H_

@ -14,7 +14,7 @@
namespace lunarium namespace lunarium
{ {
Entity::Entity(World& w) Entity::Entity(World& w)
: mHandle(entt::null), mWorld(w) : mHandle(entt::null), mWorld(w), mParent(0), mParentSet(false)
{ {
mUUID = UUID::GetNewID(); mUUID = UUID::GetNewID();
Init(); Init();
@ -42,6 +42,16 @@ namespace lunarium
return mUUID; return mUUID;
} }
std::string Entity::GetName() const
{
return mName;
}
void Entity::SetName(std::string name)
{
mName = name;
}
bool Entity::HasChildren() const bool Entity::HasChildren() const
{ {
@ -49,9 +59,52 @@ namespace lunarium
} }
void Entity::AddChild(Entity* pChild) void Entity::AddChild(LUUID child)
{
Entity* e = mWorld.GetEntity(child);
e->AddComponent<ParentEntityComponent>(mUUID);
mChildren.push_back(child);
}
void Entity::RemoveChild(LUUID child)
{
Entity* e = mWorld.GetEntity(child);
e->ClearParent();
for (auto iter = mChildren.begin(); iter != mChildren.end(); iter++)
{
if ((*iter) == child)
{
mChildren.erase(iter);
break;
}
}
}
const std::vector<LUUID>& Entity::GetChildren() const
{ {
mChildren.push_back(pChild); return mChildren;
}
bool Entity::HasParent() const
{
return mParentSet;
}
LUUID Entity::GetParent() const
{
return mParent;
}
void Entity::SetParent(LUUID parent)
{
mParent = parent;
}
void Entity::ClearParent()
{
mParentSet = false;
} }
@ -63,6 +116,7 @@ namespace lunarium
#if !BUILD_NO_EDITOR // Only does this when this is an editor build #if !BUILD_NO_EDITOR // Only does this when this is an editor build
node["UUID"] = mUUID; node["UUID"] = mUUID;
node["name"] = mName;
auto& components = node["components"]; auto& components = node["components"];
if (HasComponent<TagComponent>()) if (HasComponent<TagComponent>())
@ -151,6 +205,15 @@ namespace lunarium
components.emplace_back(blockout); components.emplace_back(blockout);
} }
if (HasComponent<ParentEntityComponent>())
{
nlohmann::ordered_json parent;
ParentEntityComponent& comp = GetComponent<ParentEntityComponent>();
parent["type_name"] = "ParentEntityComponent";
parent["UUID"] = (u64)comp.parent;
components.emplace_back(parent);
}
// TODO: ADD CODE TO SERIALIZE ANY NEW COMPONENTS // TODO: ADD CODE TO SERIALIZE ANY NEW COMPONENTS
@ -160,7 +223,7 @@ namespace lunarium
for (int i = 0; i < mChildren.size(); i++) for (int i = 0; i < mChildren.size(); i++)
{ {
nlohmann::ordered_json child; nlohmann::ordered_json child;
mChildren[i]->Serialize(child).LogIfFailed(LogCategory::GAME_SYSTEM); child["UUID"] = mChildren[i];
children.emplace_back(child); children.emplace_back(child);
} }
@ -173,6 +236,7 @@ namespace lunarium
#if !BUILD_NO_EDITOR // Only does this when this is an editor build #if !BUILD_NO_EDITOR // Only does this when this is an editor build
mUUID = node["UUID"].get<u64>(); mUUID = node["UUID"].get<u64>();
mName = node["name"].get<std::string>();
// TODO: Load components // TODO: Load components
auto& components = node["components"]; auto& components = node["components"];
@ -255,6 +319,12 @@ namespace lunarium
AddComponent<BlockOutComponent>(Color, Size); AddComponent<BlockOutComponent>(Color, Size);
} }
if ("ParentEntityComponent" == comp_type_name)
{
LUUID parent = comp["UUID"].get<u64>();
AddComponent<ParentEntityComponent>(parent);
}
// TODO: ADD CODE TO DESERIALIZE ANY NEW COMPONENTS // TODO: ADD CODE TO DESERIALIZE ANY NEW COMPONENTS
} }
@ -266,8 +336,7 @@ namespace lunarium
{ {
auto& child = *iter; auto& child = *iter;
Entity* ne = new Entity(mWorld); LUUID ne = child["UUID"].get<u64>();
ne->Deserialize(child).LogIfFailed(LogCategory::GAME_SYSTEM);
mChildren.push_back(ne); mChildren.push_back(ne);
} }

@ -65,9 +65,18 @@ namespace lunarium // TODO: : public JSONSerializable
} }
LUUID GetUUID() const; LUUID GetUUID() const;
std::string GetName() const;
void SetName(std::string name);
bool HasChildren() const; bool HasChildren() const;
void AddChild(Entity* pChild); void AddChild(LUUID child);
void RemoveChild(LUUID child);
const std::vector<LUUID>& GetChildren() const;
bool HasParent() const;
LUUID GetParent() const;
void SetParent(LUUID parent);
void ClearParent();
// Serializing // Serializing
[[nodiscard]] virtual OpRes Serialize(nlohmann::ordered_json& node); [[nodiscard]] virtual OpRes Serialize(nlohmann::ordered_json& node);
@ -77,9 +86,12 @@ namespace lunarium // TODO: : public JSONSerializable
private: private:
LUUID mUUID; LUUID mUUID;
LUUID mParent;
bool mParentSet;
std::string mName;
entt::entity mHandle; entt::entity mHandle;
World& mWorld; // The world the entity is contained within World& mWorld; // The world the entity is contained within
std::vector<Entity*> mChildren; std::vector<LUUID> mChildren;
private: private:
void Init(); void Init();

@ -65,6 +65,8 @@ namespace lunarium
// case RunMode::EDITOR: RenderEditor(pGraphics); break; // case RunMode::EDITOR: RenderEditor(pGraphics); break;
// } // }
// TODO: Modify to handle parent/child rendering
// Draw the Renderables that also have a transform // Draw the Renderables that also have a transform
// Code from: // Code from:
@ -180,6 +182,7 @@ namespace lunarium
new_ent->Deserialize(ent).LogIfFailed(LogCategory::GAME_SYSTEM); new_ent->Deserialize(ent).LogIfFailed(LogCategory::GAME_SYSTEM);
mEntities.push_back(new_ent); mEntities.push_back(new_ent);
mEntitiesByUUID[new_ent->GetUUID()] = new_ent;
} }
#endif #endif

@ -2,7 +2,7 @@
"State": "State":
{ {
"DataDirectory": "data/", "DataDirectory": "data/",
"Mode": "test", "Mode": "editor",
"Display": "Display":
{ {

Loading…
Cancel
Save