Skip to content

Commit

Permalink
feat: Improved inspector with custom transform widget
Browse files Browse the repository at this point in the history
  • Loading branch information
BenMcAvoy committed Oct 8, 2024
1 parent d87e383 commit e60e059
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 112 deletions.
6 changes: 6 additions & 0 deletions engine/include/jenjin/editor/widgets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "jenjin/gameobject.h"
namespace Jenjin::Editor::Widgets {
bool transformWidget(Jenjin::GameObject::Transform* transform); // Returns true if the transform was changed
};
207 changes: 97 additions & 110 deletions engine/src/editor/editor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "jenjin/editor/editor.h"
#include "jenjin/editor/utils.h"
#include "jenjin/editor/widgets.h"
#include "jenjin/gameobject.h"
#include "jenjin/helpers.h"
#include "jenjin/engine.h"
Expand Down Expand Up @@ -32,7 +33,6 @@ void Manager::menu() {
}

if (ImGui::MenuItem("Open Scene")) {
/* std::ifstream file(this->paths.openScenePath); */
Jenjin::EngineRef->GetCurrentScene()->Load(this->paths.openScenePath);
}

Expand Down Expand Up @@ -115,7 +115,7 @@ void Manager::dockspace() {

auto dock_left = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.25f, nullptr, &dockspace_id);
auto dock_left_up = ImGui::DockBuilderSplitNode(dock_left, ImGuiDir_Up, 0.8f, nullptr, &dock_left);
auto dock_right = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right, 0.4f, nullptr, &dockspace_id);
auto dock_right = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right, 0.6f, nullptr, &dockspace_id);
auto middle = dockspace_id;

ImGui::DockBuilderDockWindow("Hierarchy", dock_left_up);
Expand Down Expand Up @@ -249,79 +249,114 @@ void Manager::inspector(Jenjin::Scene* scene) {
return;
}

if (!(ImGui::CollapsingHeader(selectedObject->name.c_str()), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Bullet)) {
ImGui::End();
return;
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Indent();
Jenjin::Editor::Widgets::transformWidget(&selectedObject->transform);
ImGui::Unindent();
}

ImGui::Indent();

ImGui::Text("Transform");
ImGui::Separator();
ImGui::Indent();

ImGui::DragFloat2("Position", glm::value_ptr(selectedObject->transform.position), 0.1f);
ImGui::DragFloat("Rotation", &selectedObject->transform.rotation, 0.1f);
ImGui::DragFloat2("Scale", glm::value_ptr(selectedObject->transform.scale), 0.025f);

ImGui::Unindent();

ImGui::Text("Appearance");
ImGui::Separator();
ImGui::Indent();

ImGui::Text("Colours");
ImGui::Separator();
ImGui::Indent();
ImGui::Spacing();
ImGui::ColorEdit3("Color", glm::value_ptr(selectedObject->color));
ImGui::Unindent();

ImGui::Text("Textures");
ImGui::Separator();
ImGui::Indent();
ImGui::Spacing();
auto diriter = std::filesystem::directory_iterator(this->paths.projectPath + "/textures/");
ImGui::ItemSize(ImVec2(0, 10));

if (diriter == std::filesystem::directory_iterator()) {
ImGui::Text("No textures found");
if (ImGui::CollapsingHeader("Appearance", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Indent();
ImGui::ColorPicker3("Color", glm::value_ptr(selectedObject->color));
ImGui::Unindent();
}

for (auto& texture : diriter) {
if (texture.is_regular_file() && texture.path().extension() == ".png" || texture.path().extension() == ".jpg") {
bool isSelected = selectedObject->texturePath == texture.path().string();
if (ImGui::Selectable(texture.path().filename().string().c_str(), isSelected)) {
scene->SetGameObjectTexture(selectedObject, texture.path().string());
ImGui::ItemSize(ImVec2(0, 10));

if (ImGui::CollapsingHeader("Textures", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Indent();
auto diriter = std::filesystem::directory_iterator(this->paths.projectPath + "/textures/");
if (diriter == std::filesystem::directory_iterator()) {
ImGui::Text("No textures found");
}
for (auto& texture : diriter) {
if (texture.is_regular_file() && texture.path().extension() == ".png" || texture.path().extension() == ".jpg") {
bool isSelected = selectedObject->texturePath == texture.path().string();
if (ImGui::Selectable(texture.path().filename().string().c_str(), isSelected)) {
scene->SetGameObjectTexture(selectedObject, texture.path().string());
}
}
}
}

if (!selectedObject->texturePath.empty()) {
ImGui::Spacing();
ImGui::Checkbox("Mix Color", &selectedObject->mixColor);
}
ImGui::ItemSize(ImVec2(0, 2));

ImGui::Unindent();
if (!selectedObject->texturePath.empty()) {
ImGui::Spacing();
ImGui::Checkbox("Mix Color", &selectedObject->mixColor);
}

ImGui::Spacing();
ImGui::Unindent();
}

ImGui::Text("Manage");
ImGui::Separator();
ImGui::Indent();
ImGui::Spacing();
ImGui::ItemSize(ImVec2(0, 10));

ImGui::InputText("##RenameInput", renameGameObjectBuffer, sizeof(renameGameObjectBuffer));
ImGui::SameLine();
if (ImGui::Button("Rename")) {
selectedObject->SetName(renameGameObjectBuffer);
if (ImGui::CollapsingHeader("Manage", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Indent();
ImGui::InputText("##RenameInput", renameGameObjectBuffer, sizeof(renameGameObjectBuffer));
ImGui::SameLine();
if (ImGui::Button("Rename")) {
selectedObject->SetName(renameGameObjectBuffer);
}
if (ImGui::Button("Delete")) {
scene->RemoveGameObject(selectedObject);
selectedObject = nullptr;
}
ImGui::Unindent();
}

if (ImGui::Button("Delete")) {
scene->RemoveGameObject(selectedObject);
selectedObject = nullptr;
}
/* ImGui::Text("Colours"); */
/* ImGui::Separator(); */
/* ImGui::Indent(); */
/* ImGui::Spacing(); */
/* ImGui::ColorEdit3("Color", glm::value_ptr(selectedObject->color)); */
/* ImGui::Unindent(); */

/* ImGui::Text("Textures"); */
/* ImGui::Separator(); */
/* ImGui::Indent(); */
/* ImGui::Spacing(); */
/* auto diriter = std::filesystem::directory_iterator(this->paths.projectPath + "/textures/"); */

/* if (diriter == std::filesystem::directory_iterator()) { */
/* ImGui::Text("No textures found"); */
/* } */

/* for (auto& texture : diriter) { */
/* if (texture.is_regular_file() && texture.path().extension() == ".png" || texture.path().extension() == ".jpg") { */
/* bool isSelected = selectedObject->texturePath == texture.path().string(); */
/* if (ImGui::Selectable(texture.path().filename().string().c_str(), isSelected)) { */
/* scene->SetGameObjectTexture(selectedObject, texture.path().string()); */
/* } */
/* } */
/* } */

/* if (!selectedObject->texturePath.empty()) { */
/* ImGui::Spacing(); */
/* ImGui::Checkbox("Mix Color", &selectedObject->mixColor); */
/* } */

/* ImGui::Unindent(); */

/* ImGui::Spacing(); */

/* ImGui::Text("Manage"); */
/* ImGui::Separator(); */
/* ImGui::Indent(); */
/* ImGui::Spacing(); */

/* ImGui::InputText("##RenameInput", renameGameObjectBuffer, sizeof(renameGameObjectBuffer)); */
/* ImGui::SameLine(); */
/* if (ImGui::Button("Rename")) { */
/* selectedObject->SetName(renameGameObjectBuffer); */
/* } */

/* if (ImGui::Button("Delete")) { */
/* scene->RemoveGameObject(selectedObject); */
/* selectedObject = nullptr; */
/* } */

ImGui::Unindent();
ImGui::Unindent();

ImGui::End();
Expand All @@ -346,54 +381,6 @@ void Manager::explorer(Jenjin::Scene* scene) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 256);

static bool demo_tools; ImGui::Checkbox("Demo Tools", &demo_tools); if (demo_tools) ImGui::ShowDemoWindow(&demo_tools);
static bool jenjin_demo; ImGui::Checkbox("Jenjin Demo", &jenjin_demo);

static float hue = 0.0f;
auto change_ui_hue = [](float hue) {
ImGuiStyle& style = ImGui::GetStyle();
for (int i = 0; i < ImGuiCol_COUNT; i++) {
static ImVec4* colors = style.Colors;
float h, s, v; ImGui::ColorConvertRGBtoHSV(colors[i].x, colors[i].y, colors[i].z, h, s, v);
float r, g, b; ImGui::ColorConvertHSVtoRGB(hue, s, v, r, g, b);
colors[i] = ImVec4(r, g, b, colors[i].w);
}
};
hue = fmodf(hue + 0.0012f, 1.0f);
change_ui_hue(hue);

/*if (jenjin_demo) {
static float hue = 0.0f;
auto change_ui_hue = [](float hue) {
ImGuiStyle& style = ImGui::GetStyle();
for (int i = 0; i < ImGuiCol_COUNT; i++) {
static ImVec4* colors = style.Colors;
float h, s, v; ImGui::ColorConvertRGBtoHSV(colors[i].x, colors[i].y, colors[i].z, h, s, v);
float r, g, b; ImGui::ColorConvertHSVtoRGB(hue, s, v, r, g, b);
colors[i] = ImVec4(r, g, b, colors[i].w);
}
};
float ch, cs, cv;
ch = 0.0f; cs = 1.0f; cv = 1.0f;
float cr, cg, cb;
ImGui::ColorConvertHSVtoRGB(hue, cs, cv, cr, cg, cb);
static ImVec4 col = ImVec4(cr, cg, cb, 1.0f);
if (ImGui::ColorEdit3("Base colour", (float*)&col)) {
float nh, ns, nv;
ImGui::ColorConvertRGBtoHSV(col.x, col.y, col.z, nh, ns, nv);
hue = nh;
change_ui_hue(hue);
}
if (ImGui::DragFloat("Hue", &hue, 0.001f, 0.0f, 1.0f)) {
change_ui_hue(hue);
}
/* static bool rainbow; ImGui::Checkbox("Rainbow", &rainbow); */
/* if (rainbow) { */
/* }
}*/

ImGui::End();
}
Expand Down Expand Up @@ -510,7 +497,7 @@ void Manager::welcome() {
ImGui::SameLine();

if (ImGui::Button("New Project")) {
ImGui::OpenPopup("NewProject");
ImGui::OpenPopup("New Project");
}

ImGui::SameLine();
Expand All @@ -522,7 +509,7 @@ void Manager::welcome() {
ImGui::OpenPopup("DeleteProject");
}

if (ImGui::BeginPopupModal("NewProject", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
if (ImGui::BeginPopupModal("New Project", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
static char projectName[128] = {0};
ImGui::InputText("Project Name", projectName, sizeof(projectName));
if (ImGui::Button("Create##NewProject") || ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter))) {
Expand Down
86 changes: 86 additions & 0 deletions engine/src/editor/widgets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "jenjin/editor/widgets.h"
#include "jenjin/gameobject.h"

#include <glm/glm.hpp>

#include <imgui.h>
#include <imgui_internal.h>

using namespace Jenjin::Editor;

static void drawButtonWithDrag(const std::string& buttonLabel, const std::string& dragLabel, float& value, const ImVec4& buttonColor, const ImVec4& buttonHoveredColor, const ImVec4& buttonActiveColor, const ImVec2& buttonSize, int defaultValue = 0) {
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, buttonActiveColor);

if (ImGui::Button(buttonLabel.c_str(), buttonSize))
value = defaultValue;

ImGui::PopStyleColor(3);

ImGui::SameLine();
ImGui::DragFloat(dragLabel.c_str(), &value, 0.1f, 0.0f, 0.0f, "%.2f");
ImGui::PopItemWidth();
ImGui::SameLine();
}

static void start_widget(const std::string& label, int count = 2) {
ImGui::PushID(label.c_str());
ImGui::Columns(2);
ImGui::SetColumnWidth(0, 100.0f);
ImGui::Text("%s", label.c_str());
ImGui::NextColumn();

// HACK: This is a hack to make the drag float buttons all the same size... this needs to be revisited
ImGui::PushMultiItemsWidths(count, ImGui::CalcItemWidth() + (count == 1 ? ImGui::GetStyle().ItemSpacing.x * 2 + ImGui::GetStyle().FramePadding.x + 1 : 0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0, 0 });
}

static void end_widget() {
ImGui::PopStyleVar();
ImGui::Columns(1);
ImGui::PopID();
}

bool Widgets::transformWidget(Jenjin::GameObject::Transform* transform) {
float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
ImVec2 buttonSize = { lineHeight + 3.0f, lineHeight };

start_widget("Position");
drawButtonWithDrag("X", "##X", transform->position.x,
ImVec4{ 0.6f, 0.2f, 0.2f, 1.0f },
ImVec4{ 0.7f, 0.3f, 0.3f, 1.0f },
ImVec4{ 0.6f, 0.2f, 0.2f, 1.0f },
buttonSize);

drawButtonWithDrag("Y", "##Y", transform->position.y,
ImVec4{ 0.3f, 0.6f, 0.3f, 1.0f },
ImVec4{ 0.4f, 0.7f, 0.4f, 1.0f },
ImVec4{ 0.3f, 0.6f, 0.3f, 1.0f },
buttonSize);
end_widget();

start_widget("Scale");
drawButtonWithDrag("W", "##ScaleW", transform->scale.x,
ImVec4{ 0.6f, 0.2f, 0.2f, 1.0f },
ImVec4{ 0.7f, 0.3f, 0.3f, 1.0f },
ImVec4{ 0.6f, 0.2f, 0.2f, 1.0f },
buttonSize, 1);

drawButtonWithDrag("H", "##ScaleH", transform->scale.y,
ImVec4{ 0.3f, 0.6f, 0.3f, 1.0f },
ImVec4{ 0.4f, 0.7f, 0.4f, 1.0f },
ImVec4{ 0.3f, 0.6f, 0.3f, 1.0f },
buttonSize, 1);
end_widget();

start_widget("Rotation", 1);
drawButtonWithDrag("Z", "##Rotation", transform->rotation,
ImVec4{ 0.3f, 0.4f, 0.7f, 1.0f },
ImVec4{ 0.4f, 0.5f, 0.8f, 1.0f },
ImVec4{ 0.3f, 0.4f, 0.7f, 1.0f },
buttonSize);
end_widget();

return false;
}
4 changes: 2 additions & 2 deletions engine/src/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void InitiateImGui(GLFWwindow* window) {
io.Fonts->AddFontFromFileTTF("resources/fonts/Roboto-Medium.ttf", 16.0f);
ImGui::StyleColorsDark();

// Photoshop style by Derydoca from ImThemes (Padding values slightly adjusted)
// Photoshop style by Derydoca from ImThemes
auto Derydocas_PhotoshopTheme_FromImThemes = [](ImGuiStyle& style) {
style.Alpha = 1.0f;
style.DisabledAlpha = 0.6000000238418579f;
Expand All @@ -57,7 +57,7 @@ void InitiateImGui(GLFWwindow* window) {
style.ChildBorderSize = 1.0f;
style.PopupRounding = 2.0f;
style.PopupBorderSize = 1.0f;
style.FramePadding = ImVec2(10.0f, 8.0f);
style.FramePadding = ImVec2(4.0f, 3.0f);
style.FrameRounding = 2.0f;
style.FrameBorderSize = 1.0f;
style.ItemSpacing = ImVec2(8.0f, 4.0f);
Expand Down

0 comments on commit e60e059

Please sign in to comment.