diff --git a/docs/tasks/core.todo b/docs/tasks/core.todo index 4a492b6..391fe9e 100644 --- a/docs/tasks/core.todo +++ b/docs/tasks/core.todo @@ -7,10 +7,14 @@ Build System: ✔ Modify .sh scripts to recognize the noeditor flag @done (1/25/2022, 3:59:23 PM) Core: + ☐ Update console gui system to store the full message meta-data so that filters can be applied @High ☐ Create log rotation system so that log files do not grow to GB in size... @critical - If file is X MBs, check for file with .old ext and erase if exists, .old to current file and create new log file ☐ Figure out how to represent Unique Entities and entity instances - and how this will work with UUIDs @critical ☐ Design Entity Template system + + ☐ Add log settings to the state file + ✔ Implement generic serialization system @done(22-06-29 18:44) ✔ JSON serializable base class @done(22-06-29 17:41) ✔ JSON implementions should be stubbed out in non-editor builds @done(22-06-29 17:41) @@ -27,7 +31,6 @@ Core: ✔ assets @done(22-05-17 14:27) ✔ gui @done(22-05-17 14:27) ✔ Replace the File Browser (imgui) class with the NFD library (https://github.com/btzy/nativefiledialog-extended) @high @done(22-05-23 16:00) - ☐ Add log settings to the state file ✔ Refactor log system to use separate log level methods instead of passing log level @done(22-05-12 16:46) ✔ Add log level options to config script @done(22-05-12 16:46) ✔ Add run modes (Editor, Game, Test) to state file @done (9/15/2021, 7:27:03 PM) @@ -35,15 +38,19 @@ Core: ✔ Read the window size and position on shutdown and write these to the state file @done (2/8/2022, 4:39:37 PM) Physics: + ☐ Joint Component to allow parent/child entities to both use the physics system @high + ☐ Come up with a way to wrap Box2D into an API @low ✔ Research Box2D as a possible physics library @done (10/27/2021, 7:40:44 PM) ✔ Add Box2D to the project as an external library @done (10/27/2021, 7:40:46 PM) ✔ Add a scene to the tester to test Box2D usage @done (10/28/2021, 2:42:45 PM) - ☐ Come up with a way to wrap Box2D into an API - ☐ Joint Component to allow parent/child entities to both use the physics system Scripting: - ☐ Add a Log methods to the CoreAPI + ☐ Add Entity class to wrap entity id values + - Foreign class that stores the entity id values and gives access to + - foreign methods for interacting with that entity (getting components/scripts) + + ✔ Add a Log methods to the CoreAPI @done(23-01-11 15:24) ✔ Allow scripts to interact (calling methods in other scripts) @done(23-01-10 16:54) - In order for a script to be registered with the World API it MUST @@ -56,11 +63,16 @@ Scripting: ✔ Script Asset @done(22-11-14 18:19) - Script Managment class: + Script State class: + ✔ Allow for running script class objects @done(23-01-11 15:28) + ✔ Allow for running raw code snippets (with module importing made easy) @done(23-01-11 15:29) + ✔ Wrapper methods for registering foreign classes and methods @done(23-01-11 15:29) + ✔ Wrapper methods for getting handles to classes @done(23-01-11 15:29) + ✘ Manage LUA states @cancelled(22-05-13 17:31) - ☐ Initialize new scripts - ☐ Run given script with given state - ☐ Add any generated errors to the Script object + ✘ Initialize new scripts @cancelled(23-01-11 15:28) + ✘ Run given script with given state @cancelled(23-01-11 15:28) + ✘ Add any generated errors to the Script object @cancelled(23-01-11 15:28) Interface Class (Core API): ☐ Provide Methods that give access to the C++ code @@ -71,8 +83,9 @@ Audio: ☐ Design Audio API Assets: + ☐ Document Index.Dat and the AssetIndex class + ✔ Internal Asset Manager @high @done (1/25/2022, 3:58:20 PM) - ☐ Document Index.Dat and the AssetIndex class ✔ Move the GenerateFont method from internal_font.h into data_manager.h @done(22-06-29 17:42) Types: @@ -156,7 +169,7 @@ ECS: ✔ Single UUID @done(22-06-01 14:01) ✔ Functionality for adding/working with components (through EnTT) @done(22-06-01 14:01) ☐ Serialize - ☐ JSON + ✔ JSON @done(23-01-11 15:35) ☐ Binary Components: @@ -171,11 +184,12 @@ ECS: ✔ Script @done(22-11-14 18:19) ☐ Audio Listener Physics: - ☐ Rigid Body (Box2D) - ☐ Box Collider (Box2D) + ☐ Joint Component + ✔ Rigid Body (Box2D) @done(23-01-11 15:35) + ✔ Collider (Box2D) @done(23-01-11 15:35) World (Lunariums version of a "Scene"): - ☐ Add Render layer property to all renderable components + ✔ Add Render layer property to all renderable components @done(23-01-11 15:35) ✔ Implement memento pattern to save the initial state of the world @done(22-11-14 18:19) ✔ Implement running the world and resetting to initial state @done(22-11-14 18:19) ✔ Implement the world without Regions first @done(22-11-14 18:20) diff --git a/docs/tasks/editor.todo b/docs/tasks/editor.todo index b36c094..210c74a 100644 --- a/docs/tasks/editor.todo +++ b/docs/tasks/editor.todo @@ -1,7 +1,11 @@ Editor: + ☐ Add ability to browse and restore trashed assets @High + ☐ Add button to flip image assets vertically + ☐ Design a custom editor style @low + ☐ Save and unload world data when a new world is selected + ✔ Generate boiler-plate code when a new script is created @critical @done(23-01-11 13:49) - ✔ Add pure virtual ShowProperties method to EditorAsset @done(22-11-28 20:11) ✔ Script Editor Asset @done(22-11-14 18:19) ✔ Editor Assets need to switch to using UUIDs @critical @done(22-11-02 18:51) @@ -10,9 +14,6 @@ Editor: ✔ Add Entity children @done(22-09-14 15:07) ✔ Entity Parent/Child hierarchy system @done(22-09-14 15:07) ✔ Give Entities a name property separate from the tag component @done(22-09-14 15:06) - ☐ Add button to flip image assets vertically - ☐ Design a custom editor style @low - ☐ Save and unload world data when a new world is selected ✔ Load the selected world when double clicked on in the asset browser @done(22-07-05 14:29) ✔ Asset Location MUST be relative to the project root directory @critical @done(22-05-20 18:35) ✔ Switch to NFD dialogs @done(22-05-20 18:35) @@ -24,8 +25,7 @@ Editor: ✔ Turn World into an editor asset that can be created @done(22-07-05 14:04) ✔ Store entities in the World object @done(22-07-06 17:53) ✔ Implement Saving/loading the World asset @done(22-07-06 17:53) - ☐ Test the Asset Trashing system @high - ☐ Add ability to browse and restore trashed assets + ✔ Test the Asset Trashing system @high @done(23-01-11 15:22) ✔ Figure out how to make game asset types integrate with editor asset types @critical @done(22-06-27 13:32) - Probably just wrap the game object in an EditorAsset object if needed diff --git a/src/gui/console.cpp b/src/gui/console.cpp index 2b84aa0..1119f94 100644 --- a/src/gui/console.cpp +++ b/src/gui/console.cpp @@ -46,7 +46,7 @@ namespace lunarium Console::Console(const char* name, PanelDockZone dock_zone, bool isOpen, int window_flags) : Panel(name, dock_zone, isOpen, window_flags), mbNewCommand(false), mRecalledCommand(-1), mIsFocused(false), mListener(nullptr), - mbOglDebug(false), mbInfoVerbose(false), mpListener(nullptr), mInputWindowHeight(20) + mbOglDebug(false), mbInfoVerbose(false), mbInfoDebug(false), mpListener(nullptr), mInputWindowHeight(20) { memset(mBuffer, 0, CONSOLE_BUFFER_SIZE); mpListener = Logger::GetInstance()->AddListener(new GuiListener(this)); @@ -76,6 +76,12 @@ namespace lunarium } + void Console::SetDebugFlag(bool flag) + { + mbInfoDebug = flag; + } + + void Console::ClearMessageHistory() { mMsgHistory.clear(); @@ -105,7 +111,8 @@ namespace lunarium { if ((mMsgHistory[i].find("[GRAPHICS INTERNAL DEBUG]") != std::string::npos && !mbOglDebug) - || (mMsgHistory[i].find("[TRACE]") != std::string::npos && !mbInfoVerbose)) + || (mMsgHistory[i].find("[TRACE]") != std::string::npos && !mbInfoVerbose) + || (mMsgHistory[i].find("[DEBUG]") != std::string::npos && !mbInfoDebug)) { continue; } diff --git a/src/gui/console.h b/src/gui/console.h index ad29d1d..8f9b5ac 100644 --- a/src/gui/console.h +++ b/src/gui/console.h @@ -53,6 +53,7 @@ namespace lunarium void SetOGLDebugFlag(bool flag); void SetVerboseFlag(bool flag); + void SetDebugFlag(bool flag); private: // INPUT COMMAND STUFF @@ -71,6 +72,7 @@ namespace lunarium GuiListener* mListener; bool mbOglDebug; bool mbInfoVerbose; + bool mbInfoDebug; private: void CheckFocus(); diff --git a/src/run_modes/editor/contents/content_manager.cpp b/src/run_modes/editor/contents/content_manager.cpp index 59547b2..7d4fb44 100644 --- a/src/run_modes/editor/contents/content_manager.cpp +++ b/src/run_modes/editor/contents/content_manager.cpp @@ -349,6 +349,7 @@ namespace lunarium { namespace editor void ContentManager::MoveAsset(EditorAsset* asset, std::filesystem::path to) { std::filesystem::path from = mpProject->GetAssetDirectory() / asset->GetFileLocation(); + to /= asset->GetFileLocation().filename(); // Not all assets will have files associated with them if (std::filesystem::exists(from)) diff --git a/src/run_modes/editor/contents/content_manager.h b/src/run_modes/editor/contents/content_manager.h index b1ae6c3..0819657 100644 --- a/src/run_modes/editor/contents/content_manager.h +++ b/src/run_modes/editor/contents/content_manager.h @@ -53,6 +53,9 @@ namespace lunarium { namespace editor /// file: the full path to the raw file /// to_location: the location inside the project's asset directory to import to (this MUST be a relative path starting in the Asset dir) [[nodiscard]] OpRes ImportFile(std::filesystem::path file, std::filesystem::path to_location, AssetType type, LUUID& id); + + /// @brief Trashes an asset + /// @param asset_id the UUID of the asset to trash void RemoveAsset(LUUID asset_id); void MoveAsset(EditorAsset* asset, std::filesystem::path to); diff --git a/src/run_modes/editor/contents/script.cpp b/src/run_modes/editor/contents/script.cpp index 716d38f..a34bef1 100644 --- a/src/run_modes/editor/contents/script.cpp +++ b/src/run_modes/editor/contents/script.cpp @@ -19,6 +19,12 @@ namespace lunarium { namespace editor Script::Script(std::filesystem::path file_location, std::filesystem::path asset_dir) : EditorAsset(AssetType::EATYPE_SCRIPT) { + // This is an existing script and data will be set later + // NOTE: Kind of hacky... + if (file_location.string().size() < 1 && asset_dir.string().size() < 1) + return; + + std::string full_path = (asset_dir / file_location).string(); if (!std::filesystem::exists(full_path)) diff --git a/src/run_modes/editor/editor.cpp b/src/run_modes/editor/editor.cpp index 881d75d..83e22a9 100644 --- a/src/run_modes/editor/editor.cpp +++ b/src/run_modes/editor/editor.cpp @@ -534,6 +534,12 @@ namespace editor } } } + + + void Editor::OnAssetTrash(EditorAsset* pAsset) + { + ContentManager::GetInstance().RemoveAsset(pAsset->GetID()); + } void Editor::OnAssetSelected(EditorAsset* pAsset) { diff --git a/src/run_modes/editor/editor.h b/src/run_modes/editor/editor.h index d78f1a2..4165052 100644 --- a/src/run_modes/editor/editor.h +++ b/src/run_modes/editor/editor.h @@ -62,6 +62,7 @@ namespace lunarium { namespace editor void OnEntitySelect(lunarium::Entity* pEnt); //void ChangeWorld(lunarium::World* pWorld); void OnAssetOpen(EditorAsset* pAsset); + void OnAssetTrash(EditorAsset* pAsset); void OnAssetSelected(EditorAsset* pAsset); void OnNewAsset(EditorAsset* pAsset); void OnAssetUpdate(EditorAsset* pAsset); diff --git a/src/run_modes/editor/panels/asset_browser.cpp b/src/run_modes/editor/panels/asset_browser.cpp index 8ea6b2b..ca0427e 100644 --- a/src/run_modes/editor/panels/asset_browser.cpp +++ b/src/run_modes/editor/panels/asset_browser.cpp @@ -27,7 +27,7 @@ namespace editor { AssetBrowser::AssetBrowser(std::filesystem::path dir, Editor* pEditor) : Panel("Asset Browser", PanelDockZone::DDZ_BOTTOM, true, (ImGuiWindowFlags)ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar), - mAssetDirectory(dir), mpEditor(pEditor), mSyncTree(false) + mAssetDirectory(dir), mpEditor(pEditor), mSyncTree(false), mpHoveredAsset(nullptr), mbMenusOpen(false) { DefinePopups(); } @@ -229,6 +229,9 @@ namespace editor for (auto iter = assets.begin(); iter != assets.end(); iter++) { + if ((*iter)->GetIsTrashed()) + continue; + if (ImGui::Selectable((*iter)->GetFileLocation().stem().string().c_str())) { // Show properties if this is new selection (meaning wasn't selected last frame) @@ -252,10 +255,11 @@ namespace editor mpEditor->OnAssetOpen((*iter)); } - if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) + if (ImGui::IsItemHovered() && ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - // TODO: CONTEXT MENU FOR ITEMS - Test Removing/Trashing + // Change context menu to apply to the hovered asset + mpHoveredAsset = (*iter); } } @@ -271,53 +275,82 @@ namespace editor // CONTEXT MENUS void AssetBrowser::DoContentContextMenu() { - if (ImGui::BeginPopupContextWindow(0, 1, false)) + if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight)) { - if (ImGui::Button("New Folder")) + if (mpHoveredAsset) { - //mNewFolder = true; - OpenPopup(PopUp::NEW_FOLDER).LogIfFailed(Editor::LogCat); + mbMenusOpen = true; + DoHoveredContextMenu(); } + else + { + DoEmptySpaceContextMenu(); + } + + // TODO: Buttons for creating/importing new assets + ImGui::EndPopup(); + } + else if (mbMenusOpen) + { + mbMenusOpen = false; + mpHoveredAsset = nullptr; + } + } + + void AssetBrowser::DoHoveredContextMenu() + { + if (ImGui::Button("Trash Asset")) + { + mpEditor->OnAssetTrash(mpHoveredAsset); + ImGui::CloseCurrentPopup(); + mpHoveredAsset = nullptr; + } + } + + void AssetBrowser::DoEmptySpaceContextMenu() + { + if (ImGui::Button("New Folder")) + { + // mNewFolder = true; + OpenPopup(PopUp::NEW_FOLDER).LogIfFailed(Editor::LogCat); + } - if (ImGui::BeginMenu("New Asset")) + if (ImGui::BeginMenu("New Asset")) + { + if (ImGui::MenuItem("New World")) { - if (ImGui::MenuItem("New World")) - { - OpenPopup(PopUp::NEW_WORLD).LogIfFailed(Editor::LogCat); - } + OpenPopup(PopUp::NEW_WORLD).LogIfFailed(Editor::LogCat); + } - if (ImGui::MenuItem("New Script")) - { - OpenPopup(PopUp::NEW_SCRIPT).LogIfFailed(Editor::LogCat); - } - ImGui::EndMenu(); + if (ImGui::MenuItem("New Script")) + { + OpenPopup(PopUp::NEW_SCRIPT).LogIfFailed(Editor::LogCat); } + ImGui::EndMenu(); + } - if (ImGui::BeginMenu("Import Asset")) + if (ImGui::BeginMenu("Import Asset")) + { + if (ImGui::MenuItem("Image")) { - if (ImGui::MenuItem("Image")) - { - std::filesystem::path outPath; + std::filesystem::path outPath; - // prepare filters for the dialog - FileSystem::FilterItem filterItem[3] = {{"Image file", "png"}, {"Image File", "jpg"}, {"Image File", "jpeg"}}; + // prepare filters for the dialog + FileSystem::FilterItem filterItem[3] = {{"Image file", "png"}, {"Image File", "jpg"}, {"Image File", "jpeg"}}; - // show the dialog - FileSystem::DialogResult result = FileSystem::OpenFileDialog(outPath, filterItem, 3); - if (result == FileSystem::DialogResult::OK) - { - Logger::Info(Editor::LogCat, "Importing asset: %s", outPath.string().c_str()); + // show the dialog + FileSystem::DialogResult result = FileSystem::OpenFileDialog(outPath, filterItem, 3); + if (result == FileSystem::DialogResult::OK) + { + Logger::Info(Editor::LogCat, "Importing asset: %s", outPath.string().c_str()); - LUUID id = 0; - ContentManager::GetInstance().ImportFile(outPath, mSelectedDir / outPath.filename(), - AssetType::EATYPE_IMAGE, id).LogIfFailed(Editor::LogCat); - } + LUUID id = 0; + ContentManager::GetInstance().ImportFile(outPath, mSelectedDir / outPath.filename(), + AssetType::EATYPE_IMAGE, id) + .LogIfFailed(Editor::LogCat); } - ImGui::EndMenu(); } - - // TODO: Buttons for creating/importing new assets - ImGui::EndPopup(); + ImGui::EndMenu(); } } @@ -344,66 +377,75 @@ namespace editor { // New Folder AddPopup(PopUp::NEW_FOLDER, "New Folder Name", [](Panel *p) + { + bool stay_open = true; + AssetBrowser* ab = (AssetBrowser*)p; + char name_buf[64] = "New Folder"; + ImGui::TextUnformatted("Folder Name: "); + ImGui::SameLine(); + if (ImGui::InputText("##Folder Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) { - bool stay_open = true; - AssetBrowser* ab = (AssetBrowser*)p; - char name_buf[64] = "New Folder"; - ImGui::TextUnformatted("Folder Name: "); - ImGui::SameLine(); - if (ImGui::InputText("##Folder Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) - { - std::filesystem::create_directory(ab->mSelectedDir / name_buf); - stay_open = false; - ImGui::CloseCurrentPopup(); - } + std::filesystem::create_directory(ab->mSelectedDir / name_buf); + stay_open = false; + ImGui::CloseCurrentPopup(); + } - if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) - { - stay_open = false; - ImGui::CloseCurrentPopup(); - } - return stay_open; - }).LogIfFailed(Editor::LogCat); + if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) + { + stay_open = false; + ImGui::CloseCurrentPopup(); + } + return stay_open; + }).LogIfFailed(Editor::LogCat); - // New World - AddPopup(PopUp::NEW_WORLD, "New World Name", [](Panel *p) + // New World + AddPopup(PopUp::NEW_WORLD, "New World Name", [](Panel *p) + { + bool stay_open = true; + AssetBrowser* ab = (AssetBrowser*)p; + char name_buf[64] = "New World"; + ImGui::TextUnformatted("World Name: "); + ImGui::SameLine(); + if (ImGui::InputText("##World Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) { - bool stay_open = true; - AssetBrowser* ab = (AssetBrowser*)p; - char name_buf[64] = "New World"; - ImGui::TextUnformatted("World Name: "); - ImGui::SameLine(); - if (ImGui::InputText("##World Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) - { - auto assets_dir = ab->mpEditor->GetProject()->MakeRelativeToAssets(ab->mSelectedDir); - EditorAsset* pAsset = new editor::World(assets_dir / name_buf); - LUUID id; - - ContentManager::GetInstance().AddGeneratedAsset(pAsset, id).LogIfFailed(Editor::LogCat); - stay_open = false; - ImGui::CloseCurrentPopup(); - } + auto assets_dir = ab->mpEditor->GetProject()->MakeRelativeToAssets(ab->mSelectedDir); + EditorAsset* pAsset = new editor::World(assets_dir / name_buf); + LUUID id; + + ContentManager::GetInstance().AddGeneratedAsset(pAsset, id).LogIfFailed(Editor::LogCat); + stay_open = false; + ImGui::CloseCurrentPopup(); + } - if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) - { - stay_open = false; - ImGui::CloseCurrentPopup(); - } - return stay_open; - }).LogIfFailed(Editor::LogCat); + if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) + { + stay_open = false; + ImGui::CloseCurrentPopup(); + } + return stay_open; + }).LogIfFailed(Editor::LogCat); - // New script asset - AddPopup(PopUp::NEW_SCRIPT, "New Script Name", [](Panel *p) + // New script asset + AddPopup(PopUp::NEW_SCRIPT, "New Script Name", [](Panel *p) + { + bool stay_open = true; + AssetBrowser* ab = (AssetBrowser*)p; + char name_buf[64] = "New Script"; + ImGui::TextUnformatted("Script Name: "); + ImGui::SameLine(); + if (ImGui::InputText("##Script Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) { - bool stay_open = true; - AssetBrowser* ab = (AssetBrowser*)p; - char name_buf[64] = "New Script"; - ImGui::TextUnformatted("Script Name: "); - ImGui::SameLine(); - if (ImGui::InputText("##Script Name", name_buf, 64, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) + auto assets_dir = ab->mpEditor->GetProject()->MakeRelativeToAssets(ab->mSelectedDir); + std::string sname_buf = name_buf; + if (sname_buf.find(' ')!= std::string::npos) + { + // This does not show up + ImGui::BeginTooltip(); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Script names can not contain spaces!"); + ImGui::EndTooltip(); + } + else { - auto assets_dir = ab->mpEditor->GetProject()->MakeRelativeToAssets(ab->mSelectedDir); - std::string sname_buf = name_buf; sname_buf.append(".wren"); std::filesystem::path location = assets_dir / sname_buf; EditorAsset* pAsset = new editor::Script(location, ab->mpEditor->GetProject()->GetAssetDirectory()); @@ -413,14 +455,21 @@ namespace editor stay_open = false; ImGui::CloseCurrentPopup(); } + } + ImGui::SameLine(); + if (ImGui::Button("X")) + { + stay_open = false; + ImGui::CloseCurrentPopup(); + } - if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) - { - stay_open = false; - ImGui::CloseCurrentPopup(); - } - return stay_open; - }).LogIfFailed(Editor::LogCat); + if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true)) + { + stay_open = false; + ImGui::CloseCurrentPopup(); + } + return stay_open; + }).LogIfFailed(Editor::LogCat); } diff --git a/src/run_modes/editor/panels/asset_browser.h b/src/run_modes/editor/panels/asset_browser.h index af38f46..e43cbc4 100644 --- a/src/run_modes/editor/panels/asset_browser.h +++ b/src/run_modes/editor/panels/asset_browser.h @@ -36,6 +36,7 @@ namespace editor std::filesystem::path mSelectedDir; Editor* mpEditor; bool mSyncTree; + EditorAsset* mpHoveredAsset; private: void DefinePopups(); @@ -45,7 +46,10 @@ namespace editor void DoContentArea(ImVec2 wind_size); // Context menus + bool mbMenusOpen; void DoContentContextMenu(); + void DoHoveredContextMenu(); + void DoEmptySpaceContextMenu(); // General Helpers void HandleAssetDrop(std::filesystem::path dir); @@ -59,6 +63,7 @@ namespace editor NEW_WORLD, NEW_SCRIPT, IMPORT_IMAGE, + TRASH_ASSET, }; }; diff --git a/src/run_modes/editor/panels/editor_console.cpp b/src/run_modes/editor/panels/editor_console.cpp index 0b5ce0f..71383b5 100644 --- a/src/run_modes/editor/panels/editor_console.cpp +++ b/src/run_modes/editor/panels/editor_console.cpp @@ -15,7 +15,7 @@ namespace lunarium { namespace editor { EditorConsole::EditorConsole() : Console("Console", PanelDockZone::DDZ_BOTTOM, true, (ImGuiWindowFlags)ImGuiWindowFlags_NoCollapse), - mGraphicsDebug(false), mInfoVerbose(false) + mGraphicsDebug(false), mInfoVerbose(false), mInfoDebug(false) { } @@ -62,6 +62,13 @@ namespace lunarium { namespace editor ImGui::SameLine(); + if (ImGuiExt::CheckBoxLeft("Info Debug", &mInfoDebug)) + { + SetVerboseFlag(mInfoDebug); + } + + ImGui::SameLine(); + if (ImGui::Button("Clear")) { ClearMessageHistory(); diff --git a/src/run_modes/editor/panels/editor_console.h b/src/run_modes/editor/panels/editor_console.h index e5c44fd..3f31cb3 100644 --- a/src/run_modes/editor/panels/editor_console.h +++ b/src/run_modes/editor/panels/editor_console.h @@ -26,6 +26,7 @@ namespace lunarium { namespace editor void DoToolBar(); bool mGraphicsDebug; bool mInfoVerbose; + bool mInfoDebug; }; }} diff --git a/src/run_modes/editor/panels/properties_view.cpp b/src/run_modes/editor/panels/properties_view.cpp index 7d8c61a..16fbacb 100644 --- a/src/run_modes/editor/panels/properties_view.cpp +++ b/src/run_modes/editor/panels/properties_view.cpp @@ -16,6 +16,7 @@ #include #include #include +#include ///////////////////////////////////////////////////////////////////// // MACROS MACROS @@ -161,6 +162,22 @@ namespace lunarium { namespace editor { LUUID id = mpSelectedEntity->GetUUID(); ImGui::Text("UUID: %llu", (u64)id); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Button("Copy UUID")) + { + ImGui::SetClipboardText(std::to_string(id).c_str()); + ImGui::CloseCurrentPopup(); + } + + if (ImGui::IsKeyDown(ImGuiKey_Escape)) + { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + char buffer[256] = { 0 }; strcpy(buffer, mpSelectedEntity->GetName().c_str()); ImGui::Text("Name:"); diff --git a/src/scripting/coreAPI.cpp b/src/scripting/coreAPI.cpp index 3f06763..7eecb71 100644 --- a/src/scripting/coreAPI.cpp +++ b/src/scripting/coreAPI.cpp @@ -41,6 +41,10 @@ namespace lunarium // Register Methods sman.RegisterForeignMethod({"CoreAPI", "Core", true, "IsKeyDown(_)", (ForeignMethod)&CoreAPI::IsKeyDown}); + sman.RegisterForeignMethod({"CoreAPI", "Core", true, "LogInfo(_)", (ForeignMethod)&CoreAPI::LogInfo}); + sman.RegisterForeignMethod({"CoreAPI", "Core", true, "LogWarning(_)", (ForeignMethod)&CoreAPI::LogWarning}); + sman.RegisterForeignMethod({"CoreAPI", "Core", true, "LogError(_)", (ForeignMethod)&CoreAPI::LogError}); + sman.RegisterForeignMethod({"CoreAPI", "Core", true, "LogDebug(_)", (ForeignMethod)&CoreAPI::LogDebug}); // Generate Code std::string keys_script = GenerateWrenKeyCodes(); @@ -89,18 +93,18 @@ namespace lunarium Core::MainWindow().Resize(w, h); } - void CoreAPI::Log(int level, const char* msg) - { - switch (level) - { - case LogLevel::FATAL_ERROR: { Logger::Fatal(mpInstance->mCat, msg); break; } - case LogLevel::ERROR: { Logger::Error(mpInstance->mCat, msg); break; } - case LogLevel::WARNING: { Logger::Warn(mpInstance->mCat, msg); break; } - case LogLevel::INFO: { Logger::Info(mpInstance->mCat, msg); break; } - case LogLevel::DEBUG: { Logger::Debug(mpInstance->mCat, msg); break; } - default: { Logger::Trace(mpInstance->mCat, msg); break; } - } - } + // void CoreAPI::Log(int level, const char* msg) + // { + // switch (level) + // { + // case LogLevel::FATAL_ERROR: { Logger::Fatal(mpInstance->mCat, msg); break; } + // case LogLevel::ERROR: { Logger::Error(mpInstance->mCat, msg); break; } + // case LogLevel::WARNING: { Logger::Warn(mpInstance->mCat, msg); break; } + // case LogLevel::INFO: { Logger::Info(mpInstance->mCat, msg); break; } + // case LogLevel::DEBUG: { Logger::Debug(mpInstance->mCat, msg); break; } + // default: { Logger::Trace(mpInstance->mCat, msg); break; } + // } + // } void CoreAPI::IsKeyDown(WrenVM* vm) { @@ -108,4 +112,29 @@ namespace lunarium bool result = Core::Input().IsKeyDown((KeyCode)key_code, true); wrenSetSlotBool(vm, 0, result); } + + void CoreAPI::LogInfo(WrenVM* vm) + { + std::string msg = wrenGetSlotString(vm, 1); + Logger::Info(mpInstance->mCat, msg.c_str()); + } + + void CoreAPI::LogWarning(WrenVM* vm) + { + std::string msg = wrenGetSlotString(vm, 1); + Logger::Warn(mpInstance->mCat, msg.c_str()); + } + + void CoreAPI::LogError(WrenVM* vm) + { + std::string msg = wrenGetSlotString(vm, 1); + Logger::Error(mpInstance->mCat, msg.c_str()); + } + + void CoreAPI::LogDebug(WrenVM* vm) + { + std::string msg = wrenGetSlotString(vm, 1); + Logger::Debug(mpInstance->mCat, msg.c_str()); + } + } \ No newline at end of file diff --git a/src/scripting/coreAPI.h b/src/scripting/coreAPI.h index e2df8ee..b7b5626 100644 --- a/src/scripting/coreAPI.h +++ b/src/scripting/coreAPI.h @@ -47,7 +47,10 @@ namespace lunarium public: // API static void SetWindowSize(int w, int h); - static void Log(int level, const char* msg); + static void LogInfo(WrenVM* vm); + static void LogWarning(WrenVM* vm); + static void LogError(WrenVM* vm); + static void LogDebug(WrenVM* vm); static void IsKeyDown(WrenVM* vm); diff --git a/src/scripting/internal_scripts/components.wren b/src/scripting/internal_scripts/components.wren index 6e5f488..32f3b61 100644 --- a/src/scripting/internal_scripts/components.wren +++ b/src/scripting/internal_scripts/components.wren @@ -31,4 +31,16 @@ foreign class BlockOutComponent { // Returns the size as a list: [width, height] foreign GetSize() foreign SetSize(w, h) -} \ No newline at end of file +} + +// foreign class RigidBodyComponent { +// construct new(entity_id) {} + + +// } + +// foreign class CollisionComponent { +// construct new(entity_id) {} + + +// } \ No newline at end of file diff --git a/src/scripting/internal_scripts/core_api.wren b/src/scripting/internal_scripts/core_api.wren index e939dd4..ea8c811 100644 --- a/src/scripting/internal_scripts/core_api.wren +++ b/src/scripting/internal_scripts/core_api.wren @@ -10,4 +10,8 @@ import "KeyCodes" for KeyCodes class Core { foreign static IsKeyDown(key) + foreign static LogInfo(msg) + foreign static LogWarning(msg) + foreign static LogError(msg) + foreign static LogDebug(msg) } \ No newline at end of file diff --git a/src/scripting/internal_scripts/world_interface.wren b/src/scripting/internal_scripts/world_interface.wren index ac32e09..1aee25b 100644 --- a/src/scripting/internal_scripts/world_interface.wren +++ b/src/scripting/internal_scripts/world_interface.wren @@ -7,7 +7,7 @@ ******************************************************************************/ import "Components" for VelocityComponent, BlockOutComponent -import "CoreAPI" for CoreAPI +import "CoreAPI" for Core // Manages all of the EntityBehaviors class WorldInterface { @@ -25,6 +25,8 @@ class WorldInterface { __ScriptObjects[entity_id][script_name] = script_class.new(entity_id) //System.print("Registered script: %(script_name) to entity: %(entity_id)") + var msg = "Registered script: %(script_name) to entity: %(entity_id)" + Core.LogDebug(msg) } ///////////////////////////////////////////////////////////////////// diff --git a/src/scripting/world_api.cpp b/src/scripting/world_api.cpp index 3906819..7ba0a96 100644 --- a/src/scripting/world_api.cpp +++ b/src/scripting/world_api.cpp @@ -21,6 +21,7 @@ namespace lunarium WrenState WorldAPI::mScriptState; World* WorldAPI::mpWorld = nullptr; WorldAPI::ScriptEventHandles WorldAPI::mEventHandles; + std::vector WorldAPI::mAlreadyRanScripts; OpRes WorldAPI::Initialize(World* pWorld) { @@ -65,6 +66,7 @@ namespace lunarium void WorldAPI::Shutdown() { + mAlreadyRanScripts.clear(); mpWorld = nullptr; } @@ -76,26 +78,22 @@ namespace lunarium void WorldAPI::RegisterScript(LUUID entity, WrenScript& script) { - mScriptState.RunScript(&script); - // // Get Handle to script class type to use as second paraneter to RegisterScript - // WrenHandle* pScriptClass = mScriptState.GetWrenClassHandle("WorldInterface", script.GetScriptName()); - // std::vector params; - - // WrenParameter p; - // p.Type = WrenParamType::WPT_STR; - // p.As.String = std::to_string(entity).c_str(); - // params.push_back(p); - // p.As.String = script.GetScriptName().c_str(); - // params.push_back(p); - // p.Type = WrenParamType::WPT_HANDLE; - // p.As.Handle = pScriptClass; - // params.push_back(p); - // mScriptState.CallWrenMethod(mEventHandles.mWIRegisterScriptMethod, mEventHandles.mWIHandle, params, "WorldInterface.entity_id, script_name, script_class"); - + // Need to check if script was already run. + // In that case skip running and just make a new instance for this entity + // This allows multiple entities to have their own instances of the same script std::string script_class = script.GetScriptName(); + std::vector modules_to_load; + if (!ScriptAlreadyRan(script.GetScriptName())) + { + mScriptState.RunScript(&script); + mAlreadyRanScripts.push_back(script.GetScriptName()); + modules_to_load.push_back({"WorldInterface", "WorldInterface"}); + modules_to_load.push_back({ script_class, script_class }); + } + std::string module_name = "Register_" + script_class; std::string code = "WorldInterface.RegisterScript(\"" + std::to_string(entity) + "\", \"" + script_class + "\", " + script_class + ")"; - mScriptState.RunSnippet(module_name, {{"WorldInterface", "WorldInterface"}, { script_class, script_class }}, code); + mScriptState.RunSnippet(module_name, modules_to_load, code); } void WorldAPI::InvokeEvent(Event e, ...) @@ -118,6 +116,18 @@ namespace lunarium } } + + bool WorldAPI::ScriptAlreadyRan(std::string name) + { + for (auto iter : mAlreadyRanScripts) + { + if (iter == name) + return true; + } + + return false; + } + ///////////////////////////////////////////////////////////////////// // SCRIPT API ///////////////////////////////////////////////////////////////////// diff --git a/src/scripting/world_api.h b/src/scripting/world_api.h index e7f1b64..ba70890 100644 --- a/src/scripting/world_api.h +++ b/src/scripting/world_api.h @@ -14,6 +14,8 @@ #include #include +#include + namespace lunarium { class WorldAPI @@ -53,11 +55,14 @@ namespace lunarium // Foreign classes + private: // HELPERS + static bool ScriptAlreadyRan(std::string name); private: static WrenState mScriptState; static World* mpWorld; static ScriptEventHandles mEventHandles; + static std::vector mAlreadyRanScripts; }; } diff --git a/src/utils/helpers.cpp b/src/utils/helpers.cpp index 97fb84e..70c16bc 100644 --- a/src/utils/helpers.cpp +++ b/src/utils/helpers.cpp @@ -42,6 +42,21 @@ namespace lunarium return glsl_version; } + void System::CopyToClipboard(std::string data) + { + #ifdef WIN32 + HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, data.size() + 1); + memcpy(GlobalLock(hMem), data.c_str(), data.size() + 1); + GlobalUnlock(hMem); + OpenClipboard(0); + EmptyClipboard(); + SetClipboardData(CF_TEXT, hMem); + CloseClipboard(); + #else + + #endif // WIN32 + } + //////////////////////////////////////////////////////////// // FILE SYSTEM FUNCTIONS //////////////////////////////////////////////////////////// diff --git a/src/utils/helpers.h b/src/utils/helpers.h index 6863bef..fc913ad 100644 --- a/src/utils/helpers.h +++ b/src/utils/helpers.h @@ -23,6 +23,7 @@ namespace lunarium public: static Sizei GetScreenResolution(); static std::string GetGLSLVersionString(); + static void CopyToClipboard(std::string data); }; class FileSystem diff --git a/src/utils/uuid.cpp b/src/utils/uuid.cpp index 44c7ad7..90a8e9c 100644 --- a/src/utils/uuid.cpp +++ b/src/utils/uuid.cpp @@ -14,19 +14,6 @@ namespace lunarium std::mt19937_64 UUID::mt64(time(nullptr)); LUUID UUID::GetNewID() { - // This is kind of hacky. Should probably try to remove the need for null ids. - // LUUID id = 0; - // while (0 == id) - // { - // id = mt64(); - // } - // return id; - return mt64(); } - - // LUUID UUID::GetNullID() - // { - // return 0; - // } } \ No newline at end of file diff --git a/src/world/world.cpp b/src/world/world.cpp index a3e1197..4135a0c 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -479,6 +479,29 @@ namespace lunarium Deserialize(state.State).LogIfFailed(LogCategory::GAME_SYSTEM, "Failed to deserialize the world state"); } + ///////////////////////////////////////////////////////////////////// + // PHYSICS CALLBACKS + ///////////////////////////////////////////////////////////////////// + void World::BeginContact(b2Contact* contact) + { + + } + + void World::EndContact(b2Contact* contact) + { + + } + + void World::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) + { + + } + + void World::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) + { + + } + ///////////////////////////////////////////////////////////////////// // SERIALIZING ///////////////////////////////////////////////////////////////////// diff --git a/src/world/world.h b/src/world/world.h index 7e3336b..fda3c30 100644 --- a/src/world/world.h +++ b/src/world/world.h @@ -52,7 +52,7 @@ namespace lunarium int Index; }; - class World : public JSONSerializable + class World : public JSONSerializable, b2ContactListener { public: struct Region @@ -105,6 +105,13 @@ namespace lunarium float GetPhysicsScaleFactor() const; void SetPhysicsScaleFactor(float factor); + // Physics Callbacks + void BeginContact(b2Contact* contact); + void EndContact(b2Contact* contact); + void PreSolve(b2Contact* contact, const b2Manifold* oldManifold); + void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse); + + // Serializing [[nodiscard]] virtual OpRes Serialize(nlohmann::ordered_json& node); [[nodiscard]] virtual OpRes Deserialize(nlohmann::ordered_json& node); @@ -112,6 +119,7 @@ namespace lunarium [[nodiscard]] virtual nlohmann::ordered_json AsJSON(); + private: LUUID mUUID; std::string mName;