Muto 0.0.1
Cross-Platform Application Template
GitHub Repo | Muto Updates | Muto's Author
Loading...
Searching...
No Matches
Muto::SceneHierarchyPanel Class Reference

#include <SceneHierarchyPanel.h>

Public Member Functions

Entity GetSelectedEntity () const
 
void OnImGuiRender ()
 
 SceneHierarchyPanel ()=default
 
 SceneHierarchyPanel (const Ref< Scene > &context)
 
void SetContext (const Ref< Scene > &context)
 
void SetSelectedEntity (Entity entity)
 

Private Member Functions

template<typename T >
void DisplayAddComponentEntry (const std::string &entryName)
 
void DrawComponents (Entity entity)
 
void DrawEntityNode (Entity entity)
 

Private Attributes

Ref< Scene > m_Context
 
Ref< Framebuffer > m_Framebuffer
 
Entity m_SelectionContext
 

Constructor & Destructor Documentation

◆ SceneHierarchyPanel() [1/2]

Muto::SceneHierarchyPanel::SceneHierarchyPanel ( )
default

◆ SceneHierarchyPanel() [2/2]

Muto::SceneHierarchyPanel::SceneHierarchyPanel ( const Ref< Scene > &  context)
18 {
20 }
void SetContext(const Ref< Scene > &context)
Definition SceneHierarchyPanel.cpp:22
constexpr Scope< T > CreateScope(Args &&... args)
Creates a Scope (unique_ptr) for the given type and constructor arguments.
Definition Defines_Macros.h:51

Member Function Documentation

◆ DisplayAddComponentEntry()

template<typename T >
void Muto::SceneHierarchyPanel::DisplayAddComponentEntry ( const std::string &  entryName)
private
704 {
706 {
707 if (ImGui::MenuItem(entryName.c_str()))
708 {
710 ImGui::CloseCurrentPopup();
711 }
712 }
713 }
bool HasComponent() const
Checks if the entity has a component of type T.
Definition Entity.h:36
T & AddComponent(Args &&... args)
Adds a component of type T to the entity with the provided arguments Otherwise, asserts if the entity...
Definition Entity.h:48
Entity m_SelectionContext
Definition SceneHierarchyPanel.h:31
@ T
Definition KeyCodes.h:60

References m_SelectionContext.

◆ DrawComponents()

void Muto::SceneHierarchyPanel::DrawComponents ( Entity  entity)
private
452 {
453 if (entity.HasComponent<NameComponent>())
454 {
455 auto& name = entity.GetComponent<NameComponent>().Name;
456
457 char buffer[256];
458 memset(buffer, 0, sizeof(buffer));
459 std::strncpy(buffer, name.c_str(), sizeof(buffer) - 1);
460 if (ImGui::InputText("##Name", buffer, sizeof(buffer)))
461 {
462 name = std::string(buffer);
463 }
464 }
465
466 ImGui::SameLine();
467 ImGui::PushItemWidth(-1);
468
469 if (ImGui::Button("Add Component"))
470 ImGui::OpenPopup("AddComponent");
471
472 if (ImGui::BeginPopup("AddComponent"))
473 {
475 //DisplayAddComponentEntry<ScriptComponent>("Script");
480
481 ImGui::EndPopup();
482 }
483
484 ImGui::PopItemWidth();
485
486 DrawComponent<TransformComponent>("Transform", entity, [](Entity ent, auto& component)
487 {
488 DrawVec3Control("Translation", component.Translation);
489 glm::vec3 rotation = glm::degrees(component.Rotation);
490 DrawVec3Control("Rotation", rotation);
491 component.Rotation = glm::radians(rotation);
492 DrawVec3Control("Scale", component.Scale, 1.0f);
493 });
494
495 DrawComponent<CameraComponent>("Camera", entity, [](Entity ent, auto& component)
496 {
497 auto& camera = component.Camera;
498
499 ImGui::Checkbox("Primary", &component.Primary);
500
501 const char* projectionTypeStrings[] = { "Perspective", "Orthographic" };
502 const char* currentProjectionTypeString = projectionTypeStrings[(int)camera.GetProjectionType()];
503 if (ImGui::BeginCombo("Projection", currentProjectionTypeString))
504 {
505 for (int i = 0; i < 2; i++)
506 {
508 if (ImGui::Selectable(projectionTypeStrings[i], isSelected))
509 {
511 camera.SetProjectionType((SceneCamera::ProjectionType)i);
512 }
513
514 if (isSelected)
515 ImGui::SetItemDefaultFocus();
516 }
517
518 ImGui::EndCombo();
519 }
520
521 if (camera.GetProjectionType() == SceneCamera::ProjectionType::Perspective)
522 {
523 float perspectiveVerticalFov = glm::degrees(camera.GetPerspectiveVerticalFOV());
524 if (ImGui::DragFloat("Vertical FOV", &perspectiveVerticalFov))
525 camera.SetPerspectiveVerticalFOV(glm::radians(perspectiveVerticalFov));
526
527 float perspectiveNear = camera.GetPerspectiveNearClip();
528 if (ImGui::DragFloat("Near", &perspectiveNear))
529 camera.SetPerspectiveNearClip(perspectiveNear);
530
531 float perspectiveFar = camera.GetPerspectiveFarClip();
532 if (ImGui::DragFloat("Far", &perspectiveFar))
533 camera.SetPerspectiveFarClip(perspectiveFar);
534 }
535
536 if (camera.GetProjectionType() == SceneCamera::ProjectionType::Orthographic)
537 {
538 float orthoSize = camera.GetOrthographicSize();
539 if (ImGui::DragFloat("Size", &orthoSize))
540 camera.SetOrthographicSize(orthoSize);
541
542 float orthoNear = camera.GetOrthographicNearClip();
543 if (ImGui::DragFloat("Near", &orthoNear))
544 camera.SetOrthographicNearClip(orthoNear);
545
546 float orthoFar = camera.GetOrthographicFarClip();
547 if (ImGui::DragFloat("Far", &orthoFar))
548 camera.SetOrthographicFarClip(orthoFar);
549
550 ImGui::Checkbox("Fixed Aspect Ratio", &component.FixedAspectRatio);
551 }
552 });
553
554 DrawComponent<SpriteRendererComponent>("Sprite Renderer", entity, [](Entity ent, auto& component)
555 {
556 ImGui::ColorEdit4("Color", glm::value_ptr(component.Color));
557
558 // Separate checkbox for enabling/disabling texture usage
559 ImGui::Checkbox("Texture Enabled", &component.TextureEnabled);
560 ImGui::SameLine();
561
562 // Display current texture name (if any) and buttons to Set / Change / Clear the texture
563 if (component.Texture)
564 {
565 ImGui::TextUnformatted(component.Texture->GetName().c_str());
566 ImGui::SameLine();
567 if (ImGui::Button("Change Texture"))
568 {
569 std::string filePath = FileDialogs::OpenFile("Image Files (*.png;*.jpg;*.jpeg;*.bmp;*.tga)\0*.png;*.jpg;*.jpeg;*.bmp;*.tga\0All Files (*.*)\0*.*\0");
570 if (!filePath.empty())
571 {
573 if (tex)
574 {
575 component.Texture = tex;
576 component.TextureEnabled = true;
577 if (ent.HasComponent<SubTextureComponent>()) {
578 auto& stc = ent.GetComponent<SubTextureComponent>();
579 stc.SetTexture(component.Texture);
580
581 if (ent.HasComponent<TextureAnimationComponent>()) {
582 auto& texAnim = ent.GetComponent<TextureAnimationComponent>();
583 // Always replace animation frames with a fresh initial frame based on the new texture
584 texAnim.SubTextures.clear();
585 texAnim.SubTextures.push_back(SubTexture2D::CreateFromCoords(
586 component.Texture, stc.Offset,
587 glm::vec2(static_cast<float>(tex->GetWidth()) * stc.TilingFactor.x,
588 static_cast<float>(tex->GetHeight()) * stc.TilingFactor.y)
589 ));
590 texAnim.CurrentFrame = 0;
591 texAnim.TimeAccumulator = 0.0f;
592 }
593 }
594 }
595 else
596 {
597 MU_WARN("Could not load texture {0}", filePath);
598 }
599 }
600 }
601 ImGui::SameLine();
602 if (ImGui::Button("Clear Texture"))
603 {
604 component.Texture = nullptr;
605 component.TextureEnabled = false;
606 }
607 }
608 else
609 {
610 ImGui::SameLine();
611 if (ImGui::Button("Set Texture"))
612 {
613 std::string filePath = FileDialogs::OpenFile("Image Files (*.png;*.jpg;*.jpeg;*.bmp;*.tga)\0*.png;*.jpg;*.jpeg;*.bmp;*.tga\0All Files (*.*)\0*.*\0");
614 if (!filePath.empty())
615 {
617 if (tex)
618 {
619 component.Texture = tex;
620 component.TextureEnabled = true;
621 }
622 else
623 {
624 MU_WARN("Could not load texture {0}", filePath);
625 }
626 }
627 }
628 }
629
630 ImGui::DragFloat("Tiling Factor", &component.TilingFactor, 0.1f, 0.0f, 100.0f);
631
632 });
633
634 DrawComponent<SubTextureComponent>("SubTexture", entity, [](Entity ent, auto& component)
635 {
636 std::string name = (component.SubTexture && component.SubTexture->GetTexture()) ? component.SubTexture->GetTexture()->GetName() : std::string();
638 });
639
640 DrawComponent<TextureAnimationComponent>("Texture Animation", entity, [](Entity ent, auto& component)
641 {
642 ImGui::DragFloat("Frame Time", &component.FrameTime, 0.01f, 0.01f, 10.0f);
643 if (component.SubTextures.size() > 0) {
644 // Clamp current frame to valid range
645 if (component.CurrentFrame < 0) component.CurrentFrame = 0;
646 if (component.CurrentFrame >= (int)component.SubTextures.size()) component.CurrentFrame = (int)component.SubTextures.size() - 1;
647 ImGui::SliderInt("Frame Count", &component.CurrentFrame, 0, component.SubTextures.size() - 1);
648 }
649 else
650 ImGui::Text("No frames in animation.");
651
652 ImGui::Checkbox("Play Animation", &component.IsLooping);
653 auto& stc = ent.GetOrAddComponent<SubTextureComponent>();
654
655 std::string texName = (stc.SubTexture && stc.SubTexture->GetTexture()) ? stc.SubTexture->GetTexture()->GetName() : std::string();
657 });
658
659 DrawComponent<ParticleSystemComponent>("Particle System", entity, [](Entity ent, auto& component)
660 {
661 ParticleSystem& ps = component.System;
662 ParticleProps& psp = ps.m_Props;
663 ImGui::DragFloat("Lifetime", &psp.Lifetime, 0.1f, 0.0f, 10000.0f);
664 ImGui::DragFloat("Lifetime Variation", &psp.LifetimeVariation, 0.1f, 0.0f, 10000.0f);
665 ImGui::Separator();
666
667 ImGui::DragFloat("Start Size", &psp.SizeBegin, 0.1f, 0.0f, 10000.0f);
668 ImGui::DragFloat("Size Variation", &psp.SizeVariation, 0.1f, 0.0f, 10000.0f);
669 ImGui::DragFloat("End Size", &psp.SizeEnd, 0.1f, 0.0f, 10000.0f);
670 ImGui::Separator();
671
672 ImGui::ColorEdit4("Start Color", glm::value_ptr(psp.ColorBegin));
673 ImGui::ColorEdit4("End Color", glm::value_ptr(psp.ColorEnd));
674 ImGui::Separator();
675
676 ImGui::DragFloat2("Velocity", glm::value_ptr(psp.Velocity), 0.1f);
677 ImGui::DragFloat2("Velocity Variation", glm::value_ptr(psp.VelocityVariation), 0.1f);
678 ImGui::DragFloat3("Position Variation", glm::value_ptr(psp.PositionVariation), 0.1f);
679 ImGui::Separator();
680
681 ImGui::DragFloat("Rotation Speed", &psp.Rotation, 0.1f, -360.0f, 360.0f);
682 ImGui::DragFloat("Rotation Speed Variation", &psp.RotationVariation, 0.1f, 0.0f, 360.0f);
683 ImGui::Separator();
684
685 if (ImGui::Button("Reset System")) {
686 ps.ResetSystem();
687 }
688 ImGui::SameLine();
689 if (ImGui::Button("Emit")) {
690 ps.Emit(ps.m_Props);
691 }
692 ImGui::SameLine();
693 if (ImGui::Checkbox("Loop", &ps.m_Loop)) {
694
695 }
696
697 });
698
699
700 }
#define MU_WARN(...)
warn: indicates a potential issue or important event
Definition Log.h:51
static std::string OpenFile(const char *filter)
Opens a file dialog to select a file to open.
Definition LinuxPlatformUtils.cpp:160
ProjectionType
Definition SceneCamera.h:14
static Ref< SubTexture2D > CreateFromCoords(const Ref< Texture2D > &texture, const glm::vec2 &coords, const glm::vec2 &cellSize, const glm::vec2 &spriteSize={1, 1})
Creates a SubTexture2D from a grid of cells within the given texture.
Definition SubTexture2D.cpp:17
static Ref< Texture2D > Create(uint32_t width, uint32_t height)
Definition Texture.cpp:10
static void SubTextureEdit(Entity entity, const std::string &label, SubTextureComponent &subTexture)
Definition SceneHierarchyPanel.cpp:298
static void TextureAnimationEdit(const std::string &label, SubTextureComponent &subTexture, TextureAnimationComponent &texAnim)
Definition SceneHierarchyPanel.cpp:343
static void DrawVec3Control(const std::string &label, glm::vec3 &values, float resetValue=0.0f, float columnWidth=100.0f)
Definition SceneHierarchyPanel.cpp:156

References Muto::ParticleSystem::Emit(), Muto::FileDialogs::OpenFile(), Muto::SceneCamera::Orthographic, Muto::SceneCamera::Perspective, and Muto::ParticleSystem::ResetSystem().

Referenced by OnImGuiRender().

◆ DrawEntityNode()

void Muto::SceneHierarchyPanel::DrawEntityNode ( Entity  entity)
private

TODO: Improve name duplication logic

TODO: Draw child entities here in the future

TODO: Improve name duplication logic

TODO: Draw child entities here in the future

69 {
70 auto& name = entity.GetComponent<NameComponent>().Name;
71 void* nodeID = (void*)(uint64_t)(uint32_t)entity;
72
75 bool opened = ImGui::TreeNodeEx(nodeID, flags, name.c_str());
76 if (ImGui::IsItemClicked())
77 {
78 m_SelectionContext = entity;
79 }
80
81 bool entityDeleted = false;
82 if (ImGui::BeginPopupContextItem())
83 {
84 if (ImGui::MenuItem("Delete Entity"))
85 entityDeleted = true;
86
87 if (ImGui::MenuItem("Duplicate Entity"))
88 {
89 Entity newEntity = m_Context->CreateEntity(name);
90 // Copy components
91 if (entity.HasComponent<NameComponent>()) {
92 auto& src = entity.GetComponent<NameComponent>();
93 auto& newEntName = newEntity.GetComponent<NameComponent>();
95 if (src.Name.capacity() > 0 && isdigit(src.Name.back()))
96 {
97 // Increment trailing number
98 size_t i = src.Name.size() - 1;
99 while (i > 0 && isdigit(src.Name[i - 1]))
100 --i;
101 std::string baseName = src.Name.substr(0, i);
102 std::string numberStr = src.Name.substr(i);
103 int number = std::stoi(numberStr);
104 newEntName.Name = baseName + std::to_string(number + 1);
105 }
106 else
107 newEntName.Name = src.Name + "1";
108 }
109 if (entity.HasComponent<SpriteRendererComponent>())
110 {
111 auto& src = entity.GetComponent<SpriteRendererComponent>();
112 newEntity.AddComponent<SpriteRendererComponent>(src);
113 }
114 if (entity.HasComponent<CameraComponent>())
115 {
116 auto& cc = entity.GetComponent<CameraComponent>();
117 newEntity.AddComponent<CameraComponent>(cc);
118 }
119 if (entity.HasComponent<NativeScriptComponent>())
120 {
121 auto& nsc = entity.GetComponent<NativeScriptComponent>();
122 newEntity.AddComponent<NativeScriptComponent>(nsc);
123 }
124 if (entity.HasComponent<TextureAnimationComponent>())
125 {
126 auto& tac = entity.GetComponent<TextureAnimationComponent>();
127 newEntity.AddComponent<TextureAnimationComponent>(tac);
128 }
129 // Add more components as needed
131 }
132
133 ImGui::EndPopup();
134 }
135
136 if (opened)
137 {
139 bool opened = ImGui::TreeNodeEx((void*)9817239, flags, name.c_str());
140 if (opened)
141 {
143 ImGui::TreePop();
144 }
145 ImGui::TreePop();
146 }
147
148 if (entityDeleted)
149 {
150 m_Context->DestroyEntity(entity);
151 if (m_SelectionContext == entity)
153 }
154 }
T & GetComponent()
Retrieves a reference to the component of type T attached to the entity if it exists....
Definition Entity.h:73
Ref< Scene > m_Context
Definition SceneHierarchyPanel.h:30

References m_SelectionContext.

◆ GetSelectedEntity()

Entity Muto::SceneHierarchyPanel::GetSelectedEntity ( ) const
inline
21{ return m_SelectionContext; }

References m_SelectionContext.

◆ OnImGuiRender()

void Muto::SceneHierarchyPanel::OnImGuiRender ( )
29 {
30 ImGui::Begin("Scene Hierarchy");
31 if (m_Context) {
32
33 auto view = m_Context->m_Registry.view<NameComponent>();
34
35 for (auto entity : view) {
36 Entity e{ entity, m_Context.get() };
38 }
39
40 if (ImGui::IsMouseDown(0) && ImGui::IsWindowHovered())
42
43 // Right-click on blank space
44 if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_NoOpenOverItems | ImGuiPopupFlags_MouseButtonRight))
45 {
46 if (ImGui::MenuItem("Create Empty Entity"))
47 m_SelectionContext = m_Context->CreateEntity("Empty Entity");
48
49 ImGui::EndPopup();
50 }
51 }
52 ImGui::End();
53
54 ImGui::Begin("Properties");
56 {
58 }
59
60 ImGui::End();
61 }
void DrawComponents(Entity entity)
Definition SceneHierarchyPanel.cpp:451
void DrawEntityNode(Entity entity)
Definition SceneHierarchyPanel.cpp:68

References DrawComponents(), and m_SelectionContext.

◆ SetContext()

void Muto::SceneHierarchyPanel::SetContext ( const Ref< Scene > &  context)
23 {
26 }

References m_SelectionContext.

◆ SetSelectedEntity()

void Muto::SceneHierarchyPanel::SetSelectedEntity ( Entity  entity)
64 {
65 m_SelectionContext = entity;
66 }

References m_SelectionContext.

Member Data Documentation

◆ m_Context

Ref<Scene> Muto::SceneHierarchyPanel::m_Context
private

◆ m_Framebuffer

Ref<Framebuffer> Muto::SceneHierarchyPanel::m_Framebuffer
private

◆ m_SelectionContext

Entity Muto::SceneHierarchyPanel::m_SelectionContext
private

The documentation for this class was generated from the following files: