diff --git a/CMakeLists.txt b/CMakeLists.txt index 65e5b85..625591d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.5) set (CMAKE_EXPORT_COMPILE_COMMANDS ON) # C++ -set (CMAKE_CXX_STANDARD 23) +set (CMAKE_CXX_STANDARD 20) set (CMAKE_CXX_STANDARD_REQUIRED ON) # Project declaration diff --git a/README.md b/README.md index 5209eba..03c625d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Come back later, sorry! Jenjin is not ready for real usage. - [x] Texture loading - [x] Scripting (Lua) - [x] Transparency on sprites -- [ ] Icons everywhere +- [x] Icons everywhere - [ ] Code editor in the editor - [ ] Dynamic data attached to game objects at runtime - [ ] Hierarchy and `.Parent` in Lua along with `workspace` (e.g. `Workspace.MyGameObject.Parent` == `Workspace`) diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 809b491..c0dc12a 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -15,6 +15,7 @@ target_include_directories(JenjinEngine ${CMAKE_SOURCE_DIR}/megasource/libs/stb/ ${CMAKE_SOURCE_DIR}/megasource/libs/lua/include/ ${CMAKE_SOURCE_DIR}/megasource/libs/sol2/include/ + ${CMAKE_SOURCE_DIR}/megasource/libs/IconFontCppHeaders/ ${CMAKE_SOURCE_DIR}/megasource/libs/ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src diff --git a/engine/src/editor/editor.cpp b/engine/src/editor/editor.cpp index 2710681..e52a8ce 100644 --- a/engine/src/editor/editor.cpp +++ b/engine/src/editor/editor.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include #include @@ -77,6 +79,7 @@ void Manager::menu() { ->LoadDirectory( (this->paths.projectPath + "/scripts/").c_str()); + spdlog::info("Readying lua manager"); scene->GetLuaManager()->Ready(); } else { scene->Load(this->paths.liveScenePath); @@ -148,10 +151,17 @@ void Manager::dockspace() { 0.6f, nullptr, &dockspace_id); auto middle = dockspace_id; - ImGui::DockBuilderDockWindow("Hierarchy", dock_left_up); - ImGui::DockBuilderDockWindow("Explorer", dock_left); - ImGui::DockBuilderDockWindow("Inspector", dock_right); - ImGui::DockBuilderDockWindow("Viewport", middle); + static auto hierarchy_title = ICON_FA_SITEMAP " Hierarchy"; + ImGui::DockBuilderDockWindow(hierarchy_title, dock_left_up); + + static auto explorer_title = ICON_FA_FOLDER " Explorer"; + ImGui::DockBuilderDockWindow(explorer_title, dock_left); + + static auto inspector_title = ICON_FA_EYE " Inspector"; + ImGui::DockBuilderDockWindow(inspector_title, dock_right); + + static auto viewport_title = ICON_FA_VIDEO " Viewport"; + ImGui::DockBuilderDockWindow(viewport_title, middle); ImGui::DockBuilderFinish(dockspace_id); } @@ -168,7 +178,8 @@ void Manager::hierarchy(Jenjin::Scene *scene) { std::vector> *gameObjects = Jenjin::EngineRef->GetCurrentScene()->GetGameObjects(); - ImGui::Begin("Hierarchy"); + static auto title = ICON_FA_SITEMAP " Hierarchy"; + ImGui::Begin(title); static char name[128] = {0}; // Press or Ctrl + Shift + A @@ -215,7 +226,8 @@ void Manager::hierarchy(Jenjin::Scene *scene) { ImGui::EndPopup(); } - if (ImGui::Selectable("Camera", selectedCamera)) { + static auto cameraText = ICON_FA_VIDEO " Camera"; + if (ImGui::Selectable(cameraText, selectedCamera)) { selectedCamera = !selectedCamera; if (selectedCamera) selectedObject = nullptr; @@ -224,7 +236,8 @@ void Manager::hierarchy(Jenjin::Scene *scene) { for (std::shared_ptr gameObject : *gameObjects) { bool isSelected = selectedObject == gameObject.get(); - if (ImGui::Selectable(gameObject->name.c_str(), isSelected)) { + const auto text = fmt::format("{} {}", ICON_FA_CUBE, gameObject->name); + if (ImGui::Selectable(text.c_str(), isSelected)) { if (isSelected) { selectedObject = nullptr; } else { @@ -246,7 +259,9 @@ void Manager::inspector(Jenjin::Scene *scene) { return; } - ImGui::Begin("Inspector"); + static auto appearance_title = ICON_FA_PALETTE " Appearance"; + static auto title = ICON_FA_EYE " Inspector"; + ImGui::Begin(title); if (selectedCamera) { ImGui::Text("Camera"); @@ -274,7 +289,7 @@ void Manager::inspector(Jenjin::Scene *scene) { ImGui::Unindent(); - ImGui::Text("Appearance"); + ImGui::Text("%s", appearance_title); ImGui::Separator(); ImGui::Indent(); @@ -294,7 +309,9 @@ void Manager::inspector(Jenjin::Scene *scene) { return; } - if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) { + static auto transform_title = ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT " Transform"; + if (ImGui::CollapsingHeader(transform_title, + ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Indent(); Jenjin::Editor::Widgets::transformWidget(&selectedObject->transform); ImGui::Unindent(); @@ -302,7 +319,7 @@ void Manager::inspector(Jenjin::Scene *scene) { ImGui::ItemSize(ImVec2(0, 10)); - if (ImGui::CollapsingHeader("Appearance", ImGuiTreeNodeFlags_DefaultOpen)) { + if (ImGui::CollapsingHeader(appearance_title)) { ImGui::Indent(); ImGui::ColorPicker3("Color", glm::value_ptr(selectedObject->color)); ImGui::Unindent(); @@ -310,54 +327,27 @@ void Manager::inspector(Jenjin::Scene *scene) { ImGui::ItemSize(ImVec2(0, 10)); - if (ImGui::CollapsingHeader("Textures", ImGuiTreeNodeFlags_DefaultOpen)) { + static auto manage_title = ICON_FA_JAR " Manage"; + if (ImGui::CollapsingHeader(manage_title, 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)) { - if (isSelected) { - scene->SetGameObjectTexture(selectedObject, ""); - } else { - scene->SetGameObjectTexture(selectedObject, - texture.path().string()); - } - } - } - } - - ImGui::ItemSize(ImVec2(0, 2)); - - if (!selectedObject->texturePath.empty()) { - ImGui::Spacing(); - ImGui::Checkbox("Mix Color", &selectedObject->mixColor); - } - - ImGui::Unindent(); - } - ImGui::ItemSize(ImVec2(0, 10)); + float itemWidth = ImGui::GetContentRegionAvail().x; - if (ImGui::CollapsingHeader("Manage", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Indent(); + ImGui::SetNextItemWidth(itemWidth); ImGui::InputText("##RenameInput", renameGameObjectBuffer, sizeof(renameGameObjectBuffer)); - ImGui::SameLine(); - if (ImGui::Button("Rename")) { + + static auto text = ICON_FA_PEN " Rename"; + if (ImGui::Button(text, ImVec2(itemWidth, 0))) { selectedObject->SetName(renameGameObjectBuffer); } - if (ImGui::Button("Delete")) { + + static auto delete_text = ICON_FA_TRASH " Delete"; + if (ImGui::Button(delete_text, ImVec2(itemWidth, 0))) { scene->RemoveGameObject(selectedObject); selectedObject = nullptr; } + ImGui::Unindent(); } @@ -367,16 +357,54 @@ void Manager::inspector(Jenjin::Scene *scene) { } void Manager::explorer(Jenjin::Scene *scene) { - ImGui::Begin("Explorer"); + static auto title = ICON_FA_FOLDER " Explorer"; + ImGui::Begin(title); for (auto file : std::filesystem::directory_iterator(this->paths.projectPath)) { if (file.is_directory()) { + bool shouldBeOpenByDefault = + file.path().filename().string() == "textures"; if (ImGui::TreeNode(file.path().filename().string().c_str())) { for (auto subfile : std::filesystem::directory_iterator(file.path())) { if (subfile.is_regular_file()) { - ImGui::Selectable( - fmt::format("{}", subfile.path().filename().string()).c_str()); + auto ext = subfile.path().extension(); + + if (ext == ".jenscene") { + auto scene_text = fmt::format("{} {}", ICON_FA_CUBE, + subfile.path().filename().string()); + if (ImGui::Selectable(scene_text.c_str())) { + scene->Load(subfile.path().string()); + } + } else if (ext == ".lua") { + auto script_text = + fmt::format("{} {}", ICON_FA_FILE_CODE, + subfile.path().filename().string()); + if (ImGui::Selectable(script_text.c_str())) { + scene->GetLuaManager()->ReloadScripts(this->paths.projectPath + + "/scripts/"); + scene->GetLuaManager()->Ready(); + } + } else if (ext == ".png" || ext == ".jpg") { + auto texture_text = fmt::format( + "{} {}", ICON_FA_IMAGE, subfile.path().filename().string()); + if (ImGui::Selectable(texture_text.c_str())) { + if (selectedObject) { + scene->SetGameObjectTexture(selectedObject, + subfile.path().string()); + } else { + spdlog::warn("No object selected"); + + // TODO: Notificaiton system + } + } + } else { + auto file_text = fmt::format("{} {}", ICON_FA_FILE, + subfile.path().filename().string()); + if (ImGui::Selectable(file_text.c_str())) { + spdlog::warn("No handler for file type: {}", ext.string()); + } + } } } ImGui::TreePop(); @@ -502,8 +530,10 @@ void Manager::welcome() { Jenjin::Editor::get_jendir() + "/Projects")) { if (file.is_directory()) { bool isSelected = selectedPreExisting == file.path().filename().string(); - if (ImGui::Selectable(file.path().filename().string().c_str(), isSelected, - ImGuiSelectableFlags_None, + const auto text = + fmt::format("{} {}", ICON_FA_FOLDER, file.path().filename().string()); + + if (ImGui::Selectable(text.c_str(), isSelected, ImGuiSelectableFlags_None, ImVec2(ImGui::GetWindowWidth() - ImGui::GetStyle().WindowPadding.x * 2, 0))) { @@ -532,21 +562,24 @@ void Manager::welcome() { ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); } - if (ImGui::Button("Open Project") && !selectedPreExisting.empty()) { + static auto open_project_text = ICON_FA_FOLDER_OPEN " Open Project"; + if (ImGui::Button(open_project_text) && !selectedPreExisting.empty()) { open_project(); } + if (selectedPreExisting.empty()) ImGui::PopStyleColor(3); ImGui::SameLine(); - if (ImGui::Button("New Project")) { + static auto new_project_text = ICON_FA_FOLDER_PLUS " New Project"; + if (ImGui::Button(new_project_text)) { ImGui::OpenPopup("New Project"); } ImGui::SameLine(); - auto text = "Delete"; + static auto text = ICON_FA_TRASH " Delete Project"; auto width = ImGui::CalcTextSize(text).x; ImGui::SetCursorPosX(ImGui::GetWindowWidth() - width - ImGui::GetStyle().WindowPadding.x - diff --git a/engine/src/editor/widgets.cpp b/engine/src/editor/widgets.cpp index a3e62fd..86dcc81 100644 --- a/engine/src/editor/widgets.cpp +++ b/engine/src/editor/widgets.cpp @@ -8,6 +8,13 @@ #include #include +#include + +#define LEFT_RIGHT ICON_FA_ARROWS_LEFT_RIGHT +#define UP_DOWN ICON_FA_ARROWS_UP_DOWN + +#define ROTATE ICON_FA_ARROWS_SPIN + using namespace Jenjin::Editor; static void drawButtonWithDrag(const std::string &buttonLabel, @@ -59,6 +66,9 @@ bool Widgets::transformWidget(Jenjin::GameObject::Transform *transform) { GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f; ImVec2 buttonSize = {lineHeight + 3.0f, lineHeight}; + static auto left_right_title = LEFT_RIGHT; + static auto up_down_title = UP_DOWN; + start_widget("Position"); drawButtonWithDrag("X", "##X", transform->position.x, ImVec4{0.6f, 0.2f, 0.2f, 1.0f}, @@ -72,19 +82,20 @@ bool Widgets::transformWidget(Jenjin::GameObject::Transform *transform) { end_widget(); start_widget("Scale"); - drawButtonWithDrag("W", "##ScaleW", transform->scale.x, + drawButtonWithDrag(left_right_title, "##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, + drawButtonWithDrag(up_down_title, "##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(); + static auto rotation_title = ROTATE; start_widget("Rotation", 1); - drawButtonWithDrag("Z", "##Rotation", transform->rotation, + drawButtonWithDrag(rotation_title, "##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); diff --git a/engine/src/helpers.cpp b/engine/src/helpers.cpp index 50034fc..856f940 100644 --- a/engine/src/helpers.cpp +++ b/engine/src/helpers.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include namespace Jenjin::Helpers { @@ -37,12 +39,24 @@ void CheckWindow(GLFWwindow *window) { void InitiateImGui(GLFWwindow *window) { IMGUI_CHECKVERSION(); ImGui::CreateContext(); + ImGuiIO &io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; io.Fonts->AddFontFromFileTTF("resources/fonts/Roboto-Medium.ttf", 16.0f); + + float base = 16.0f; + float icon = base * 2.0f / 3.0f; + + static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_16_FA, 0 }; + ImFontConfig config; + config.MergeMode = true; + config.PixelSnapH = true; + config.GlyphMinAdvanceX = icon; + io.Fonts->AddFontFromFileTTF("./resources/fonts/fa-solid-900.ttf", base, &config, icon_ranges); + ImGui::StyleColorsDark(); // Photoshop style by Derydoca from ImThemes diff --git a/engine/src/targets/editor.cpp b/engine/src/targets/editor.cpp index 3d887d4..98e2eaf 100644 --- a/engine/src/targets/editor.cpp +++ b/engine/src/targets/editor.cpp @@ -9,9 +9,12 @@ #include #include +#include #include +#define VIEWPORT_TITLE ICON_FA_VIDEO " Viewport"; + using namespace Jenjin::Targets; EditorTarget::EditorTarget() {} @@ -51,7 +54,9 @@ void EditorTarget::Render() { return; } - ImGui::Begin("Viewport"); + static auto title = VIEWPORT_TITLE; + ImGui::Begin(title, nullptr, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); ImVec2 size = ImGui::GetContentRegionAvail(); this->width = size.x; @@ -91,17 +96,13 @@ void EditorTarget::Resize(glm::vec2 size) { } glm::vec2 EditorTarget::GetMousePosition() { - // WARNING: Untested... - static auto ctx = glfwGetCurrentContext(); static double gx, gy; glfwGetCursorPos(ctx, &gx, &gy); - // g_ is the whole window - // l_ is the viewport we need to calculate this - auto l_ = ImGui::GetWindowPos(); - auto lx = gx - l_.x; - auto ly = gy - l_.y; + auto v = ImGui::GetWindowPos(); // HACK: This is wrong!!! It doesn't get the viewport window pos. + auto lx = gx - v.x; + auto ly = gy - v.y; return glm::vec2(lx, ly); } diff --git a/jenjin/game b/jenjin/game deleted file mode 100755 index 0d333db..0000000 Binary files a/jenjin/game and /dev/null differ diff --git a/megasource b/megasource index 603b8cd..a9f6cc7 160000 --- a/megasource +++ b/megasource @@ -1 +1 @@ -Subproject commit 603b8cda1e1ed00d492da2ee2db10f407ea89f31 +Subproject commit a9f6cc787d03e03ba66aa8ccc678478a43bc1924 diff --git a/resources/fonts/fa-solid-900-LICENSE.txt b/resources/fonts/fa-solid-900-LICENSE.txt new file mode 100644 index 0000000..49cdf4f --- /dev/null +++ b/resources/fonts/fa-solid-900-LICENSE.txt @@ -0,0 +1 @@ +https://fontawesome.com/license/free diff --git a/resources/fonts/fa-solid-900.ttf b/resources/fonts/fa-solid-900.ttf new file mode 100644 index 0000000..cee3c5b Binary files /dev/null and b/resources/fonts/fa-solid-900.ttf differ