From 407ff89df7baafb686628f1e88894d454840f3ca Mon Sep 17 00:00:00 2001 From: antopilo Date: Tue, 28 Jun 2022 19:56:16 -0400 Subject: [PATCH] Refactor Mesh serialization and model system. --- Editor/src/Windows/EditorInterface.cpp | 12 +- Editor/src/Windows/WelcomeWindow.cpp | 13 +- Nuake/Model.cpp | 6 + Nuake/Model.h | 27 ++ Nuake/src/Rendering/Camera.cpp | 4 +- Nuake/src/Rendering/Mesh/Mesh.cpp | 54 +++- Nuake/src/Rendering/SceneRenderer.cpp | 12 +- Nuake/src/Rendering/Textures/Material.cpp | 35 +-- Nuake/src/Rendering/Textures/Material.h | 60 ++++- Nuake/src/Resource/Model.cpp | 74 ++++++ Nuake/src/Resource/Model.h | 27 ++ Nuake/src/Resource/ModelLoader.cpp | 225 +++++++++++++++++ Nuake/src/Resource/ModelLoader.h | 37 +++ Nuake/src/Resource/Project.cpp | 4 +- Nuake/src/Resource/ResourceManager.h | 11 + Nuake/src/Resource/Serializable.h | 7 + .../src/Scene/Components/BSPBrushComponent.h | 10 +- Nuake/src/Scene/Components/MeshComponent.cpp | 230 +----------------- Nuake/src/Scene/Components/MeshComponent.h | 32 ++- Nuake/src/Scene/Scene.cpp | 9 +- Nuake/src/Scene/Systems/QuakeMapBuilder.cpp | 10 +- 21 files changed, 612 insertions(+), 287 deletions(-) create mode 100644 Nuake/Model.cpp create mode 100644 Nuake/Model.h create mode 100644 Nuake/src/Resource/Model.cpp create mode 100644 Nuake/src/Resource/Model.h create mode 100644 Nuake/src/Resource/ModelLoader.cpp create mode 100644 Nuake/src/Resource/ModelLoader.h diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 806881ae..5fbc9220 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -823,9 +823,9 @@ namespace Nuake { // m_SelectedEntity = scene->GetAllEntities().at(0); //} + } ImGui::EndChild(); - ImGui::Separator(); // Draw a tree of entities. ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(26.f / 255.0f, 26.f / 255.0f, 26.f / 255.0f, 1)); @@ -870,9 +870,10 @@ namespace Nuake { } } - ImGui::EndTable(); + ImGui::EndTable(); + } - ImGui::EndChild(); + ImGui::EndChild(); ImGui::PopStyleColor(); if (ImGui::BeginDragDropTarget()) // Drag n drop new prefab file into scene tree @@ -1410,6 +1411,10 @@ namespace Nuake { if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1))) { std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (texture != "") + { + m_SelectedMaterial->SetMetalness(TextureManager::Get()->GetTexture(texture)); + } } ImGui::SameLine(); //ImGui::Checkbox("Use##4", &m_SelectedMaterial->data.u_HasMetalness); @@ -1424,6 +1429,7 @@ namespace Nuake { if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec2(2, 2), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) { std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + m_SelectedMaterial->SetRoughness(TextureManager::Get()->GetTexture(texture)); } ImGui::SameLine(); //ImGui::Checkbox("Use##5", &m_SelectedMaterial->data.u_HasRoughness); diff --git a/Editor/src/Windows/WelcomeWindow.cpp b/Editor/src/Windows/WelcomeWindow.cpp index 44ee2ace..21ccd803 100644 --- a/Editor/src/Windows/WelcomeWindow.cpp +++ b/Editor/src/Windows/WelcomeWindow.cpp @@ -199,14 +199,17 @@ namespace Nuake auto project = Project::New(); auto projectFileData = FileSystem::ReadFile(projectPath, true); - if (!project->Deserialize(projectFileData)) + try { + project->Deserialize(projectFileData); + project->FullPath = projectPath; + Engine::LoadProject(project); + } + catch (std::exception exception) { Logger::Log("Error loading project: " + projectPath, CRITICAL); - return; + Logger::Log(exception.what()); } - - project->FullPath = projectPath; - Engine::LoadProject(project); + Engine::GetCurrentWindow()->SetTitle("Nuake Engine - Editing " + project->Name); } diff --git a/Nuake/Model.cpp b/Nuake/Model.cpp new file mode 100644 index 00000000..9d41f438 --- /dev/null +++ b/Nuake/Model.cpp @@ -0,0 +1,6 @@ +#include "src/Resource/Model.h" + +namespace Nuake +{ + +} \ No newline at end of file diff --git a/Nuake/Model.h b/Nuake/Model.h new file mode 100644 index 00000000..51682b0a --- /dev/null +++ b/Nuake/Model.h @@ -0,0 +1,27 @@ +#pragma once +#include "src/Core/Core.h" + +#include "src/Resource/Resource.h" +#include "src/Resource/Serializable.h" + +namespace Nuake +{ + class Mesh; + + class Model : Resource, ISerializable + { + private: + std::vector> m_Meshes; + + public: + Model(); + ~Model(); + + bool LoadModel(const std::string& path); + + std::vector>& GetMeshes(); + + json Serialize() override; + bool Deserialize(const std::string& data) override; + }; +} \ No newline at end of file diff --git a/Nuake/src/Rendering/Camera.cpp b/Nuake/src/Rendering/Camera.cpp index 6dbe6600..56a3360b 100644 --- a/Nuake/src/Rendering/Camera.cpp +++ b/Nuake/src/Rendering/Camera.cpp @@ -39,8 +39,8 @@ namespace Nuake void Camera::OnWindowResize(int x, int y) { AspectRatio = (float)x / (float)y; - float width = y * (16 * 9); - float height = y; + float width = (float)y * (16.0f * 9.0f); + float height = (float)y; } void Camera::SetDirection(Vector3 direction) diff --git a/Nuake/src/Rendering/Mesh/Mesh.cpp b/Nuake/src/Rendering/Mesh/Mesh.cpp index d7bc71c3..a21ce6a1 100644 --- a/Nuake/src/Rendering/Mesh/Mesh.cpp +++ b/Nuake/src/Rendering/Mesh/Mesh.cpp @@ -116,23 +116,65 @@ namespace Nuake j["Material"] = m_Material->Serialize(); j["Indices"] = m_Indices; - for (unsigned int i = 0; i < m_Vertices.size(); i++) + json v; + for (uint32_t i = 0; i < m_Vertices.size(); i++) { - j["Vertices"][i]["Position"] = SERIALIZE_VEC3(m_Vertices[i].position); - j["Vertices"][i]["Normal"] = SERIALIZE_VEC3(m_Vertices[i].normal); - j["Vertices"][i]["UV"] = SERIALIZE_VEC2(m_Vertices[i].uv); - j["Vertices"][i]["Tangent"] = SERIALIZE_VEC3(m_Vertices[i].tangent); - j["Vertices"][i]["Bitangent"] = SERIALIZE_VEC3(m_Vertices[i].bitangent); + v["Position"]["x"] = m_Vertices[i].position.x; + v["Position"]["y"] = m_Vertices[i].position.y; + v["Position"]["z"] = m_Vertices[i].position.z; + + v["UV"]["x"] = m_Vertices[i].uv.x; + v["UV"]["y"] = m_Vertices[i].uv.y; + + v["Normal"]["x"] = m_Vertices[i].normal.x; + v["Normal"]["y"] = m_Vertices[i].normal.y; + v["Normal"]["z"] = m_Vertices[i].normal.z; + + v["Tangent"]["x"] = m_Vertices[i].tangent.x; + v["Tangent"]["y"] = m_Vertices[i].tangent.y; + v["Tangent"]["z"] = m_Vertices[i].tangent.z; + + v["Bitangent"]["x"] = m_Vertices[i].bitangent.x; + v["Bitangent"]["y"] = m_Vertices[i].bitangent.y; + v["Bitangent"]["z"] = m_Vertices[i].bitangent.z; + + j["Vertices"][i] = v; } + END_SERIALIZE(); } bool Mesh::Deserialize(const std::string& str) { BEGIN_DESERIALIZE(); + + m_Material = CreateRef(); + m_Material->Deserialize(j["Material"].dump()); + std::vector indices; + for (auto& i : j["Indices"]) + { + indices.push_back(i); + } + m_Indices = indices; + std::vector vertices; + for (auto& v : j["Vertices"]) + { + Vertex vertex; + 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) + + vertices.push_back(vertex); + } + + m_Vertices = vertices; + + SetupMesh(); return true; } } diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index ebc7a29f..9c5dc151 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -144,7 +144,7 @@ namespace Nuake { for (auto e : meshView) { auto [transform, mesh] = meshView.get(e); - for (auto& m : mesh.meshes) + for (auto& m : mesh.ModelResource->GetMeshes()) Renderer::SubmitMesh(m, transform.GetGlobalTransform()); } @@ -183,11 +183,16 @@ namespace Nuake { for (auto e : view) { auto [transform, mesh, parent] = view.get(e); - for (auto& m : mesh.meshes) - Renderer::SubmitMesh(m, transform.GetGlobalTransform()); + + if (mesh.ModelResource) + { + for (auto& m : mesh.ModelResource->GetMeshes()) + Renderer::SubmitMesh(m, transform.GetGlobalTransform()); + } } glCullFace(GL_BACK); + RenderCommand::Disable(RendererEnum::FACE_CULL); Renderer::Flush(gBufferShader, false); auto quakeView = scene.m_Registry.view(); @@ -201,7 +206,6 @@ namespace Nuake { for (auto& b : model.Meshes) Renderer::SubmitMesh(b, transform.GetGlobalTransform()); } - glCullFace(GL_FRONT); Renderer::Flush(gBufferShader, false); } mGBuffer->Unbind(); diff --git a/Nuake/src/Rendering/Textures/Material.cpp b/Nuake/src/Rendering/Textures/Material.cpp index 55cf1b56..f68785cd 100644 --- a/Nuake/src/Rendering/Textures/Material.cpp +++ b/Nuake/src/Rendering/Textures/Material.cpp @@ -20,6 +20,16 @@ namespace Nuake Ref Material::m_DefaultMetalness; Ref Material::m_DefaultDisplacement; + Material::Material() + { + InitDefaultTextures(); + InitUniformBuffer(); + + glGenBuffers(1, &UBO); + glBindBuffer(GL_UNIFORM_BUFFER, UBO); + glBufferData(GL_UNIFORM_BUFFER, sizeof(UBOStructure), NULL, GL_STATIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } Material::Material(const std::string albedo) { @@ -43,21 +53,12 @@ namespace Nuake } m_Name = albedo; - - if (m_DefaultAO == nullptr) - m_DefaultAO = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); - if (m_DefaultNormal == nullptr) - m_DefaultNormal = TextureManager::Get()->GetTexture("resources/Textures/default/defaultNormal.png"); - if (m_DefaultDisplacement == nullptr) - m_DefaultDisplacement = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); - if (m_DefaultRoughness == nullptr) - m_DefaultRoughness = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); - if (m_DefaultMetalness == nullptr) - m_DefaultMetalness = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); + InitDefaultTextures(); } Material::Material(const glm::vec3 albedoColor) { + InitDefaultTextures(); InitUniformBuffer(); glGenBuffers(1, &UBO); @@ -69,11 +70,15 @@ namespace Nuake m_Name = "New material"; + m_Albedo = m_DefaultAlbedo; + } + + Material::~Material() {} + + void Material::InitDefaultTextures() + { if (m_DefaultAlbedo == nullptr) m_DefaultAlbedo = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); - - m_Albedo = m_DefaultAlbedo; - if (m_DefaultAO == nullptr) m_DefaultAO = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); if (m_DefaultNormal == nullptr) @@ -86,8 +91,6 @@ namespace Nuake m_DefaultMetalness = TextureManager::Get()->GetTexture("resources/Textures/default/Default.png"); } - Material::~Material() {} - void Material::Bind(Shader* shader) { //if (MaterialManager::Get()->CurrentlyBoundedMaterial == m_Name) diff --git a/Nuake/src/Rendering/Textures/Material.h b/Nuake/src/Rendering/Textures/Material.h index eadbaa58..b7a2c71d 100644 --- a/Nuake/src/Rendering/Textures/Material.h +++ b/Nuake/src/Rendering/Textures/Material.h @@ -6,7 +6,8 @@ #include "src/Rendering/Textures/TextureManager.h" #include "Texture.h" #include - +#include "src/Resource/Resource.h" +#include "src/Core/FileSystem.h" namespace Nuake { @@ -27,7 +28,7 @@ namespace Nuake int u_Unlit; }; - class Material : ISerializable + class Material : ISerializable, public Resource { private: std::string m_Name; @@ -75,6 +76,8 @@ namespace Nuake Material(const glm::vec3 albedoColor); ~Material(); + void InitDefaultTextures(); + void Bind(Shader* shader); void SetupUniformBuffer(); @@ -111,11 +114,10 @@ namespace Nuake json Serialize() override { BEGIN_SERIALIZE(); - j["Path"] = this->m_Name; j["HasAlbedo"] = this->HasAlbedo(); if (HasAlbedo()) { - j["Abledo"] = this->m_Albedo->Serialize(); + j["Albedo"] = this->m_Albedo->Serialize(); } j["HasAO"] = this->HasAO(); j["HasMetalness"] = this->HasMetalness(); @@ -128,6 +130,56 @@ namespace Nuake bool Deserialize(const std::string& str) override { + BEGIN_DESERIALIZE(); + + if (j.contains("Path")) + { + this->Path = j["Path"]; + if (FileSystem::FileExists(FileSystem::Root + Path)) + { + std::string content = FileSystem::ReadFile(Path); + Deserialize(content); + } + } + else + { + if (j.contains("Albedo")) + { + Ref albedoTexture = TextureManager::Get()->GetTexture(j["Albedo"]["Path"]); + SetAlbedo(albedoTexture); + } + + if (j.contains("Normal")) + { + Ref normalTexture = TextureManager::Get()->GetTexture(j["Normal"]["Path"]); + SetMetalness(normalTexture); + } + + if (j.contains("AO")) + { + Ref aoTexture = TextureManager::Get()->GetTexture(j["AO"]["Path"]); + SetAO(aoTexture); + } + + if (j.contains("Metalness")) + { + Ref metalTexture = TextureManager::Get()->GetTexture(j["Metalness"]["Path"]); + SetMetalness(metalTexture); + } + + if (j.contains("Roughness")) + { + Ref metalTexture = TextureManager::Get()->GetTexture(j["Roughness"]["Path"]); + SetRoughness(metalTexture); + } + + if (j.contains("Displacement")) + { + Ref displacementTexture = TextureManager::Get()->GetTexture(j["Displacement"]["Path"]); + SetDisplacement(displacementTexture); + } + } + return true; } }; diff --git a/Nuake/src/Resource/Model.cpp b/Nuake/src/Resource/Model.cpp new file mode 100644 index 00000000..563dbc03 --- /dev/null +++ b/Nuake/src/Resource/Model.cpp @@ -0,0 +1,74 @@ +#include "src/Resource/Model.h" +#include "src/Core/FileSystem.h" +#include "src/Core/Logger.h" +#include "src/Rendering/Mesh/Mesh.h" + +#include "src/Resource/ModelLoader.h" + +namespace Nuake +{ + Model::Model(const std::string path) : m_Meshes(std::vector>()) + { + this->Path = path; + } + + Model::Model() : m_Meshes(std::vector>()) + {} + + Model::~Model() {} + + void Model::AddMesh(Ref mesh) + { + m_Meshes.push_back(mesh); + } + + std::vector>& Model::GetMeshes() + { + return m_Meshes; + } + + json Model::Serialize() + { + BEGIN_SERIALIZE(); + + if (this->Path != "") + { + j["Path"] = this->Path; + } + else + { + for (uint32_t i = 0; i < std::size(m_Meshes); i++) + { + j["Meshes"][i] = m_Meshes[i]->Serialize(); + } + } + END_SERIALIZE(); + } + + bool Model::Deserialize(const std::string& str) + { + BEGIN_DESERIALIZE(); + if (j.contains("Path")) + { + this->IsEmbedded = true; + + ModelLoader loader; + auto otherModel = loader.LoadModel(j["Path"]); + m_Meshes = otherModel->GetMeshes(); + + this->Path = j["Path"]; + } + else + { + for (auto& m : j["Meshes"]) + { + Ref mesh = CreateRef(); + mesh->Deserialize(m.dump()); + + m_Meshes.push_back(mesh); + } + } + + return true; + } +} \ No newline at end of file diff --git a/Nuake/src/Resource/Model.h b/Nuake/src/Resource/Model.h new file mode 100644 index 00000000..89db3d04 --- /dev/null +++ b/Nuake/src/Resource/Model.h @@ -0,0 +1,27 @@ +#pragma once +#include "src/Core/Core.h" + +#include "src/Resource/Resource.h" +#include "src/Resource/Serializable.h" +#include "src/Rendering/Mesh/Mesh.h" +namespace Nuake +{ + + class Model : public Resource, ISerializable + { + private: + std::vector> m_Meshes; + + public: + Model(); + Model(const std::string path); + ~Model(); + + void AddMesh(Ref mesh); + std::vector>& GetMeshes(); + + json Serialize() override; + bool Deserialize(const std::string& data) override; + + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp new file mode 100644 index 00000000..d044a060 --- /dev/null +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -0,0 +1,225 @@ +#include "src/Resource/ModelLoader.h" + +#include "src/Core/FileSystem.h" +#include "src/Core/Logger.h" + +#include "src/Core/String.h" + +#include "src/Resource/Model.h" +namespace Nuake +{ + ModelLoader::ModelLoader() {} + ModelLoader::~ModelLoader() {} + + Ref ModelLoader::LoadModel(const std::string& path) + { + Ref model = CreateRef(path); + + Assimp::Importer import; + import.SetPropertyFloat("PP_GSN_MAX_SMOOTHING_ANGLE", 90); + + auto importFlags = + aiProcess_Triangulate | + aiProcess_GenSmoothNormals | + aiProcess_FixInfacingNormals | + aiProcess_CalcTangentSpace; + + modelDir = path + "/../"; + const aiScene* scene = import.ReadFile(FileSystem::Root + path, importFlags); + if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) + { + std::string assimpErrorMsg = std::string(import.GetErrorString()); + std::string logMsg = "[Failed to load model] - " + assimpErrorMsg; + Logger::Log(logMsg, WARNING); + + return model; + } + + ProcessNode(scene->mRootNode, scene); + + for (const auto& mesh : m_Meshes) + { + model->AddMesh(mesh); + } + + return model; + } + + void ModelLoader::ProcessNode(aiNode* node, const aiScene* scene) + { + for (uint32_t i = 0; i < node->mNumMeshes; i++) + { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + m_Meshes.push_back(ProcessMesh(mesh, scene)); + } + + for (uint32_t i = 0; i < node->mNumChildren; i++) + { + ProcessNode(node->mChildren[i], scene); + } + } + + Ref ModelLoader::ProcessMesh(aiMesh* node, const aiScene* scene) + { + auto vertices = ProcessVertices(node); + auto indices = ProcessIndices(node); + auto material = ProcessMaterials(scene, node); + + Ref mesh = CreateRef(); + mesh->AddSurface(vertices, indices); + mesh->SetMaterial(material); + + return mesh; + } + + std::vector ModelLoader::ProcessVertices(aiMesh* mesh) + { + auto vertices = std::vector(); + for (uint32_t i = 0; i < mesh->mNumVertices; i++) + { + Vertex vertex; + vertex.texture = 1.0f; + + Vector3 current; + + // Position + current.x = mesh->mVertices[i].x; + current.y = mesh->mVertices[i].y; + current.z = mesh->mVertices[i].z; + vertex.position = current; + + // Normals + current.x = mesh->mNormals[i].x; + current.y = mesh->mNormals[i].y; + current.z = mesh->mNormals[i].z; + vertex.normal = current; + + // Tangents + if (mesh->mTangents) + { + current.x = mesh->mTangents[i].x; + current.y = mesh->mTangents[i].y; + current.z = mesh->mTangents[i].z; + vertex.tangent = current; + } + + if (mesh->mBitangents) + { + current.x = mesh->mBitangents[i].x; + current.y = mesh->mBitangents[i].y; + current.z = mesh->mBitangents[i].z; + vertex.bitangent = current; + } + + vertex.uv = glm::vec2(0.0f, 0.0f); + + // Does it contain UVs? + if (mesh->mTextureCoords[0]) + { + float u = mesh->mTextureCoords[0][i].x; + float v = mesh->mTextureCoords[0][i].y; + vertex.uv = Vector2(u, v); + } + + vertices.push_back(vertex); + } + + return vertices; + } + + std::vector ModelLoader::ProcessIndices(aiMesh* mesh) + { + auto indices = std::vector(); + for (uint32_t i = 0; i < mesh->mNumFaces; i++) + { + aiFace face = mesh->mFaces[i]; + for (uint32_t j = 0; j < face.mNumIndices; j++) + { + indices.push_back(face.mIndices[j]); + } + } + + return indices; + } + + Ref ModelLoader::ProcessMaterials(const aiScene* scene, aiMesh* mesh) + { + if (mesh->mMaterialIndex < 0) + return nullptr; + + aiMaterial* materialNode = scene->mMaterials[mesh->mMaterialIndex]; + + Ref material = CreateRef(); + + aiString str; + if (materialNode->GetTextureCount(aiTextureType_DIFFUSE) > 0) + { + materialNode->GetTexture(aiTextureType_DIFFUSE, 0, &str); + Ref albedoTexture = ProcessTextures(scene, str.C_Str()); + material->SetAlbedo(albedoTexture); + } + + if (materialNode->GetTextureCount(aiTextureType_NORMALS) > 0) + { + materialNode->GetTexture(aiTextureType_NORMALS, 0, &str); + Ref albedoTexture = ProcessTextures(scene, str.C_Str()); + material->SetNormal(albedoTexture); + } + + if (materialNode->GetTextureCount(aiTextureType_METALNESS) > 0) + { + materialNode->GetTexture(aiTextureType_METALNESS, 0, &str); + Ref albedoTexture = ProcessTextures(scene, str.C_Str()); + material->SetMetalness(albedoTexture); + } + + if (materialNode->GetTextureCount(aiTextureType_AMBIENT_OCCLUSION) > 0) + { + materialNode->GetTexture(aiTextureType_AMBIENT_OCCLUSION, 0, &str); + Ref albedoTexture = ProcessTextures(scene, str.C_Str()); + material->SetAO(albedoTexture); + } + + if (materialNode->GetTextureCount(aiTextureType_DIFFUSE_ROUGHNESS) > 0) + { + materialNode->GetTexture(aiTextureType_DIFFUSE_ROUGHNESS, 0, &str); + Ref albedoTexture = ProcessTextures(scene, str.C_Str()); + material->SetRoughness(albedoTexture); + } + + if (materialNode->GetTextureCount(aiTextureType_DISPLACEMENT) > 0) + { + materialNode->GetTexture(aiTextureType_DISPLACEMENT, 0, &str); + Ref albedoTexture = ProcessTextures(scene, str.C_Str()); + material->SetDisplacement(albedoTexture); + } + + return material; + } + + Ref ModelLoader::ProcessTextures(const aiScene* scene, const std::string& path) + { + // Load embedded textures, a texture is embedded is the path + // starts with a '*'. + if (String::BeginsWith(path, "*")) + { + uint32_t textureIndex = std::atoi(String::Split(path, '*')[1].c_str()); + const aiTexture* aitexture = scene->GetEmbeddedTexture(path.c_str()); + + Vector2 textureSize = Vector2(aitexture->mWidth, aitexture->mHeight); + auto texture = CreateRef(textureSize, (unsigned char*)aitexture->pcData, textureSize.x); + return texture; + } + + std::string texturePath = FileSystem::Root + modelDir + path; + if (!FileSystem::FileExists(texturePath)) + { + std::string textureNotFoundmsg = "Texture file couldn't be found: " + texturePath; + Logger::Log(textureNotFoundmsg, Nuake::LOG_TYPE::WARNING); + + texturePath = "resources/Textures/default/Default.png"; + } + + return TextureManager::Get()->GetTexture(texturePath); + } +} \ No newline at end of file diff --git a/Nuake/src/Resource/ModelLoader.h b/Nuake/src/Resource/ModelLoader.h new file mode 100644 index 00000000..ecec8214 --- /dev/null +++ b/Nuake/src/Resource/ModelLoader.h @@ -0,0 +1,37 @@ +#pragma once +#include "src/Core/Core.h" + +#include "src/Rendering/Mesh/Mesh.h" +#include "src/Rendering/Textures/Material.h" +#include "src/Rendering/Textures/Texture.h" + +#include "src/Rendering/Vertex.h" + +#include "assimp/Importer.hpp" +#include +#include + +namespace Nuake +{ + class Model; + class ModelLoader + { + public: + ModelLoader(); + ~ModelLoader(); + + Ref LoadModel(const std::string& path); + + private: + std::string modelDir; + std::vector> m_Meshes; + + void ProcessNode(aiNode* node, const aiScene* scene); + Ref ProcessMesh(aiMesh* node, const aiScene* scene); + + std::vector ProcessVertices(aiMesh* mesh); + std::vector ProcessIndices(aiMesh* mesh); + Ref ProcessMaterials(const aiScene* scene, aiMesh* mesh); + Ref ProcessTextures(const aiScene* scene, const std::string& path); + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/Project.cpp b/Nuake/src/Resource/Project.cpp index fc5f019a..14ad4e25 100644 --- a/Nuake/src/Resource/Project.cpp +++ b/Nuake/src/Resource/Project.cpp @@ -131,11 +131,13 @@ namespace Nuake if (scenePath == "") // Not set correctly. return true; + if (!FileSystem::FileExists(FileSystem::Root + scenePath)) + return true; + std::string sceneContent = FileSystem::ReadFile(scenePath, false); if (!DefaultScene->Deserialize(sceneContent)) { Logger::Log("Error loading scene: " + scenePath, CRITICAL); - return false; } DefaultScene->Path = scenePath; diff --git a/Nuake/src/Resource/ResourceManager.h b/Nuake/src/Resource/ResourceManager.h index 3d7c133a..d286ce35 100644 --- a/Nuake/src/Resource/ResourceManager.h +++ b/Nuake/src/Resource/ResourceManager.h @@ -15,5 +15,16 @@ namespace Nuake { template static Ref LoadResource(const std::string& path); + + void RegisterResource(Ref resource) + { + m_Resources[resource->Id] = resource; + } + + template + static Ref GetResource(const UUID& uuid) + { + return reinterpret_pointer_cast>(m_Resources[uuid]); + } }; } \ No newline at end of file diff --git a/Nuake/src/Resource/Serializable.h b/Nuake/src/Resource/Serializable.h index 9991725a..ddb6b57a 100644 --- a/Nuake/src/Resource/Serializable.h +++ b/Nuake/src/Resource/Serializable.h @@ -19,6 +19,13 @@ using json = nlohmann::json; SERIALIZE_VEC3(v) \ j[#v]["w"] = this->v.z; +#define DESERIALIZE_VEC3(v, p) \ + p = Vector3(v["x"], v["y"], v["z"]); + +#define DESERIALIZE_VEC2(v, p) \ + p = Vector2(v["x"], v["y"]); + + #define SERIALIZE_OBJECT(v) j[#v] = v->Serialize(); #define SERIALIZE_OBJECT_REF(v) j[#v] = v.Serialize(); #define SERIALIZE_OBJECT_REF_LBL(lbl, v) j[lbl] = v.Serialize(); diff --git a/Nuake/src/Scene/Components/BSPBrushComponent.h b/Nuake/src/Scene/Components/BSPBrushComponent.h index 3db5e2d4..4a038c19 100644 --- a/Nuake/src/Scene/Components/BSPBrushComponent.h +++ b/Nuake/src/Scene/Components/BSPBrushComponent.h @@ -11,7 +11,7 @@ namespace Nuake { { public: std::vector> Meshes; - std::vector< Ref> Materials; + std::vector> Materials; std::vector> Rigidbody; std::string target = ""; @@ -33,7 +33,7 @@ namespace Nuake { { BEGIN_SERIALIZE(); - for (unsigned int i = 0; i < Meshes.size(); i++) + for (uint32_t i = 0; i < Meshes.size(); i++) { j["Meshes"][i] = Meshes[i]->Serialize(); } @@ -41,9 +41,13 @@ namespace Nuake { END_SERIALIZE(); } - bool Deserialize() + bool Deserialize(const std::string& str) { + BEGIN_DESERIALIZE(); + + + return true; } }; } diff --git a/Nuake/src/Scene/Components/MeshComponent.cpp b/Nuake/src/Scene/Components/MeshComponent.cpp index 93a8fb95..7d3f7159 100644 --- a/Nuake/src/Scene/Components/MeshComponent.cpp +++ b/Nuake/src/Scene/Components/MeshComponent.cpp @@ -1,231 +1,21 @@ +#include "src/Resource/ModelLoader.h" #include "MeshComponent.h" +#include "src/Rendering/Mesh/Mesh.h" +#include "src/Rendering/Textures/TextureManager.h" #include "src/Rendering/Textures/Material.h" #include "src/Rendering/Renderer.h" -#include "src/Rendering/Textures/TextureManager.h" #include namespace Nuake { + MeshComponent::MeshComponent() + { + + } + void MeshComponent::LoadModel() { - this->meshes.clear(); - Assimp::Importer import; - import.SetPropertyFloat("PP_GSN_MAX_SMOOTHING_ANGLE", 90); - const aiScene* scene = import.ReadFile(FileSystem::Root + ModelPath, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | aiProcess_CalcTangentSpace); - - - directory = ""; - std::vector path = String::Split(ModelPath, '/'); - for (int i = 0; i < path.size(); i++) - if (i < path.size() - 1) - directory += path[i] + '/'; - - if (scene->HasTextures()) - { - int textureCount = scene->mNumTextures; - for (unsigned int i = 0; i < textureCount; i++) - { - scene->mTextures[i]; - } - } - if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) - { - Logger::Log("ASSIMP! Failed to load model" + std::string(import.GetErrorString()), CRITICAL); - return; - } - - ProcessNode(scene->mRootNode, scene); - } - - void MeshComponent::ProcessNode(aiNode* node, const aiScene* scene) - { - // process all the node's meshes (if any) - for (unsigned int i = 0; i < node->mNumMeshes; i++) - { - aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; - meshes.push_back(ProcessMesh(mesh, scene)); - } - // then do the same for each of its children - for (unsigned int i = 0; i < node->mNumChildren; i++) - { - ProcessNode(node->mChildren[i], scene); - } - } - - Ref MeshComponent::ProcessMesh(aiMesh* mesh, const aiScene* scene) - { - std::vector vertices; - std::vector indices; - std::vector textures; - - for (unsigned int i = 0; i < mesh->mNumVertices; i++) - { - Vertex vertex; - vertex.texture = 1.0f; - - glm::vec3 vector; - vector.x = mesh->mVertices[i].x; - vector.y = mesh->mVertices[i].y; - vector.z = mesh->mVertices[i].z; - vertex.position = vector; - - vector.x = mesh->mNormals[i].x; - vector.y = mesh->mNormals[i].y; - vector.z = mesh->mNormals[i].z; - vertex.normal = vector; - - if (mesh->mTangents) - { - vector.x = mesh->mTangents[i].x; - vector.y = mesh->mTangents[i].y; - vector.z = mesh->mTangents[i].z; - vertex.tangent = vector; - } - - if (mesh->mBitangents) - { - vector.x = mesh->mBitangents[i].x; - vector.y = mesh->mBitangents[i].y; - vector.z = mesh->mBitangents[i].z; - vertex.bitangent = vector; - } - - - if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates? - { - glm::vec2 vec; - vec.x = mesh->mTextureCoords[0][i].x; - vec.y = mesh->mTextureCoords[0][i].y; - vertex.uv = vec; - } - else - vertex.uv = glm::vec2(0.0f, 0.0f); - - vertices.push_back(vertex); - } - // process indices - for (unsigned int i = 0; i < mesh->mNumFaces; i++) - { - aiFace face = mesh->mFaces[i]; - for (unsigned int j = 0; j < face.mNumIndices; j++) - indices.push_back(face.mIndices[j]); - } - - // process material - if (mesh->mMaterialIndex < 0) - return nullptr; - - aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; - std::string materialPath = directory + std::to_string(mesh->mMaterialIndex) + material->GetName().C_Str(); - Ref newMaterial = MaterialManager::Get()->GetMaterial(materialPath); - - aiString str; - - unsigned int textureCount = material->GetTextureCount(aiTextureType_DIFFUSE); - material->GetTexture(aiTextureType_DIFFUSE, 0, &str); - - // Embedded texture - if (String::BeginsWith(str.C_Str(), "*")) - { - int textureIndex = std::atoi(String::Split(str.C_Str(), '*')[1].c_str()); - const aiTexture* texture = scene->GetEmbeddedTexture(str.C_Str()); - - Ref newTexture = CreateRef(Vector2(texture->mWidth, texture->mHeight), (unsigned char*)texture->pcData, texture->mWidth); - newMaterial->SetAlbedo(newTexture); - } - else - { - std::string texturePath = FileSystem::Root + directory + str.C_Str(); - if (!FileSystem::FileExists(texturePath)) - { - Logger::Log("Texture file couldn't be found: " + texturePath, Nuake::LOG_TYPE::CRITICAL); - texturePath = "resources/Textures/default/Default.png"; - } - newMaterial->SetAlbedo(TextureManager::Get()->GetTexture(texturePath)); - } - - material->GetTexture(aiTextureType_NORMALS, 0, &str); - if (String::BeginsWith(str.C_Str(), "*")) - { - int textureIndex = std::atoi(String::Split(str.C_Str(), '*')[1].c_str()); - const aiTexture* texture = scene->GetEmbeddedTexture(str.C_Str()); - - Ref newTexture = CreateRef(Vector2(texture->mWidth, texture->mHeight), (unsigned char*)texture->pcData, texture->mWidth); - newMaterial->SetNormal(newTexture); - } - else - { - newMaterial->SetNormal(TextureManager::Get()->GetTexture(FileSystem::Root + directory + str.C_Str())); - } - //newMaterial->SetNormal(TextureManager::Get()->GetTexture(directory + str.C_Str())); - - material->GetTexture(aiTextureType_METALNESS, 0, &str); - if (String::BeginsWith(str.C_Str(), "*")) - { - int textureIndex = std::atoi(String::Split(str.C_Str(), '*')[1].c_str()); - const aiTexture* texture = scene->GetEmbeddedTexture(str.C_Str()); - - Ref newTexture = CreateRef(Vector2(texture->mWidth, texture->mHeight), (unsigned char*)texture->pcData, texture->mWidth); - newMaterial->SetMetalness(newTexture); - } - else - { - newMaterial->SetMetalness(TextureManager::Get()->GetTexture(FileSystem::Root + directory + str.C_Str())); - } - //newMaterial->SetMetalness(TextureManager::Get()->GetTexture(directory + str.C_Str())); - - material->GetTexture(aiTextureType_DIFFUSE_ROUGHNESS, 0, &str); - if (String::BeginsWith(str.C_Str(), "*")) - { - int textureIndex = std::atoi(String::Split(str.C_Str(), '*')[1].c_str()); - const aiTexture* texture = scene->GetEmbeddedTexture(str.C_Str()); - - Ref newTexture = CreateRef(Vector2(texture->mWidth, texture->mHeight), (unsigned char*)texture->pcData, texture->mWidth); - newMaterial->SetRoughness(newTexture); - } - else - { - newMaterial->SetRoughness(TextureManager::Get()->GetTexture(FileSystem::Root + directory + str.C_Str())); - } - //newMaterial->SetRoughness(TextureManager::Get()->GetTexture(directory + str.C_Str())); - - //material->GetTexture(aiTextureType_DISPLACEMENT, 0, &str); - //newMaterial->SetDisplacement(TextureManager::Get()->GetTexture(directory + str.C_Str())); - - material->GetTexture(aiTextureType_AMBIENT_OCCLUSION, 0, &str); - if (String::BeginsWith(str.C_Str(), "*")) - { - int textureIndex = std::atoi(String::Split(str.C_Str(), '*')[1].c_str()); - const aiTexture* texture = scene->GetEmbeddedTexture(str.C_Str()); - - Ref newTexture = CreateRef(Vector2(texture->mWidth, texture->mHeight), (unsigned char*)texture->pcData, texture->mWidth); - newMaterial->SetAO(newTexture); - } - else - { - newMaterial->SetAO(TextureManager::Get()->GetTexture(FileSystem::Root + directory + str.C_Str())); - } - //newMaterial->SetAO(TextureManager::Get()->GetTexture(directory + str.C_Str())); - - Ref nuakeMesh = CreateRef(); - nuakeMesh->AddSurface(vertices, indices); - nuakeMesh->SetMaterial(newMaterial); - - return nuakeMesh; - } - - std::vector MeshComponent::LoadMaterialTextures(aiMaterial* mat, aiTextureType type) - { - std::vector textures; - for (unsigned int i = 0; i < mat->GetTextureCount(type); i++) - { - aiString str; - mat->GetTexture(type, i, &str); - std::string fixedStr = std::string(str.C_Str()); - - Texture* texture = new Texture(directory + fixedStr); - textures.push_back(texture); - } - return textures; + auto loader = ModelLoader(); + this->ModelResource = loader.LoadModel(ModelPath); } } diff --git a/Nuake/src/Scene/Components/MeshComponent.h b/Nuake/src/Scene/Components/MeshComponent.h index 2883d80c..54e25865 100644 --- a/Nuake/src/Scene/Components/MeshComponent.h +++ b/Nuake/src/Scene/Components/MeshComponent.h @@ -1,40 +1,29 @@ #pragma once -#include #include -#include "src/Rendering/Mesh/Mesh.h" -#include "src/Rendering/Textures/Texture.h" - #include "src/Resource/Serializable.h" -#include "assimp/Importer.hpp" -#include -#include +#include "src/Resource/Model.h" + #include namespace Nuake { struct MeshComponent { + Ref ModelResource; std::string ModelPath; - MeshComponent() - { - //loadModel(path); - } + MeshComponent(); void LoadModel(); - void Draw(); - std::vector> meshes; + std::string directory; - void ProcessNode(aiNode* node, const aiScene* scene); - Ref ProcessMesh(aiMesh* mesh, const aiScene* scene); - std::vector LoadMaterialTextures(aiMaterial* mat, aiTextureType type); - json Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(ModelPath); + SERIALIZE_OBJECT(ModelResource); END_SERIALIZE(); } @@ -42,7 +31,14 @@ namespace Nuake { BEGIN_DESERIALIZE(); ModelPath = j["ModelPath"]; - LoadModel(); + ModelResource = CreateRef(); + + if (j.contains("ModelResource")) + { + auto res = j["ModelResource"]; + ModelResource->Deserialize(res.dump()); + } + return true; } }; diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 38a5ccd8..adf30ea6 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -263,10 +263,11 @@ namespace Nuake { bool Scene::SaveAs(const std::string& path) { - std::ofstream sceneFile; - sceneFile.open(FileSystem::Root + path); - sceneFile << Serialize().dump(4); - sceneFile.close(); + std::string fileContent = Serialize().dump(4); + + FileSystem::BeginWriteFile(FileSystem::Root + path); + FileSystem::WriteLine(fileContent); + FileSystem::EndWriteFile(); Logger::Log("Scene saved successfully"); return true; diff --git a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp index 035f13b8..9bbeccae 100644 --- a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp +++ b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp @@ -23,6 +23,7 @@ extern "C" { #include "src/Resource/FGD/FGDClass.h" #include "src/Scene/Components/WrenScriptComponent.h" #include "src/Scene/Components/PrefabComponent.h" +#include "src/Scene/Components/MeshComponent.h" #include #include @@ -498,6 +499,7 @@ namespace Nuake { TransformComponent& transformComponent = brushEntity.GetComponent(); BSPBrushComponent& bsp = brushEntity.AddComponent(); + bsp.IsSolid = true; bsp.IsTransparent = false; bsp.IsFunc = false; @@ -580,6 +582,8 @@ namespace Nuake { } } + Ref model = CreateRef(); + // Batching process for (auto& mat : m_StaticWorld) { @@ -601,8 +605,12 @@ namespace Nuake { mesh->AddSurface(batchedVertices, batchedIndices); mesh->SetMaterial(mat.first); - bsp.Meshes.push_back(mesh); + model->AddMesh(mesh); + //bsp.Meshes.push_back(mesh); } + + MeshComponent& modelComponent = brushEntity.AddComponent(); + modelComponent.ModelResource = model; } isEntity = false;