diff --git a/Editor/resources/Images/logo.png b/Editor/resources/Images/logo.png new file mode 100644 index 00000000..2757ae89 Binary files /dev/null and b/Editor/resources/Images/logo.png differ diff --git a/Editor/resources/Images/screenshot.png b/Editor/resources/Images/screenshot.png new file mode 100644 index 00000000..42ee0892 Binary files /dev/null and b/Editor/resources/Images/screenshot.png differ diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 871ceab8..67ec3268 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -94,7 +94,7 @@ namespace Nuake { float needed = half - used; ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - if (ImGui::Button(ICON_FA_PLAY, ImVec2(30, 30))) + if (ImGui::Button(ICON_FA_PLAY, ImVec2(30, 30)) || (Input::IsKeyPressed(GLFW_KEY_F5) && !Engine::IsPlayMode)) { SceneSnapshot = Engine::GetCurrentScene()->Copy(); Engine::EnterPlayMode(); @@ -102,7 +102,7 @@ namespace Nuake { ImGui::SameLine(); - if (ImGui::Button(ICON_FA_STOP, ImVec2(30, 30)) || Input::IsKeyPressed(297)) + if (ImGui::Button(ICON_FA_STOP, ImVec2(30, 30)) || Input::IsKeyPressed(GLFW_KEY_F8)) { Engine::ExitPlayMode(); @@ -1248,16 +1248,37 @@ namespace Nuake { void NewProject() { - if (Engine::GetProject()) + if (Engine::GetProject() && Engine::GetProject()->FileExist()) Engine::GetProject()->Save(); - + std::string selectedProject = FileDialog::SaveFile("Project file\0*.project"); - if (selectedProject == "") // Hit cancel + + if(!String::EndsWith(selectedProject, ".project")) + selectedProject += ".project"; + + if (selectedProject.empty()) // Hit cancel return; - Ref project = Project::New("Unnamed project", "no description", selectedProject + ".project"); + auto backslashSplits = String::Split(selectedProject, '\\'); + auto fileName = backslashSplits[backslashSplits.size() - 1]; + + std::string finalPath = String::Split(selectedProject, '.')[0]; + + // We need to create a folder + if (const auto& dirPath = finalPath; + !std::filesystem::create_directory(dirPath)) + { + // Should we continue? + Logger::Log("Failed creating project directory: " + dirPath); + } + + finalPath += "\\" + fileName; + + Ref project = Project::New(String::Split(fileName, '.')[0], "no description", finalPath); Engine::LoadProject(project); Engine::LoadScene(Scene::New()); + + Engine::GetCurrentWindow()->SetTitle("Nuake Engine - Editing " + project->Name); } diff --git a/Editor/src/Windows/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp index 5d6e70ac..a5a093a1 100644 --- a/Editor/src/Windows/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -9,35 +9,34 @@ #include "src/Rendering/Textures/TextureManager.h" #include "EditorInterface.h" -const std::string TEMPLATE_SCRIPT_BEGIN = "import \"Nuake:Engine\" for Engine \ -import \"Nuake:ScriptableEntity\" for ScriptableEntity \ -import \"Nuake:Input\" for Input \ -import \"Nuake:Scene\" for Scene \ -\ -class "; +const std::string TEMPLATE_SCRIPT = R"(import "Nuake:Engine" for Engine +import "Nuake:ScriptableEntity" for ScriptableEntity +import "Nuake:Input" for Input +import "Nuake:Math" for Vector3, Math +import "Nuake:Scene" for Scene -const std::string TEMPLATE_SCRIPT_END = " is ScriptableEntity {\ -construct new(){\ - _ReloadSpeed = 0.1\ - _Intensity = 0.0\ -}\ -\ -init() {\ -}\ -\ -// Updates every frame\ -update(ts) {\ -\ -}\ -\ -// Updates every tick\ -fixedUpdate(ts) {\ - \ -}\ -\ -exit() {\ -}\ -}"; +class MyEntityScript is ScriptableEntity { + construct new() { + } + + // Called when the scene gets initialized + init() { + // Engine.Log("Hello World!") + } + + // Called every update + update(ts) { + } + + // Called 90 times per second + fixedUpdate(ts) { + } + + // Called on shutdown + exit() { + } +} +)"; #include @@ -212,9 +211,29 @@ namespace Nuake { FileSystem::BeginWriteFile(path); FileSystem::WriteLine(jsonData.dump(4)); FileSystem::EndWriteFile(); + + RefreshFileBrowser(); } } + if (ImGui::MenuItem("Wren Script")) + { + std::string path = FileDialog::SaveFile("*.wren"); + if (!String::EndsWith(path, ".wren")) + { + path += ".wren"; + } + + if (!path.empty()) + { + FileSystem::BeginWriteFile(path); + FileSystem::WriteLine(TEMPLATE_SCRIPT); + FileSystem::EndWriteFile(); + + RefreshFileBrowser(); + } + } + ImGui::EndMenu(); } @@ -223,6 +242,12 @@ namespace Nuake { } + void FileSystemUI::RefreshFileBrowser() + { + FileSystem::Scan(); + m_CurrentDirectory = FileSystem::RootDirectory; + } + float h = 200; static float sz1 = 300; static float sz2 = 300; @@ -285,8 +310,7 @@ namespace Nuake { { if (ImGui::Button("Refresh")) { - FileSystem::Scan(); - m_CurrentDirectory = FileSystem::RootDirectory; + RefreshFileBrowser(); } ImGui::SameLine(); @@ -322,7 +346,6 @@ namespace Nuake { ImGui::TableNextColumn(); if (ImGui::Button("..", ImVec2(100, 100))) m_CurrentDirectory = m_CurrentDirectory->Parent; - ImGui::TableNextColumn(); i++; } @@ -330,13 +353,12 @@ namespace Nuake { { for (Ref& d : m_CurrentDirectory->Directories) { - DrawDirectory(d); - if (i + 1 % amount != 0) ImGui::TableNextColumn(); else ImGui::TableNextRow(); + DrawDirectory(d); i++; } } @@ -345,12 +367,12 @@ namespace Nuake { { for (auto f : m_CurrentDirectory->Files) { - DrawFile(f); - - if (i - 1 % amount != 0) + if (i - 1 % amount != 0 || i == 1) ImGui::TableNextColumn(); else ImGui::TableNextRow(); + + DrawFile(f); i++; } } diff --git a/Editor/src/Windows/FileSystemUI.h b/Editor/src/Windows/FileSystemUI.h index aa630bed..be528a2b 100644 --- a/Editor/src/Windows/FileSystemUI.h +++ b/Editor/src/Windows/FileSystemUI.h @@ -26,5 +26,6 @@ namespace Nuake { void DrawFile(Ref file); void DrawDirectoryExplorer(); void DrawContextMenu(); + void RefreshFileBrowser(); }; } diff --git a/Editor/src/Windows/WelcomeWindow.cpp b/Editor/src/Windows/WelcomeWindow.cpp index bab529cd..0c2040f0 100644 --- a/Editor/src/Windows/WelcomeWindow.cpp +++ b/Editor/src/Windows/WelcomeWindow.cpp @@ -3,20 +3,21 @@ #include #include "../Misc/InterfaceFonts.h" +#include #include #include -#include #include +#include +#include #include + #include #include + #include "EditorInterface.h" - #include "FileSystemUI.h" -#include - namespace Nuake { ProjectPreview::ProjectPreview(const std::string& path) @@ -33,6 +34,16 @@ namespace Nuake nlohmann::json projectJson = nlohmann::json::parse(projectFile); Name = projectJson["Name"]; Description = projectJson["Description"]; + + const std::string projectIconPath = Path + "/../icon.png"; + if (FileSystem::FileExists(projectIconPath, true)) + { + ProjectIcon = TextureManager::Get()->GetTexture(projectIconPath); + } + else + { + ProjectIcon = TextureManager::Get()->GetTexture("resources/Images/nuake-logo.png"); + } } else { @@ -65,10 +76,14 @@ namespace Nuake _Projects = std::vector(); ParseRecentFile(); + + // Load Nuake logo + _NuakeLogo = TextureManager::Get()->GetTexture(NUAKE_LOGO_PATH); } void WelcomeWindow::Draw() { + // Make viewport fullscreen ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->GetWorkPos()); ImGui::SetNextWindowSize(viewport->GetWorkSize()); @@ -78,171 +93,23 @@ namespace Nuake ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(32.0f, 32.0f)); ImGui::Begin("Welcome Screen", 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize); { + // Draw Nuake logo { - UIFont boldfont = UIFont(Fonts::Title); - - std::string text = "Nuake Engine"; - auto windowWidth = ImGui::GetWindowSize().x; - auto textWidth = ImGui::CalcTextSize(text.c_str()).x; - - ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); - ImGui::Text(text.c_str()); + const Vector2 logoSize = _NuakeLogo->GetSize(); + const ImVec2 imguiSize = ImVec2(logoSize.x, logoSize.y); + ImGui::Image((ImTextureID)_NuakeLogo->GetID(), imguiSize, ImVec2(0, 1), ImVec2(1, 0)); } + + // Add padding under logo + ImGui::Dummy(ImVec2(10, 25)); { UIFont boldfont = UIFont(Fonts::SubTitle); - std::string text = "An IdTech inspired game engine"; - auto windowWidth = ImGui::GetWindowSize().x; - auto textWidth = ImGui::CalcTextSize(text.c_str()).x; - - ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); - ImGui::Text(text.c_str()); - } - ImGui::Separator(); - { - UIFont boldfont = UIFont(Fonts::SubTitle); - ImGui::Text("Projects recently opened"); + ImGui::Text("Open recent"); } - ImVec2 projectsWindowSize = ImGui::GetContentRegionAvail(); - projectsWindowSize.x *= 0.6f; - - ImGui::BeginChild("Projects", projectsWindowSize, true); - { - const uint32_t itemHeight = 120; - - for (uint32_t i = 0; i < std::size(_Projects); i++) - { - ProjectPreview& project = _Projects[i]; - - float cursorYStart = ImGui::GetCursorPosY(); - - std::string selectableName = "##" + std::to_string(i); - bool isSelected = SelectedProject == i; - if (ImGui::Selectable(selectableName.c_str(), isSelected, ImGuiSelectableFlags_AllowItemOverlap, ImVec2(ImGui::GetContentRegionAvailWidth(), itemHeight))) - { - SelectedProject = i; - } - - ImGui::SetCursorPosY(cursorYStart); - { - UIFont boldfont = UIFont(Fonts::LargeBold); - ImGui::Text(project.Name.c_str()); - } - - { - UIFont boldfont = UIFont(Fonts::Bold); - ImGui::Text(project.Description.c_str()); - } - - ImGui::SetCursorPosY(cursorYStart + itemHeight); - } - - if (ImGui::Button("Import an existing project", ImVec2(ImGui::GetContentRegionAvailWidth(), itemHeight))) - { - std::string path = FileDialog::OpenFile("*.project"); - if (path != "") - { - bool alreadyContainsProject = false; - for (auto& p : _Projects) - { - if (p.Path == path) - alreadyContainsProject = true; - } - - if (!alreadyContainsProject) - { - _Projects.push_back(ProjectPreview(path)); - } - } - } - } - ImGui::EndChild(); - + DrawRecentProjectsSection(); ImGui::SameLine(); - - if (ImGui::BeginChild("Controls", ImGui::GetContentRegionAvail(), true)) - { - ImVec2 buttonSize = ImVec2(ImGui::GetContentRegionAvailWidth(), 58); - if (ImGui::Button("New Project", buttonSize)) - { - std::string selectedProject = FileDialog::SaveFile("Project file\0*.project"); - - if (!selectedProject.empty()) - { - auto backslashSplits = String::Split(selectedProject, '\\'); - auto fileName = backslashSplits[backslashSplits.size() - 1]; - - std::string finalPath = selectedProject; - - if (String::EndsWith(fileName, ".project")) - { - // We need to create a folder - if (const auto& dirPath = selectedProject; - std::filesystem::create_directory(dirPath)) - { - // Should we continue? - Logger::Log("Failed creating project directory: " + dirPath); - } - - finalPath += "\\" + fileName + ".project"; - } - - auto project = Project::New(fileName, "no description", finalPath); - Engine::LoadProject(project); - Engine::LoadScene(Scene::New()); - project->Save(); - - auto projectPreview = ProjectPreview(); - projectPreview.Name = project->Name; - projectPreview.Description = project->Description; - projectPreview.Path = project->FullPath; - - _Projects.push_back(projectPreview); - } - } - ImGui::Separator(); - - if (SelectedProject != -1) - { - if (ImGui::Button("Load Project", buttonSize)) - { - assert(SelectedProject < std::size(_Projects)); - - using namespace Nuake; - - SaveRecentFile(); - - std::string projectPath = _Projects[SelectedProject].Path; - FileSystem::SetRootDirectory(projectPath + "/../"); - - auto project = Project::New(); - auto projectFileData = FileSystem::ReadFile(projectPath, true); - try - { - project->Deserialize(projectFileData); - project->FullPath = projectPath; - - Engine::LoadProject(project); - - _Editor->filesystem->m_CurrentDirectory = Nuake::FileSystem::RootDirectory; - } - catch (std::exception exception) - { - Logger::Log("Error loading project: " + projectPath, CRITICAL); - Logger::Log(exception.what()); - } - - Engine::GetCurrentWindow()->SetTitle("Nuake Engine - Editing " + project->Name); - } - - if (ImGui::Button("Remove Project")) - { - _Projects.erase(_Projects.begin() + SelectedProject); - } - } - } - - ImGui::EndChild(); + DrawRightControls(); } ImGui::End(); @@ -250,6 +117,171 @@ namespace Nuake ImGui::PopStyleVar(); } + void WelcomeWindow::DrawRecentProjectsSection() + { + // Recent projects section takes up 80% of the width + ImVec2 projectsWindowSize = ImGui::GetContentRegionAvail(); + projectsWindowSize.x *= 0.8f; + + ImGui::BeginChild("Projects", projectsWindowSize, true); + { + for (uint32_t i = 0; i < std::size(_Projects); i++) + { + DrawProjectItem(i); + } + + const float itemHeight = 120.0f; + if (ImGui::Button("Import an existing project", ImVec2(ImGui::GetContentRegionAvailWidth(), itemHeight))) + { + const std::string path = FileDialog::OpenFile("Project file |*.project"); + if (path != "" && String::EndsWith(path, ".project")) + { + // Prevent importing the same project twice in the list + bool alreadyContainsProject = false; + for (auto& p : _Projects) + { + if (p.Path == path) + { + alreadyContainsProject = true; + } + } + + if (!alreadyContainsProject) + { + _Projects.push_back(ProjectPreview(path)); + } + } + } + } + ImGui::EndChild(); + } + + void WelcomeWindow::DrawProjectItem(const uint32_t itemIndex) + { + const ProjectPreview& project = _Projects[itemIndex]; + const uint32_t itemHeight = 120; + const float cursorYStart = ImGui::GetCursorPosY(); + + const std::string selectableName = "##" + std::to_string(itemIndex); + const bool isSelected = SelectedProject == itemIndex; + if (ImGui::Selectable(selectableName.c_str(), isSelected, ImGuiSelectableFlags_AllowItemOverlap, ImVec2(ImGui::GetContentRegionAvailWidth(), itemHeight))) + { + SelectedProject = itemIndex; + } + + const ImVec2 padding = ImVec2(25.0f, 20.0f); + const ImVec2 iconSize = ImVec2(100, 100); + ImGui::SetCursorPos(padding / 2.0 + ImVec2(0, cursorYStart)); + + ImGui::Image((ImTextureID)project.ProjectIcon->GetID(), iconSize, ImVec2(0, 1), ImVec2(1, 0)); + ImGui::SameLine(); + ImGui::SetCursorPosX(padding.x + iconSize.x + padding.x); + + ImGui::SetCursorPosX(padding.x + iconSize.x + padding.x); + ImGui::SetCursorPosY(cursorYStart + padding.y); + { + UIFont boldfont = UIFont(Fonts::LargeBold); + ImGui::Text(project.Name.c_str()); + } + + ImGui::SetCursorPosY(cursorYStart + padding.y + 35.f); + { + ImGui::SetCursorPosX(padding.x + iconSize.x + padding.x); + UIFont boldfont = UIFont(Fonts::Bold); + ImGui::Text(project.Description.c_str()); + } + + ImGui::SetCursorPosY(cursorYStart + itemHeight); + } + + void WelcomeWindow::DrawRightControls() + { + const float buttonHeight = 58.0f; + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0)); + if (ImGui::BeginChild("Controls", ImGui::GetContentRegionAvail(), false)) + { + const ImVec2 buttonSize = ImVec2(ImGui::GetContentRegionAvailWidth(), buttonHeight); + if (ImGui::Button("Create a new project", buttonSize)) + { + std::string selectedProject = FileDialog::SaveFile("Project file\0*.project"); + + if (!selectedProject.empty()) + { + if(!String::EndsWith(selectedProject, ".project")) + selectedProject += ".project"; + + auto backslashSplits = String::Split(selectedProject, '\\'); + auto fileName = backslashSplits[backslashSplits.size() - 1]; + + std::string finalPath = String::Split(selectedProject, '.')[0]; + + if (String::EndsWith(fileName, ".project")) + { + // We need to create a folder + if (const auto& dirPath = finalPath; + !std::filesystem::create_directory(dirPath)) + { + // Should we continue? + Logger::Log("Failed creating project directory: " + dirPath); + } + + finalPath += "\\" + fileName; + } + + auto project = Project::New(String::Split(fileName, '.')[0], "no description", finalPath); + Engine::LoadProject(project); + Engine::LoadScene(Scene::New()); + project->Save(); + + auto projectPreview = ProjectPreview(); + projectPreview.Name = project->Name; + projectPreview.Description = project->Description; + projectPreview.Path = project->FullPath; + + _Projects.push_back(projectPreview); + } + } + ImGui::Separator(); + + if (SelectedProject != -1) + { + if (ImGui::Button("Open an existing Project", buttonSize)) + { + assert(SelectedProject < std::size(_Projects)); + + using namespace Nuake; + + SaveRecentFile(); + + std::string projectPath = _Projects[SelectedProject].Path; + FileSystem::SetRootDirectory(projectPath + "/../"); + + auto project = Project::New(); + auto projectFileData = FileSystem::ReadFile(projectPath, true); + try + { + project->Deserialize(projectFileData); + project->FullPath = projectPath; + + Engine::LoadProject(project); + + _Editor->filesystem->m_CurrentDirectory = Nuake::FileSystem::RootDirectory; + } + catch (std::exception exception) + { + Logger::Log("Error loading project: " + projectPath, CRITICAL); + Logger::Log(exception.what()); + } + + Engine::GetCurrentWindow()->SetTitle("Nuake Engine - Editing " + project->Name); + } + } + } + + ImGui::EndChild(); + ImGui::PopStyleColor(); + } + void WelcomeWindow::ParseRecentFile() { if (!FileSystem::FileExists(_RecentProjectFilePath, true)) diff --git a/Editor/src/Windows/WelcomeWindow.h b/Editor/src/Windows/WelcomeWindow.h index 57ac2e0a..3117fcec 100644 --- a/Editor/src/Windows/WelcomeWindow.h +++ b/Editor/src/Windows/WelcomeWindow.h @@ -1,10 +1,13 @@ #pragma once #include +#include + #include #include namespace Nuake { + class Texture; class ProjectPreview : ISerializable { public: @@ -12,6 +15,7 @@ namespace Nuake std::string Path; std::string Description; + Ref ProjectIcon; ProjectPreview(const std::string& path); ProjectPreview() = default; @@ -19,6 +23,7 @@ namespace Nuake json Serialize() override; bool Deserialize(const std::string& data) override; + private: void ReadProjectFile(); }; @@ -27,19 +32,27 @@ namespace Nuake class WelcomeWindow { private: + const std::string NUAKE_LOGO_PATH = "resources/Images/logo_white.png"; + Ref _NuakeLogo; + EditorInterface* _Editor; + const std::string _RecentProjectFilePath = "recent.json"; const std::string _RecentProjectFileDefaultContent = "{ \"Projects\": [ ] }"; - std::vector _Projects; + uint32_t SelectedProject = 0; - EditorInterface* _Editor; - public: + std::vector _Projects; + public: WelcomeWindow(Nuake::EditorInterface* editor); ~WelcomeWindow() = default; void Draw(); private: + void DrawRecentProjectsSection(); + void DrawProjectItem(const uint32_t projectPreview); + void DrawRightControls(); + void ParseRecentFile(); void SaveRecentFile(); }; diff --git a/Nuake/src/Core/Core.h b/Nuake/src/Core/Core.h index 1072c89a..181d234a 100644 --- a/Nuake/src/Core/Core.h +++ b/Nuake/src/Core/Core.h @@ -12,6 +12,8 @@ using Ref = std::shared_ptr; template using Scope = std::unique_ptr; +template +using Weak = std::weak_ptr; template constexpr Ref CreateRef(Args&& ... args) @@ -23,4 +25,4 @@ template constexpr Scope CreateScope(Args&& ... args) { return std::make_unique(std::forward(args)...); -} \ No newline at end of file +} diff --git a/Nuake/src/Core/Physics/DynamicWorld.cpp b/Nuake/src/Core/Physics/DynamicWorld.cpp index 7e8c15c2..bb5fa6ae 100644 --- a/Nuake/src/Core/Physics/DynamicWorld.cpp +++ b/Nuake/src/Core/Physics/DynamicWorld.cpp @@ -231,7 +231,8 @@ namespace Nuake // You should definitely not call this every frame or when e.g. streaming in a new level section as it is an expensive operation. // Instead insert all new objects in batches instead of 1 at a time to keep the broad phase efficient. //_JoltPhysicsSystem->OptimizeBroadPhase(); - _JoltJobSystem = new JPH::JobSystemThreadPool(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers, std::thread::hardware_concurrency() - 1); + const uint32_t availableThreads = std::thread::hardware_concurrency() - 1; + _JoltJobSystem = new JPH::JobSystemThreadPool(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers, availableThreads); } void DynamicWorld::DrawDebug() @@ -308,6 +309,7 @@ namespace Nuake } assert("Entity doesn't have a character controller component."); + return false; } RaycastResult DynamicWorld::Raycast(glm::vec3 from, glm::vec3 to) @@ -408,11 +410,15 @@ namespace Nuake // Do 1 collision step per 1 / 60th of a second (round up). int collisionSteps = 1; constexpr float minStepDuration = 1.0f / 90.0f; + constexpr int maxStepCount = 4; if(ts > minStepDuration) { collisionSteps = static_cast(ts) / minStepDuration; } + // Prevents having too many steps and running out of jobs + collisionSteps = std::min(collisionSteps, maxStepCount); + // If you want more accurate step results you can do multiple sub steps within a collision step. Usually you would set this to 1. constexpr int subSteps = 1; diff --git a/Nuake/src/Rendering/Mesh/Mesh.cpp b/Nuake/src/Rendering/Mesh/Mesh.cpp index be49bed1..1d847f44 100644 --- a/Nuake/src/Rendering/Mesh/Mesh.cpp +++ b/Nuake/src/Rendering/Mesh/Mesh.cpp @@ -163,9 +163,16 @@ namespace Nuake for (auto& v : j["Vertices"]) { Vertex vertex; + + try { + DESERIALIZE_VEC2(v["UV"], vertex.uv) + } + catch(std::exception& e) { + vertex.uv = { 0.0, 0.0 }; + } DESERIALIZE_VEC3(v["Position"], vertex.position) DESERIALIZE_VEC3(v["Normal"], vertex.normal) - DESERIALIZE_VEC2(v["UV"], vertex.uv) + DESERIALIZE_VEC3(v["Tangent"], vertex.tangent) DESERIALIZE_VEC3(v["Bitangent"], vertex.bitangent) diff --git a/Nuake/src/Resource/Project.cpp b/Nuake/src/Resource/Project.cpp index 8cefc2f8..78c0b8f3 100644 --- a/Nuake/src/Resource/Project.cpp +++ b/Nuake/src/Resource/Project.cpp @@ -53,6 +53,11 @@ namespace Nuake projectFile.close(); } + bool Project::FileExist() + { + return std::filesystem::exists(this->FullPath.c_str()); + } + Ref Project::New(const std::string& Name, const std::string& Description, const std::string& FullPath) { return CreateRef(Name, Description, FullPath); diff --git a/Nuake/src/Resource/Project.h b/Nuake/src/Resource/Project.h index da025243..ee3fb232 100644 --- a/Nuake/src/Resource/Project.h +++ b/Nuake/src/Resource/Project.h @@ -26,6 +26,7 @@ namespace Nuake void Save(); void SaveAs(const std::string& FullPath); + bool FileExist(); static Ref New(const std::string& Name, const std::string& Description, const std::string& FullPath); static Ref New(); diff --git a/Nuake/src/Scene/Environment/ProceduralSky.cpp b/Nuake/src/Scene/Environment/ProceduralSky.cpp index 72f9cd94..ff45bd2c 100644 --- a/Nuake/src/Scene/Environment/ProceduralSky.cpp +++ b/Nuake/src/Scene/Environment/ProceduralSky.cpp @@ -102,17 +102,29 @@ namespace Nuake json ProceduralSky::Serialize() { BEGIN_SERIALIZE() - SERIALIZE_VAL(SurfaceRadius); + SERIALIZE_VAL(SurfaceRadius); SERIALIZE_VAL(AtmosphereRadius); SERIALIZE_VEC3(RayleighScattering); SERIALIZE_VEC3(MieScattering); SERIALIZE_VAL(SunIntensity); SERIALIZE_VEC3(SunDirection); + SERIALIZE_VEC3(CenterPoint); END_SERIALIZE(); } bool ProceduralSky::Deserialize(const std::string& str) { - return false; + BEGIN_DESERIALIZE() + DESERIALIZE_VEC3(j["SunDirection"], SunDirection) + DESERIALIZE_VEC3(j["RayleighScattering"], RayleighScattering) + DESERIALIZE_VEC3(j["MieScattering"], MieScattering) + if (j.contains("CenterPoint")) + { + DESERIALIZE_VEC3(j["CenterPoint"], CenterPoint) + } + SurfaceRadius = j["SurfaceRadius"]; + AtmosphereRadius = j["AtmosphereRadius"]; + SunIntensity = j["SunIntensity"]; + return true; } } diff --git a/Nuake/src/Scene/Lighting/Environment.cpp b/Nuake/src/Scene/Lighting/Environment.cpp index 72b68a83..741753f1 100644 --- a/Nuake/src/Scene/Lighting/Environment.cpp +++ b/Nuake/src/Scene/Lighting/Environment.cpp @@ -68,6 +68,11 @@ namespace Nuake { VolumetricFog = j["VolumetricFog"]; if (j.contains("VolumetricStepCount")) VolumetricStepCount = j["VolumetricStepCount"]; + if (j.contains("ProceduralSkybox")) + { + ProceduralSkybox->Deserialize(j["ProceduralSkybox"].dump()); + } + return false; } } diff --git a/README.md b/README.md index 9047d0c4..677d6686 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,47 @@ -![Nuake](http://antoinepilote.com/assets/NUAKE.png) # Nuake -Feel free to join the discord server for updates: +![Nuake](Editor/resources/Images/logo.png) -[![Support Server](https://img.shields.io/discord/852625335236558868.svg?label=Discord&logo=Discord&colorB=7289da&style=for-the-badge)](https://discord.gg/kuF4efPK7Y) -# What is it -Nuake is a game engine written from scratch by myself. It is not meant to be a end-all be-all engine and it is not a quakespasm type engine. This is a game engine that focuses on fast level design iteration that integrates with quake level editing software. If you can create quake maps, you can create Nuake levels. -`Warning: It is still very early in development and I dont recommend anyone using this to make their games *yet*. ` +## Quake inspired game engine +Nuake is a game engine currently in developement that focuses on fast level design iteration time that integrates with quake level editing software. +> It is currently in developement and is not feature complete. We are currently aiming for an alpha release with basic features and a demo level. -# How to build +![Nuake](Editor/resources/Images/screenshot.png) + + +You can join the discord server for updates and screenshots or if you want to contribute: + +[![Join Server](https://img.shields.io/discord/852625335236558868.svg?label=Discord&logo=Discord&colorB=7289da&style=for-the-badge)](https://discord.gg/kuF4efPK7Y) + + +## Current Features +- ECS system +- Modern physic engine (Jolt physic) +- PBR Renderer +- Post processing effects(Bloom, SSAO, SSR, Volumetrics, Procedural Sky) +- Wren Scripting +- Trenchbroom integration + +## Planned features +- C# Scripting +- Custom Shaders +- Spatialized audio +- NuakeUI integration +- Dynamic global illumination +- Asset packing +- Terrain editor +- WAD converter + +## Contributing +We are currently looking for contributors, feel free to join the discord if you are looking to help the project. + +## Compiling the engine 1. Clone the repos using `git clone --recurse-submodules https://github.com/antopilo/Nuake.git` 2. Run the `generate.bat` to generate the sln files. 3. Open `Nuake.sln` 4. Build and run -# Contributing -Feel free to make pull requests and I will look over them myself. +# Documentation and demos +> The current documentation is not up to date. -# Documentation -You can access the current documentation at [here](https://nuake.readthedocs.io/en/latest/index.html) +You can access the current documentation [here](https://nuake.readthedocs.io/en/latest/index.html). -# Features -- Trenchbroom integration with live reload -- fast ECS & Scene tree system -- Jolt physics -- PBR rendering -- Volumetric lighting -- Parallax mapping -- Game in editor -- Procedural & HDR skies -- Modern UI system -- Wren scripting api and module system -- Triggers and entity editing in TB - -# Planned -- Advanced physics features - - Soft bodies, Joints, etc. -- Demo level -- Cross platform -- Optimization -- Water simulation -- Terrain editing -- Exporting -- Custom shaders diff --git a/nuake.4coder b/nuake.4coder deleted file mode 100644 index fc2bd712..00000000 --- a/nuake.4coder +++ /dev/null @@ -1,65 +0,0 @@ -version(1); -project_name = "4coder custom"; - -patterns = { -"*.c", -"*.cpp", -"*.h", -"*.m", -"*.mm", -"*.bat", -"*.sh", -"*.4coder", -"*.txt", -}; -blacklist_patterns = { -".*", -}; -load_paths_custom = { - {"."}, -}; -load_paths = { - { load_paths_custom, .os = "win" }, - { load_paths_custom, .os = "linux"}, - { load_paths_custom, .os = "mac" }, -}; - -build_super_x64_win32 = "custom\\bin\\buildsuper_x64-win.bat"; -build_super_x86_win32 = "custom\\bin\\buildsuper_x86-win.bat"; -build_super_x64_linux = "custom/bin/buildsuper_x64-linux.sh"; -build_super_x86_linux = "custom/bin/buildsuper_x86-linux.sh"; -build_super_x64_mac = "custom/bin/buildsuper_x64-mac.sh"; - -command_list = { - { .name = "build super x64", - .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, - .cmd = { {build_super_x64_win32, .os ="win" }, - {build_super_x64_linux , .os ="linux"}, - {build_super_x64_mac , .os ="mac" }, }, }, - - { .name = "build super x86", - .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, - .cmd = { {build_super_x86_win32, .os ="win" }, - {build_super_x86_linux, .os ="linux" }, }, }, - - { .name = "build C++ lexer generator", - .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, - .cmd = { {"custom\\bin\\build_one_time custom\\languages\\4coder_cpp_lexer_gen.cpp ..\\build", .os ="win" }, - }, }, - - { .name = "build token tester", - .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, - .cmd = { {"custom\\bin\\build_one_time custom\\languages\\4coder_cpp_lexer_test.cpp ..\\build", .os = "win" }, - }, }, - - { .name = "run one time", - .out = "*run*", .footer_panel = false, .save_dirty_files = false, - .cmd = { {"pushd ..\\build & one_time", .os = "win" }, - }, }, -}; - -fkey_command[1] = "build super x64"; -fkey_command[2] = "build C++ lexer generator"; -fkey_command[3] = "build token tester"; -fkey_command[4] = "run one time"; -fkey_command[5] = "build super x86";