diff --git a/libs/ImguiExtension/panels/MaterialPanel.cpp b/libs/ImguiExtension/panels/MaterialPanel.cpp index b498b07d4..8d783e865 100644 --- a/libs/ImguiExtension/panels/MaterialPanel.cpp +++ b/libs/ImguiExtension/panels/MaterialPanel.cpp @@ -10,16 +10,16 @@ namespace Atlas::ImguiExtension { auto padding = 8.0f; auto widthAfterImage = availableWidth - padding - ImGui::GetTextLineHeight(); - auto renderWithImagePreview = [&](Ref& texture, std::function element) { - if (texture != nullptr) { - UIElements::TexturePreview(wrapper, *texture); + auto renderWithImagePreview = [&](ResourceHandle& texture, std::function element) { + if (texture.IsLoaded()) { + UIElements::TexturePreview(wrapper, *texture.Get()); ImGui::SameLine(); // Calculate next item width and push a width with the image elements width substracted from it auto width = ImGui::CalcItemWidth(); ImGui::PushItemWidth(width - padding - ImGui::GetTextLineHeightWithSpacing()); } element(); - if (texture != nullptr) + if (texture.IsLoaded()) ImGui::PopItemWidth(); }; diff --git a/src/demo/App.h b/src/demo/App.h index ccf5e8bb8..7478acea7 100644 --- a/src/demo/App.h +++ b/src/demo/App.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/editor/App.h b/src/editor/App.h index b80212ff8..1c96fc61c 100644 --- a/src/editor/App.h +++ b/src/editor/App.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/editor/DataCreator.cpp b/src/editor/DataCreator.cpp index f25486db3..2eeadef80 100644 --- a/src/editor/DataCreator.cpp +++ b/src/editor/DataCreator.cpp @@ -1,6 +1,6 @@ #include "DataCreator.h" -#include "loader/ModelLoader.h" +#include "loader/ModelImporter.h" #include "volume/AABB.h" namespace Atlas::Editor { diff --git a/src/editor/FileImporter.h b/src/editor/FileImporter.h index b5038fd39..ec0aaf8eb 100644 --- a/src/editor/FileImporter.h +++ b/src/editor/FileImporter.h @@ -13,7 +13,7 @@ #include "scripting/Script.h" #include "Font.h" -#include "loader/ModelLoader.h" +#include "loader/ModelImporter.h" #include "Content.h" #include "Serializer.h" diff --git a/src/engine/Material.cpp b/src/engine/Material.cpp index 287db5600..0b74ecd13 100644 --- a/src/engine/Material.cpp +++ b/src/engine/Material.cpp @@ -10,43 +10,43 @@ namespace Atlas { bool Material::HasBaseColorMap() const { - return baseColorMap ? true : false; + return baseColorMap.IsValid(); } bool Material::HasOpacityMap() const { - return opacityMap ? true : false; + return opacityMap.IsValid(); } bool Material::HasNormalMap() const { - return normalMap ? true : false; + return normalMap.IsValid(); } bool Material::HasRoughnessMap() const { - return roughnessMap ? true : false; + return roughnessMap.IsValid(); } bool Material::HasMetalnessMap() const { - return metalnessMap ? true : false; + return metalnessMap.IsValid(); } bool Material::HasAoMap() const { - return aoMap ? true : false; + return aoMap.IsValid(); } bool Material::HasDisplacementMap() const { - return displacementMap ? true : false; + return displacementMap.IsValid(); } diff --git a/src/engine/Material.h b/src/engine/Material.h index 4358371a6..d987b31f9 100644 --- a/src/engine/Material.h +++ b/src/engine/Material.h @@ -6,6 +6,7 @@ #include "texture/Texture2DArray.h" #include "loader/ImageLoader.h" #include "pipeline/PipelineConfig.h" +#include "resource/Resource.h" #include "common/Ref.h" #include @@ -29,13 +30,13 @@ namespace Atlas { std::string name; - Ref baseColorMap = nullptr; - Ref opacityMap = nullptr; - Ref normalMap = nullptr; - Ref roughnessMap = nullptr; - Ref metalnessMap = nullptr; - Ref aoMap = nullptr; - Ref displacementMap = nullptr; + ResourceHandle baseColorMap; + ResourceHandle opacityMap; + ResourceHandle normalMap; + ResourceHandle roughnessMap; + ResourceHandle metalnessMap; + ResourceHandle aoMap; + ResourceHandle displacementMap; vec3 baseColor = vec3(1.0f); vec3 transmissiveColor = vec3(0.0f); @@ -56,14 +57,6 @@ namespace Atlas { float tiling = 1.0f; - std::string baseColorMapPath; - std::string opacityMapPath; - std::string normalMapPath; - std::string roughnessMapPath; - std::string metalnessMapPath; - std::string aoMapPath; - std::string displacementMapPath; - bool twoSided = false; bool vertexColors = false; diff --git a/src/engine/Serializer.cpp b/src/engine/Serializer.cpp index 039db6135..b9cc17c32 100644 --- a/src/engine/Serializer.cpp +++ b/src/engine/Serializer.cpp @@ -7,6 +7,10 @@ #include "loader/AssetLoader.h" #include "loader/TerrainLoader.h" +#include "loader/MeshLoader.h" +#include "loader/MaterialLoader.h" + +#include namespace Atlas { @@ -31,6 +35,26 @@ namespace Atlas { fileStream << (formatJson ? j.dump(2) : j.dump()); } + if (saveDependencies) { + auto meshes = scene->GetMeshes(); + std::map> materials; + + for (const auto& mesh : meshes) { + if (!mesh.IsLoaded()) continue; + + Loader::MeshLoader::SaveMesh(mesh.Get(), mesh.GetResource()->path); + + for (const auto& material : mesh->data.materials) + materials[material.GetID()] = material; + } + + for (const auto& [_, material] : materials) { + if (!material.IsLoaded()) continue; + + Loader::MaterialLoader::SaveMaterial(material.Get(), material.GetResource()->path); + } + } + fileStream.close(); } diff --git a/src/engine/common/Image.h b/src/engine/common/Image.h index 920c4404a..089d70cea 100644 --- a/src/engine/common/Image.h +++ b/src/engine/common/Image.h @@ -197,6 +197,13 @@ namespace Atlas { */ void GammaToLinear(); + /** + * Converts the image data from linear to gamma color space. + * @note Converting the image data will result in a loss of data + * of the mipmap chain. Call GenerateMipmap() to generate it again. + */ + void LinearToGamma(); + /** * Flips image data horizontally. * @note Flipping the image data will result in a loss of data @@ -394,6 +401,8 @@ namespace Atlas { ImageFormat fileFormat = ImageFormat::PNG; std::string fileName = ""; + bool srgbConversion = false; + private: std::vector> mipLevels; @@ -758,6 +767,27 @@ namespace Atlas { } + template + void Image::LinearToGamma() { + + auto& data = mipLevels[0].data; + int32_t size = int32_t(data.size()); + + auto invMaxPixelValue = 1.0f / MaxPixelValue(); + bool hasAlpha = channels == 4; + + for (int32_t i = 0; i < size; i++) { + // Don't correct the alpha values + if (hasAlpha && (i + 1) % 4 == 0) continue; + + float value = float(data[i]) * invMaxPixelValue; + value = powf(value, 1.0f / 2.2f); + + data[i] = T(value * MaxPixelValue()); + } + + } + template void Image::FlipHorizontally() { diff --git a/src/engine/lighting/LightingSerializer.cpp b/src/engine/lighting/LightingSerializer.cpp index 6bdbe8dfa..fa3814796 100644 --- a/src/engine/lighting/LightingSerializer.cpp +++ b/src/engine/lighting/LightingSerializer.cpp @@ -136,6 +136,7 @@ namespace Atlas::Lighting { {"rt", p.rt}, {"ddgi", p.ddgi}, {"useShadowMap", p.useShadowMap}, + {"useNormalMaps", p.useNormalMaps}, {"opacityCheck", p.opacityCheck}, {"halfResolution", p.halfResolution} }; @@ -153,11 +154,46 @@ namespace Atlas::Lighting { j.at("rt").get_to(p.rt); j.at("ddgi").get_to(p.ddgi); j.at("useShadowMap").get_to(p.useShadowMap); + j.at("useNormalMaps").get_to(p.useNormalMaps); j.at("opacityCheck").get_to(p.opacityCheck); try_get_json(j, "halfResolution", p.halfResolution); try_get_json(j, "roughnessCutoff", p.roughnessCutoff); } + void to_json(json& j, const RTGI& p) { + j = json{ + {"textureLevel", p.textureLevel}, + {"radianceLimit", p.radianceLimit}, + {"bias", p.bias}, + {"spatialFilterStrength", p.spatialFilterStrength}, + {"temporalWeight", p.temporalWeight}, + {"historyClipMax", p.historyClipMax}, + {"currentClipFactor", p.currentClipFactor}, + {"enable", p.enable}, + {"ddgi", p.ddgi}, + {"useShadowMap", p.useShadowMap}, + {"useNormalMap", p.useNormalMaps}, + {"opacityCheck", p.opacityCheck}, + {"halfResolution", p.halfResolution} + }; + } + + void from_json(const json& j, RTGI& p) { + j.at("textureLevel").get_to(p.textureLevel); + j.at("radianceLimit").get_to(p.radianceLimit); + j.at("bias").get_to(p.bias); + j.at("spatialFilterStrength").get_to(p.spatialFilterStrength); + j.at("temporalWeight").get_to(p.temporalWeight); + j.at("historyClipMax").get_to(p.historyClipMax); + j.at("currentClipFactor").get_to(p.currentClipFactor); + j.at("enable").get_to(p.enable); + j.at("ddgi").get_to(p.ddgi); + j.at("useShadowMap").get_to(p.useShadowMap); + j.at("useNormalMap").get_to(p.useNormalMaps); + j.at("opacityCheck").get_to(p.opacityCheck); + try_get_json(j, "halfResolution", p.halfResolution); + } + void to_json(json& j, const ShadowView& p) { j = json { {"nearDistance", p.nearDistance}, diff --git a/src/engine/lighting/LightingSerializer.h b/src/engine/lighting/LightingSerializer.h index b21043ac9..b49b63c4e 100644 --- a/src/engine/lighting/LightingSerializer.h +++ b/src/engine/lighting/LightingSerializer.h @@ -5,6 +5,7 @@ #include "Shadow.h" #include "AO.h" #include "SSGI.h" +#include "RTGI.h" #include "EnvironmentProbe.h" #include "SSS.h" #include "IrradianceVolume.h" @@ -40,6 +41,10 @@ namespace Atlas::Lighting { void from_json(const json& j, Reflection& p); + void to_json(json& j, const RTGI& p); + + void from_json(const json& j, RTGI& p); + void to_json(json& j, const ShadowView& p); void from_json(const json& j, ShadowView& p); diff --git a/src/engine/loader/ImageLoader.h b/src/engine/loader/ImageLoader.h index 935207faa..7f6a1a21a 100644 --- a/src/engine/loader/ImageLoader.h +++ b/src/engine/loader/ImageLoader.h @@ -103,6 +103,7 @@ namespace Atlas { } image.fileName = normalizedFileName; + image.srgbConversion = colorSpaceConversion; Log::Message("Loaded image " + normalizedFileName); @@ -128,6 +129,12 @@ namespace Atlas { return; } + /* + if (image->srgbConversion) { + image->LinearToGamma(); + } + */ + auto lambda = [](void* context, void* data, int32_t size) { auto imageStream = (std::ofstream*)context; diff --git a/src/engine/loader/MaterialLoader.cpp b/src/engine/loader/MaterialLoader.cpp index 1313b1c49..8bfc705db 100644 --- a/src/engine/loader/MaterialLoader.cpp +++ b/src/engine/loader/MaterialLoader.cpp @@ -1,281 +1,65 @@ #include "MaterialLoader.h" #include "AssetLoader.h" -#include "ImageLoader.h" -#include "../common/Path.h" -#include "../Log.h" -#include -#include +#include "mesh/MeshSerializer.h" -namespace Atlas { +namespace Atlas::Loader { - namespace Loader { - Ref MaterialLoader::LoadMaterial(std::string filename, int32_t mapResolution) { + Ref MaterialLoader::LoadMaterial(const std::string& filename, bool binaryJson) { - auto stream = AssetLoader::ReadFile(filename, std::ios::in | std::ios::binary); + Loader::AssetLoader::UnpackFile(filename); + auto path = Loader::AssetLoader::GetFullPath(filename); - if (!stream.is_open()) { - Log::Error("Failed to load material " + filename); - return nullptr; - } - - int32_t textureCount = 0; - auto material = LoadMaterialValues(stream, textureCount); - - if (!material) { - Log::Error("File isn't a material file " + filename); - return nullptr; - } - - auto materialDirectory = Common::Path::GetDirectory(filename); - - std::string line; - for (int32_t i = 0; i < textureCount; i++) { - std::getline(stream, line); - auto prefix = line.substr(0, 3); - if (prefix == "BMP") { - material->baseColorMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->baseColorMapPath, true, 4); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->baseColorMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->baseColorMap->SetData(image->GetData()); - } - if (prefix == "OMP") { - material->opacityMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->opacityMapPath, false, 1); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->baseColorMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->baseColorMap->SetData(image->GetData()); - } - else if (prefix == "NMP") { - material->normalMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->normalMapPath, false, 4); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->normalMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8G8B8A8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->normalMap->SetData(image->GetData()); - } - else if (prefix == "RMP") { - material->roughnessMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->roughnessMapPath, false, 1); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->roughnessMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->roughnessMap->SetData(image->GetData()); - } - else if (prefix == "MMP") { - material->metalnessMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->metalnessMapPath, false, 1); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->metalnessMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->metalnessMap->SetData(image->GetData()); - } - else if (prefix == "AMP") { - material->aoMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->aoMapPath, false, 1); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->aoMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->aoMap->SetData(image->GetData()); - } - else if (prefix == "DMP") { - material->displacementMapPath = ReadFilePath(line, materialDirectory); - auto image = ImageLoader::LoadImage(material->displacementMapPath, false, 1); - if ((image->width != mapResolution || image->height != mapResolution) && mapResolution) - image->Resize(mapResolution, mapResolution); - material->displacementMap = std::make_shared(image->width, image->height, - VK_FORMAT_R8_UNORM, Texture::Wrapping::ClampToEdge, Texture::Filtering::Anisotropic); - material->displacementMap->SetData(image->GetData()); - } - } - - stream.close(); - - return material; - - } - - void MaterialLoader::SaveMaterial(Ref material, std::string filename) { - - auto stream = AssetLoader::WriteFile(filename, std::ios::out | std::ios::binary); - - if (!stream.is_open()) { - Log::Error("Failed to save material " + filename); - return; - } - - std::string header, body; - int32_t textureCount = 0; - - header.append("AEM "); - - textureCount += material->HasBaseColorMap() ? 1 : 0; - textureCount += material->HasNormalMap() ? 1 : 0; - textureCount += material->HasRoughnessMap() ? 1 : 0; - textureCount += material->HasMetalnessMap() ? 1 : 0; - textureCount += material->HasAoMap() ? 1 : 0; - textureCount += material->HasDisplacementMap() ? 1 : 0; - - header.append(std::to_string(textureCount) + "\n"); - - stream << header; - - body.append("N " + material->name + "\n"); - - body.append(WriteVector("BC", material->baseColor)); - body.append(WriteVector("EC", material->emissiveColor)); - body.append(WriteVector("TC", material->transmissiveColor)); - - body.append("RN " + std::to_string(material->roughness) + "\n"); - body.append("MN " + std::to_string(material->metalness) + "\n"); - body.append("AO " + std::to_string(material->ao) + "\n"); - body.append("RF " + std::to_string(material->reflectance) + "\n"); - body.append("NS " + std::to_string(material->normalScale) + "\n"); - body.append("DS " + std::to_string(material->displacementScale) + "\n"); - body.append("TL " + std::to_string(material->tiling) + "\n"); - - stream << body; - stream << "\n"; - - auto materialPath = AssetLoader::GetFullPath(filename); - - if (material->HasBaseColorMap()) - stream << "BMP " + Common::Path::GetRelative(materialPath, material->baseColorMapPath) + "\n"; - if (material->HasOpacityMap()) - stream << "OMP " + Common::Path::GetRelative(materialPath, material->opacityMapPath) + "\n"; - if (material->HasNormalMap()) - stream << "NMP " + Common::Path::GetRelative(materialPath, material->normalMapPath) + "\n"; - if (material->HasRoughnessMap()) - stream << "RMP " + Common::Path::GetRelative(materialPath, material->roughnessMapPath) + "\n"; - if (material->HasMetalnessMap()) - stream << "MMP " + Common::Path::GetRelative(materialPath, material->metalnessMapPath) + "\n"; - if (material->HasAoMap()) - stream << "AMP " + Common::Path::GetRelative(materialPath, material->aoMapPath) + "\n"; - if (material->HasDisplacementMap()) - stream << "DMP " + Common::Path::GetRelative(materialPath, material->displacementMapPath) + "\n"; - - stream.close(); + auto fileStream = Loader::AssetLoader::ReadFile(path, std::ios::in | std::ios::binary); + if (!fileStream.is_open()) { + throw ResourceLoadException(filename, "Couldn't open material file stream"); } - Ref MaterialLoader::LoadMaterialValues(std::ifstream& stream, int32_t& textureCount) { - - auto material = std::make_shared(); - std::string header, line; - - std::getline(stream, header); - - if (header.compare(0, 4, "AEM ") != 0) { - return nullptr; - } - - size_t lastPosition = 4; - auto position = header.find_first_of('\n', lastPosition); - textureCount = std::stoi(header.substr(lastPosition, position - lastPosition)); - - std::getline(stream, line); - - lastPosition = line.find_first_of(' '); - position = line.find_first_of("\r\n", lastPosition) - 1; - material->name = line.substr(lastPosition + 1, position - lastPosition); - - std::getline(stream, line); - - while (line != "" && line != "\r") { - auto prefix = line.substr(0, 2); - - if (prefix == "BC") { - material->baseColor = ReadVector(line); - } - else if (prefix == "EC") { - material->emissiveColor = ReadVector(line); - } - else if (prefix == "TC") { - material->transmissiveColor = ReadVector(line); - } - else if (prefix == "RN") { - material->roughness = ReadFloat(line); - } - else if (prefix == "MN") { - material->metalness = ReadFloat(line); - } - else if (prefix == "AO") { - material->ao = ReadFloat(line); - } - else if (prefix == "RF") { - material->reflectance = ReadFloat(line); - } - else if (prefix == "NS") { - material->normalScale = ReadFloat(line); - } - else if (prefix == "DS") { - material->displacementScale = ReadFloat(line); - } - else if (prefix == "TL") { - material->tiling = ReadFloat(line); - } - - std::getline(stream, line); - } - - return material; - + json j; + if (binaryJson) { + auto data = Loader::AssetLoader::GetFileContent(fileStream); + j = json::from_bjdata(data); } - - std::string MaterialLoader::WriteVector(std::string prefix, vec3 vector) { - - return prefix + " " + std::to_string(vector.r) + " " + - std::to_string(vector.g) + " " + - std::to_string(vector.b) + "\n"; - + else { + std::string serialized((std::istreambuf_iterator(fileStream)), + std::istreambuf_iterator()); + j = json::parse(serialized); } - vec3 MaterialLoader::ReadVector(std::string line) { + fileStream.close(); - vec3 vector; + auto material = CreateRef(); + from_json(j, *material); - auto lastPosition = line.find_first_of(' ') + 1; - auto position = line.find_first_of(' ', lastPosition); - vector.x = std::stof(line.substr(lastPosition, position - lastPosition)); + return material; - lastPosition = position + 1; - position = line.find_first_of(' ', lastPosition); - vector.y = std::stof(line.substr(lastPosition, position - lastPosition)); + } - lastPosition = position + 1; - position = line.find_first_of("\r\n", lastPosition); - vector.z = std::stof(line.substr(lastPosition, position - lastPosition)); + void MaterialLoader::SaveMaterial(const Ref& material, const std::string& filename, + bool binaryJson, bool formatJson) { - return vector; + auto path = Loader::AssetLoader::GetFullPath(filename); + auto fileStream = Loader::AssetLoader::WriteFile(path, std::ios::out | std::ios::binary); + if (!fileStream.is_open()) { + Log::Error("Couldn't write material file " + filename); + return; } - float MaterialLoader::ReadFloat(std::string line) { - - auto lastPosition = line.find_first_of(' ') + 1; - auto position = line.find_first_of("\r\n", lastPosition); - return std::stof(line.substr(lastPosition, position - lastPosition)); + json j; + to_json(j, *material); + if (binaryJson) { + auto data = json::to_bjdata(j); + fileStream.write(reinterpret_cast(data.data()), data.size()); } - - std::string MaterialLoader::ReadFilePath(std::string line, std::string materialDirectory) { - - auto lastPosition = line.find_first_of(' ') + 1; - auto position = line.find_first_of("\r\n", lastPosition); - auto string = line.substr(lastPosition, position - lastPosition); - return materialDirectory + "/" + string; - + else { + fileStream << (formatJson ? j.dump(2) : j.dump()); } + fileStream.close(); + } } \ No newline at end of file diff --git a/src/engine/loader/MaterialLoader.h b/src/engine/loader/MaterialLoader.h index 332e6a93e..d83712ecc 100644 --- a/src/engine/loader/MaterialLoader.h +++ b/src/engine/loader/MaterialLoader.h @@ -5,30 +5,16 @@ #include -namespace Atlas { +namespace Atlas::Loader { - namespace Loader { + class MaterialLoader { - class MaterialLoader { + public: + static Ref LoadMaterial(const std::string& filename, bool binaryJson = false); - public: - static Ref LoadMaterial(std::string filename, int32_t mapResolution = 0); + static void SaveMaterial(const Ref& material, const std::string& filename, + bool binaryJson = false, bool formatJson = false); - static void SaveMaterial(Ref material, std::string filename); - - private: - static Ref LoadMaterialValues(std::ifstream& stream, int32_t& textureCount); - - static std::string WriteVector(std::string prefix, vec3 vector); - - static vec3 ReadVector(std::string line); - - static float ReadFloat(std::string line); - - static std::string ReadFilePath(std::string line, std::string materialDirectory); - - }; - - } + }; } \ No newline at end of file diff --git a/src/engine/loader/MeshLoader.cpp b/src/engine/loader/MeshLoader.cpp index 16e0a59ef..ee0be12d4 100644 --- a/src/engine/loader/MeshLoader.cpp +++ b/src/engine/loader/MeshLoader.cpp @@ -11,22 +11,23 @@ namespace Atlas::Loader { auto fileStream = Loader::AssetLoader::ReadFile(path, std::ios::in | std::ios::binary); if (!fileStream.is_open()) { - throw ResourceLoadException(filename, "Couldn't open mesh file stream"); + throw ResourceLoadException(filename, "Couldn't open mesh file stream: " + std::string(strerror(errno))); } json j; if (binaryJson) { auto data = Loader::AssetLoader::GetFileContent(fileStream); + // We don't want to keep the file stream open longer than we need + fileStream.close(); j = json::from_bjdata(data); } else { std::string serialized((std::istreambuf_iterator(fileStream)), std::istreambuf_iterator()); + fileStream.close(); j = json::parse(serialized); } - fileStream.close(); - auto mesh = CreateRef(); from_json(j, *mesh); diff --git a/src/engine/loader/ModelLoader.cpp b/src/engine/loader/ModelImporter.cpp similarity index 85% rename from src/engine/loader/ModelLoader.cpp rename to src/engine/loader/ModelImporter.cpp index 0e26b2a82..b436262f6 100644 --- a/src/engine/loader/ModelLoader.cpp +++ b/src/engine/loader/ModelImporter.cpp @@ -1,5 +1,7 @@ -#include "ModelLoader.h" +#include "ModelImporter.h" #include "ImageLoader.h" +#include "MaterialLoader.h" +#include "MeshLoader.h" #include "AssetLoader.h" #include "../Log.h" #include "../common/Path.h" @@ -217,11 +219,14 @@ namespace Atlas { meshData.aabb = Volume::AABB(min, max); meshData.radius = glm::length(max - min) * 0.5; - meshData.filename = filename; + meshData.name = Common::Path::GetFileNameWithoutExtension(filename); - mesh->name = meshData.filename; + mesh->name = meshData.name; mesh->UpdateData(); + auto meshFilename = state.paths.meshPath + mesh->name + ".aemesh"; + Loader::MeshLoader::SaveMesh(mesh, meshFilename); + return mesh; } @@ -235,7 +240,12 @@ namespace Atlas { auto materials = ImportMaterials(state, maxTextureResolution); - std::map> meshMap; + struct MeshInfo { + ResourceHandle mesh; + vec3 offset; + }; + + std::map meshMap; for (uint32_t i = 0; i < state.scene->mNumMeshes; i++) { auto assimpMesh = state.scene->mMeshes[i]; @@ -336,6 +346,14 @@ namespace Atlas { } + auto offset = vec3((max.x + min.x) * 0.5f, min.y, (max.z + min.z) * 0.5f); + // Recenter mesh + min -= offset; + max -= offset; + for (uint32_t j = 0; j < assimpMesh->mNumVertices; j++) { + vertices[j] = vertices[j] - offset; + } + // Copy indices for (uint32_t j = 0; j < assimpMesh->mNumFaces; j++) { for (uint32_t k = 0; k < 3; k++) { @@ -356,12 +374,16 @@ namespace Atlas { .aabb = meshData.aabb }); - meshData.filename = std::string(assimpMesh->mName.C_Str()); - mesh->name = meshData.filename; + meshData.name = std::string(assimpMesh->mName.C_Str()); + mesh->name = meshData.name; mesh->UpdateData(); - auto handle = ResourceManager::AddResource(filename + "_" + mesh->name + "_" + std::to_string(i), mesh); - meshMap[assimpMesh] = handle; + auto meshFilename = state.paths.meshPath + mesh->name + "_" + std::to_string(i) + ".aemesh"; + + auto handle = ResourceManager::AddResource(meshFilename, mesh); + meshMap[assimpMesh] = { handle, offset }; + + Loader::MeshLoader::SaveMesh(mesh, meshFilename); } auto scene = CreateRef(filename, min, max, depth); @@ -383,8 +405,10 @@ namespace Atlas { triangleCount += mesh->mNumFaces; + auto instanceTransform = glm::translate(meshMap[mesh].offset); + auto entity = scene->CreatePrefab( - meshMap[mesh], nodeTransform, makeMeshesStatic); + meshMap[mesh].mesh, nodeTransform * instanceTransform, makeMeshesStatic); auto name = std::string(mesh->mName.C_Str()) + "_" + std::to_string(entity); entity.AddComponent(name); @@ -448,29 +472,46 @@ namespace Atlas { std::vector> ModelImporter::ImportMaterials(ImporterState& state, int32_t maxTextureResolution) { std::atomic_int32_t counter = 0; - auto loadImagesLambda = [&]() { - auto i = counter++; - while (i < int32_t(state.scene->mNumMaterials)) { + auto threadCount = std::thread::hardware_concurrency(); + std::vector> threads; + for (uint32_t i = 0; i < threadCount; i++) { + threads.emplace_back(std::async(std::launch::async, [&]() { + auto i = counter++; - LoadMaterialImages(state, state.scene->mMaterials[i], true, maxTextureResolution); + while (i < int32_t(state.scene->mNumMaterials)) { - i = counter++; - } + LoadMaterialImages(state, state.scene->mMaterials[i], true, maxTextureResolution); - }; + i = counter++; + } + })); + } - auto threadCount = std::thread::hardware_concurrency(); - std::vector> threads; for (uint32_t i = 0; i < threadCount; i++) { - threads.emplace_back(std::async(std::launch::async, loadImagesLambda)); + threads[i].get(); } + auto imagesToSave = ImagesToTextures(state); + + threads.clear(); + counter = 0; for (uint32_t i = 0; i < threadCount; i++) { - threads[i].get(); + threads.emplace_back(std::async(std::launch::async, [&]() { + auto i = counter++; + + while (i < int32_t(imagesToSave.size())) { + + ImageLoader::SaveImage(imagesToSave[i], imagesToSave[i]->fileName); + + i = counter++; + } + })); } - ImagesToTexture(state.images); + for (uint32_t i = 0; i < threadCount; i++) { + threads[i].get(); + } std::vector> materials; for (uint32_t i = 0; i < state.scene->mNumMaterials; i++) { @@ -487,6 +528,8 @@ namespace Atlas { if (existed) Log::Warning("Material " + materialFilename + " was already loaded in the resource manager"); materials.push_back(handle); + + Loader::MaterialLoader::SaveMaterial(material, materialFilename); } return materials; @@ -563,11 +606,9 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.baseColorTextures.contains(path)) { material.baseColorMap = images.baseColorTextures[path]; - material.baseColorMapPath = images.baseColorImages[path]->fileName; } if (images.opacityTextures.contains(path)) { material.opacityMap = images.opacityTextures[path]; - material.opacityMapPath = images.opacityImages[path]->fileName; } } if (assimpMaterial->GetTextureCount(aiTextureType_OPACITY) > 0) { @@ -576,7 +617,6 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.opacityTextures.contains(path)) { material.opacityMap = images.opacityTextures[path]; - material.opacityMapPath = images.opacityImages[path]->fileName; } } if ((assimpMaterial->GetTextureCount(aiTextureType_NORMALS) > 0 || @@ -589,11 +629,9 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.normalTextures.contains(path)) { material.normalMap = images.normalTextures[path]; - material.normalMapPath = images.normalImages[path]->fileName; } if (images.displacementTextures.contains(path) && state.isObj) { material.displacementMap = images.displacementTextures[path]; - material.displacementMapPath = images.displacementImages[path]->fileName; } } if (assimpMaterial->GetTextureCount(aiTextureType_DIFFUSE_ROUGHNESS) > 0) { @@ -602,7 +640,6 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.roughnessTextures.contains(path)) { material.roughnessMap = images.roughnessTextures[path]; - material.roughnessMapPath = images.roughnessImages[path]->fileName; } } if (assimpMaterial->GetTextureCount(aiTextureType_METALNESS) > 0) { @@ -611,7 +648,6 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.metallicTextures.contains(path)) { material.metalnessMap = images.metallicTextures[path]; - material.metalnessMapPath = images.metallicImages[path]->fileName; } } if (assimpMaterial->GetTextureCount(aiTextureType_SPECULAR) > 0) { @@ -620,7 +656,6 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.metallicTextures.contains(path) && !material.HasMetalnessMap()) { material.metalnessMap = images.metallicTextures[path]; - material.metalnessMapPath = images.metallicImages[path]->fileName; } } if (assimpMaterial->GetTextureCount(aiTextureType_HEIGHT) > 0 && !state.isObj) { @@ -629,7 +664,6 @@ namespace Atlas { auto path = Common::Path::Normalize(directory + std::string(aiPath.C_Str())); if (images.displacementTextures.contains(path)) { material.displacementMap = images.displacementTextures[path]; - material.displacementMapPath = images.displacementImages[path]->fileName; } } if (assimpMaterial->GetTextureCount(aiTextureType_EMISSION_COLOR) > 0 || @@ -775,27 +809,50 @@ namespace Atlas { } } - void ModelImporter::ImagesToTexture(MaterialImages& images) { + std::vector>> ModelImporter::ImagesToTextures(ImporterState& state) { + + auto& images = state.images; + std::vector>> imagesToSave; for (const auto& [path, image] : images.baseColorImages) { - images.baseColorTextures[path] = std::make_shared(image); + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::BaseColor, path); + images.baseColorTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); } for (const auto& [path, image] : images.opacityImages) { - images.opacityTextures[path] = std::make_shared(image); + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::Opacity, path); + images.opacityTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); } for (const auto& [path, image] : images.normalImages) { - images.normalTextures[path] = std::make_shared(image); + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::Normal, path); + images.normalTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); } for (const auto& [path, image] : images.roughnessImages) { - images.roughnessTextures[path] = std::make_shared(image); + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::Roughness, path); + images.roughnessTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); } for (const auto& [path, image] : images.metallicImages) { - images.metallicTextures[path] = std::make_shared(image); + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::Metallic, path); + images.metallicTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); } for (const auto& [path, image] : images.displacementImages) { - images.displacementTextures[path] = std::make_shared(image); + auto texture = std::make_shared(image); + image->fileName = GetMaterialImageImportPath(state, MaterialImageType::Displacement, path); + images.displacementTextures[path] = ResourceManager::AddResource(image->fileName, texture); + imagesToSave.push_back(image); } + return imagesToSave; + } ModelImporter::Paths ModelImporter::GetPaths(const std::string& filename) { @@ -808,12 +865,40 @@ namespace Atlas { return Paths{ .filename = filename, .directoryPath = directoryPath, + .meshPath = directoryPath + "meshes/", .materialPath = directoryPath + "materials/", .texturePath = directoryPath + "textures/", }; } + std::string ModelImporter::GetMaterialImageImportPath(ImporterState& state, MaterialImageType type, const std::string& filename) { + + std::string typeName; + switch (type) { + case MaterialImageType::BaseColor: + typeName = "BaseColor"; break; + case MaterialImageType::Opacity: + typeName = "Opacity"; break; + case MaterialImageType::Roughness: + typeName = "Roughness"; break; + case MaterialImageType::Metallic: + typeName = "Metallic"; break; + case MaterialImageType::Normal: + typeName = "Normal"; break; + case MaterialImageType::Displacement: + typeName = "Displacement"; break; + default: + typeName = "Invalid"; break; + } + + auto extension = Common::Path::GetFileType(filename); + auto fileNameWithoutExtension = Common::Path::GetFileNameWithoutExtension(filename); + + return state.paths.texturePath + fileNameWithoutExtension + "_" + typeName + "." + extension; + + } + } } \ No newline at end of file diff --git a/src/engine/loader/ModelLoader.h b/src/engine/loader/ModelImporter.h similarity index 89% rename from src/engine/loader/ModelLoader.h rename to src/engine/loader/ModelImporter.h index 3b6b399c0..00bc8e1ef 100644 --- a/src/engine/loader/ModelLoader.h +++ b/src/engine/loader/ModelImporter.h @@ -34,6 +34,7 @@ namespace Atlas { struct Paths { std::string filename; std::string directoryPath; + std::string meshPath; std::string materialPath; std::string texturePath; }; @@ -55,12 +56,12 @@ namespace Atlas { std::map>> normalImages; std::map>> displacementImages; - std::map> baseColorTextures; - std::map> opacityTextures; - std::map> roughnessTextures; - std::map> metallicTextures; - std::map> normalTextures; - std::map> displacementTextures; + std::map> baseColorTextures; + std::map> opacityTextures; + std::map> roughnessTextures; + std::map> metallicTextures; + std::map> normalTextures; + std::map> displacementTextures; std::mutex mutexes[6]; @@ -132,10 +133,12 @@ namespace Atlas { static void LoadMaterialImages(ImporterState& state, aiMaterial* material, bool hasTangents, int32_t maxTextureResolution); - static void ImagesToTexture(MaterialImages& images); + static std::vector>> ImagesToTextures(ImporterState& state); static Paths GetPaths(const std::string& filename); + static std::string GetMaterialImageImportPath(ImporterState& state, MaterialImageType type, const std::string& filename); + template static Ref> ApplySobelFilter(const Ref>& image, const float strength = 1.0f) { diff --git a/src/engine/loader/TerrainLoader.cpp b/src/engine/loader/TerrainLoader.cpp index b223a702e..9e186e5bf 100644 --- a/src/engine/loader/TerrainLoader.cpp +++ b/src/engine/loader/TerrainLoader.cpp @@ -179,7 +179,7 @@ namespace Atlas { auto pos = line.find_last_of("\r\n"); auto materialPath = terrainDir + "/" + line.substr(offset, pos - offset); - auto material = MaterialLoader::LoadMaterial(materialPath, 1024); + auto material = MaterialLoader::LoadMaterial(materialPath); if (material) terrain->storage.WriteMaterial(slot, material); diff --git a/src/engine/mesh/DataComponent.h b/src/engine/mesh/DataComponent.h index 9aad8b433..50717f143 100644 --- a/src/engine/mesh/DataComponent.h +++ b/src/engine/mesh/DataComponent.h @@ -168,12 +168,13 @@ namespace Atlas { */ typename std::vector::const_iterator end() const; - private: - void ConvertData(); - ComponentFormat format; std::vector data; + + private: + void ConvertData(); + std::vector converted; }; diff --git a/src/engine/mesh/Mesh.cpp b/src/engine/mesh/Mesh.cpp index cba962d6e..4a68b909b 100644 --- a/src/engine/mesh/Mesh.cpp +++ b/src/engine/mesh/Mesh.cpp @@ -23,14 +23,6 @@ namespace Atlas { } - void Mesh::SetTransform(mat4 matrix) { - - data.SetTransform(matrix); - - UpdateData(); - - } - void Mesh::UpdateData() { bool hostAccessible = usage & MeshUsageBits::HostAccessBit; diff --git a/src/engine/mesh/Mesh.h b/src/engine/mesh/Mesh.h index 23822be38..56145e4d5 100644 --- a/src/engine/mesh/Mesh.h +++ b/src/engine/mesh/Mesh.h @@ -43,12 +43,6 @@ namespace Atlas { explicit Mesh(MeshMobility mobility, MeshUsage usage = 0); - /** - * Transforms the underlying mesh data and updates the buffer data afterwards - * @param transform - */ - void SetTransform(mat4 transform); - /** * Fully updates the buffer data with data available through the MeshData member */ @@ -109,8 +103,8 @@ namespace Atlas { int32_t allowedShadowCascades = 6; - float distanceCulling = 6e10f; - float shadowDistanceCulling = 6e10f; + float distanceCulling = 10000.0f; + float shadowDistanceCulling = 10000.0f; float impostorDistance = 300.0f; float impostorShadowDistance = 100.0f; diff --git a/src/engine/mesh/MeshData.cpp b/src/engine/mesh/MeshData.cpp index 384c72d23..6e020758b 100644 --- a/src/engine/mesh/MeshData.cpp +++ b/src/engine/mesh/MeshData.cpp @@ -60,62 +60,6 @@ namespace Atlas { } - void MeshData::SetTransform(mat4 transform) { - - auto hasNormals = normals.ContainsData(); - auto hasTangents = tangents.ContainsData(); - - auto& vertex = vertices.Get(); - auto& normal = normals.Get(); - auto& tangent = tangents.Get(); - - auto matrix = transform; - - auto min = vec3(std::numeric_limits::max()); - auto max = vec3(-std::numeric_limits::max()); - - for (int32_t i = 0; i < vertexCount; i++) { - - auto v = vec4(vertex[i], 1.0f); - - v = matrix * v; - - min = glm::min(min, vec3(v)); - max = glm::max(max, vec3(v)); - - vertex[i] = v; - - if (hasNormals) { - auto n = vec4(vec3(normal[i]), 0.0f); - - n = vec4(normalize(vec3(matrix * n)), normal[i].w); - - normal[i] = n; - } - if (hasTangents) { - auto t = vec4(vec3(tangent[i]), 0.0f); - - t = vec4(normalize(vec3(matrix * t)), tangent[i].w); - - tangent[i] = t; - } - - } - - vertices.Set(vertex); - - if (hasNormals) - normals.Set(normal); - - if(hasTangents) - tangents.Set(tangent); - - aabb = Volume::AABB(min, max); - - this->transform = transform; - - } - void MeshData::BuildBVH(bool parallelBuild) { auto device = Graphics::GraphicsDevice::DefaultDevice; @@ -334,7 +278,7 @@ namespace Atlas { void MeshData::DeepCopy(const MeshData& that) { - filename = that.filename; + name = that.name; indices = that.indices; diff --git a/src/engine/mesh/MeshData.h b/src/engine/mesh/MeshData.h index ae96a3c1b..b78f6736a 100644 --- a/src/engine/mesh/MeshData.h +++ b/src/engine/mesh/MeshData.h @@ -78,12 +78,6 @@ namespace Atlas { */ int32_t GetVertexCount() const; - /** - * Applies a transformation matrix to the data. - * @param transform - */ - void SetTransform(mat4 transform); - /** * Builds a blas from the data */ @@ -95,7 +89,7 @@ namespace Atlas { */ bool IsBVHBuilt(); - std::string filename; + std::string name; DataComponent indices; @@ -111,9 +105,6 @@ namespace Atlas { int32_t primitiveType = 0; Volume::AABB aabb; - - mat4 transform; - float radius = 0.0f; private: diff --git a/src/engine/mesh/MeshSerializer.cpp b/src/engine/mesh/MeshSerializer.cpp index 2424d3437..1c63c180a 100644 --- a/src/engine/mesh/MeshSerializer.cpp +++ b/src/engine/mesh/MeshSerializer.cpp @@ -1,4 +1,6 @@ #include "MeshSerializer.h" +#include "resource/ResourceManager.h" +#include "loader/MaterialLoader.h" namespace Atlas::Mesh { @@ -23,13 +25,8 @@ namespace Atlas::Mesh { {"impostorDistance", p.impostorDistance}, {"impostorShadowDistance", p.impostorShadowDistance}, {"invertUVs", p.invertUVs}, + {"data", p.data}, }; - - /* - if (p.data.IsValid()) { - j["resourcePath"] = p.data.GetResource()->path; - } - */ } void from_json(const json& j, Mesh& p) { @@ -37,6 +34,7 @@ namespace Atlas::Mesh { int mobility, usage; j.at("name").get_to(p.name); + j.at("mobility").get_to(mobility); j.at("usage").get_to(usage); j.at("cullBackFaces").get_to(p.cullBackFaces); @@ -51,36 +49,97 @@ namespace Atlas::Mesh { j.at("impostorDistance").get_to(p.impostorDistance); j.at("impostorShadowDistance").get_to(p.impostorShadowDistance); j.at("invertUVs").get_to(p.invertUVs); + j.at("data").get_to(p.data); p.mobility = static_cast(mobility); p.usage = static_cast(usage); - /* - if (j.contains("resourcePath")) { - std::string resourcePath; - j.at("resourcePath").get_to(resourcePath); - - p.data = ResourceManager::GetOrLoadResourceWithLoader(resourcePath, - ResourceOrigin::User, Loader::MeshDataLoader::LoadMeshData, false, 8192); - } - */ + p.UpdateData(); } void to_json(json& j, const MeshData& p) { j = json{ + {"name", p.name}, + {"indexCount", p.GetIndexCount()}, + {"vertexCount", p.GetVertexCount()}, + {"indices", p.indices}, + {"vertices", p.vertices}, + {"texCoords", p.texCoords}, + {"normals", p.normals}, + {"tangents", p.tangents}, + {"colors", p.colors}, + {"subData", p.subData}, + {"primitiveType", p.primitiveType}, {"radius", p.radius}, {"aabb", p.aabb}, }; + for (size_t i = 0; i < p.materials.size(); i++) { + auto& material = p.materials[i]; + auto path = material.GetResource()->path; + j["materials"][i] = path; + } + } void from_json(const json& j, MeshData& p) { + int32_t indexCount, vertexCount; + + j.at("name").get_to(p.name); + j.at("indexCount").get_to(indexCount); + j.at("vertexCount").get_to(vertexCount); + + p.SetIndexCount(indexCount); + p.SetVertexCount(vertexCount); + + j.at("indices").get_to(p.indices); + j.at("vertices").get_to(p.vertices); + j.at("texCoords").get_to(p.texCoords); + j.at("normals").get_to(p.normals); + j.at("tangents").get_to(p.tangents); + j.at("colors").get_to(p.colors); + j.at("subData").get_to(p.subData); + j.at("primitiveType").get_to(p.primitiveType); j.at("radius").get_to(p.radius); j.at("aabb").get_to(p.aabb); + if (j.contains("materials")) { + for (auto& path : j["materials"]) { + auto material = ResourceManager::GetOrLoadResourceWithLoader(path, + ResourceOrigin::User, Loader::MaterialLoader::LoadMaterial, false); + p.materials.push_back(material); + } + + for (auto& subData : p.subData) { + subData.material = p.materials[subData.materialIdx]; + } + } + + } + + void to_json(json& j, const MeshSubData& p) { + + j = json{ + {"name", p.name}, + {"indicesOffset", p.indicesOffset}, + {"indicesCount", p.indicesCount}, + {"materialIdx", p.materialIdx}, + {"aabb", p.aabb}, + }; + + } + + void from_json(const json& j, MeshSubData& p) { + + j.at("name").get_to(p.name); + j.at("indicesOffset").get_to(p.indicesOffset); + j.at("indicesCount").get_to(p.indicesCount); + j.at("materialIdx").get_to(p.materialIdx); + j.at("aabb").get_to(p.aabb); + } void to_json(json& j, const Impostor& p) { @@ -93,6 +152,89 @@ namespace Atlas::Mesh { + } + +} + +namespace Atlas { + + void to_json(json& j, const Material& p) { + + j = json{ + {"name", p.name}, + {"baseColor", p.baseColor}, + {"transmissiveColor", p.transmissiveColor}, + {"emissiveColor", p.emissiveColor}, + {"emissiveIntensity", p.emissiveIntensity}, + {"opacity", p.opacity}, + {"roughness", p.roughness}, + {"metalness", p.metalness}, + {"ao", p.ao}, + {"reflectance", p.reflectance}, + {"normalScale", p.normalScale}, + {"displacementScale", p.displacementScale}, + {"tiling", p.tiling}, + {"twoSided", p.twoSided}, + {"vertexColors", p.vertexColors}, + {"uvChannel", p.uvChannel}, + }; + + if (p.baseColorMap.IsValid()) + j["baseColorMapPath"] = p.baseColorMap.GetResource()->path; + if (p.opacityMap.IsValid()) + j["opacityMapPath"] = p.opacityMap.GetResource()->path; + if (p.normalMap.IsValid()) + j["normalMapPath"] = p.normalMap.GetResource()->path; + if (p.roughnessMap.IsValid()) + j["roughnessMapPath"] = p.roughnessMap.GetResource()->path; + if (p.metalnessMap.IsValid()) + j["metalnessMapPath"] = p.metalnessMap.GetResource()->path; + if (p.aoMap.IsValid()) + j["aoMapPath"] = p.aoMap.GetResource()->path; + if (p.displacementMap.IsValid()) + j["displacementMapPath"] = p.displacementMap.GetResource()->path; + + } + + void from_json(const json& j, Material& p) { + + j.at("name").get_to(p.name); + j.at("baseColor").get_to(p.baseColor); + j.at("transmissiveColor").get_to(p.transmissiveColor); + j.at("emissiveColor").get_to(p.emissiveColor); + j.at("emissiveIntensity").get_to(p.emissiveIntensity); + j.at("opacity").get_to(p.opacity); + j.at("roughness").get_to(p.roughness); + j.at("metalness").get_to(p.metalness); + j.at("ao").get_to(p.ao); + j.at("reflectance").get_to(p.reflectance); + j.at("normalScale").get_to(p.normalScale); + j.at("displacementScale").get_to(p.displacementScale); + j.at("tiling").get_to(p.tiling); + j.at("twoSided").get_to(p.twoSided); + j.at("vertexColors").get_to(p.vertexColors); + j.at("uvChannel").get_to(p.uvChannel); + + auto getTextureHandle = [](const std::string& path, bool colorSpaceConversion) -> auto { + return ResourceManager::GetOrLoadResource(path, colorSpaceConversion, + Texture::Wrapping::Repeat, Texture::Filtering::Anisotropic, 0); + }; + + if (j.contains("baseColorMapPath")) + p.baseColorMap = getTextureHandle(j["baseColorMapPath"], false); + if (j.contains("opacityMapPath")) + p.opacityMap = getTextureHandle(j["opacityMapPath"], false); + if (j.contains("normalMapPath")) + p.normalMap = getTextureHandle(j["normalMapPath"], false); + if (j.contains("roughnessMapPath")) + p.roughnessMap = getTextureHandle(j["roughnessMapPath"], false); + if (j.contains("metalnessMapPath")) + p.metalnessMap = getTextureHandle(j["metalnessMapPath"], false); + if (j.contains("aoMapPath")) + p.aoMap = getTextureHandle(j["aoMapPath"], false); + if (j.contains("displacementMapPath")) + p.displacementMap = getTextureHandle(j["displacementMapPath"], false); + } } \ No newline at end of file diff --git a/src/engine/mesh/MeshSerializer.h b/src/engine/mesh/MeshSerializer.h index acfea0415..b82e92019 100644 --- a/src/engine/mesh/MeshSerializer.h +++ b/src/engine/mesh/MeshSerializer.h @@ -17,8 +17,44 @@ namespace Atlas::Mesh { void from_json(const json& j, MeshData& p); + void to_json(json& j, const MeshSubData& p); + + void from_json(const json& j, MeshSubData& p); + void to_json(json& j, const Impostor& p); void from_json(const json& j, Impostor& p); + template + void to_json(json& j, const DataComponent& p) { + + int format = static_cast(p.format); + + j = json{ + {"format", format}, + {"data", p.data} + }; + + } + + template + void from_json(const json& j, DataComponent& p) { + + int format; + + j.at("format").get_to(format); + j.at("data").get_to(p.data); + + p.format = static_cast(format); + + } + +} + +namespace Atlas { + + void to_json(json& j, const Material& p); + + void from_json(const json& j, Material& p); + } \ No newline at end of file diff --git a/src/engine/physics/PhysicsSerializer.h b/src/engine/physics/PhysicsSerializer.h index 2990fa9b9..345a58a93 100644 --- a/src/engine/physics/PhysicsSerializer.h +++ b/src/engine/physics/PhysicsSerializer.h @@ -3,7 +3,7 @@ #include "PhysicsWorld.h" #include "common/SerializationHelper.h" -#include "loader/ModelLoader.h" +#include "loader/ModelImporter.h" #include #include diff --git a/src/engine/raytracing/RayTracingWorld.cpp b/src/engine/raytracing/RayTracingWorld.cpp index 58a29d87a..45684be39 100644 --- a/src/engine/raytracing/RayTracingWorld.cpp +++ b/src/engine/raytracing/RayTracingWorld.cpp @@ -211,27 +211,27 @@ namespace Atlas { gpuMaterial.useVertexColors = material->vertexColors ? 1 : 0; if (material->HasBaseColorMap()) { - gpuMaterial.baseColorTexture = scene->textureToBindlessIdx[material->baseColorMap]; + gpuMaterial.baseColorTexture = scene->textureToBindlessIdx[material->baseColorMap.Get()]; } if (material->HasOpacityMap()) { - gpuMaterial.opacityTexture = scene->textureToBindlessIdx[material->opacityMap]; + gpuMaterial.opacityTexture = scene->textureToBindlessIdx[material->opacityMap.Get()]; } if (material->HasNormalMap()) { - gpuMaterial.normalTexture = scene->textureToBindlessIdx[material->normalMap]; + gpuMaterial.normalTexture = scene->textureToBindlessIdx[material->normalMap.Get()]; } if (material->HasRoughnessMap()) { - gpuMaterial.roughnessTexture = scene->textureToBindlessIdx[material->roughnessMap]; + gpuMaterial.roughnessTexture = scene->textureToBindlessIdx[material->roughnessMap.Get()]; } if (material->HasMetalnessMap()) { - gpuMaterial.metalnessTexture = scene->textureToBindlessIdx[material->metalnessMap]; + gpuMaterial.metalnessTexture = scene->textureToBindlessIdx[material->metalnessMap.Get()]; } if (material->HasAoMap()) { - gpuMaterial.aoTexture = scene->textureToBindlessIdx[material->aoMap]; + gpuMaterial.aoTexture = scene->textureToBindlessIdx[material->aoMap.Get()]; } materials.push_back(gpuMaterial); diff --git a/src/engine/renderer/ExampleRenderer.cpp b/src/engine/renderer/ExampleRenderer.cpp index 2375bd137..5ad5b3a08 100644 --- a/src/engine/renderer/ExampleRenderer.cpp +++ b/src/engine/renderer/ExampleRenderer.cpp @@ -1,7 +1,7 @@ #include "ExampleRenderer.h" #include "../loader/ShaderLoader.h" -#include "../loader/ModelLoader.h" +#include "../loader/ModelImporter.h" #include "../resource/ResourceManager.h" #include "../common/RandomHelper.h" #include "../pipeline/PipelineManager.h" @@ -207,7 +207,7 @@ namespace Atlas { for (auto &subData: mesh->data.subData) { auto baseColorTexture = subData.material->baseColorMap; - if (baseColorTexture) { + if (subData.material->HasBaseColorMap()) { commandList->BindImage(baseColorTexture->image, baseColorTexture->sampler, 0, 1); } diff --git a/src/engine/renderer/OpaqueRenderer.cpp b/src/engine/renderer/OpaqueRenderer.cpp index c61f4f564..5085b2060 100644 --- a/src/engine/renderer/OpaqueRenderer.cpp +++ b/src/engine/renderer/OpaqueRenderer.cpp @@ -113,13 +113,13 @@ namespace Atlas { .windTextureLod = mesh->windNoiseTextureLod, .windBendScale = mesh->windBendScale, .windWiggleScale = mesh->windWiggleScale, - .baseColorTextureIdx = material->HasBaseColorMap() ? scene->textureToBindlessIdx[material->baseColorMap] : 0, - .opacityTextureIdx = material->HasOpacityMap() ? scene->textureToBindlessIdx[material->opacityMap] : 0, - .normalTextureIdx = material->HasNormalMap() ? scene->textureToBindlessIdx[material->normalMap] : 0, - .roughnessTextureIdx = material->HasRoughnessMap() ? scene->textureToBindlessIdx[material->roughnessMap] : 0, - .metalnessTextureIdx = material->HasMetalnessMap() ? scene->textureToBindlessIdx[material->metalnessMap] : 0, - .aoTextureIdx = material->HasAoMap() ? scene->textureToBindlessIdx[material->aoMap] : 0, - .heightTextureIdx = material->HasDisplacementMap() ? scene->textureToBindlessIdx[material->displacementMap] : 0, + .baseColorTextureIdx = material->HasBaseColorMap() ? scene->textureToBindlessIdx[material->baseColorMap.Get()] : 0, + .opacityTextureIdx = material->HasOpacityMap() ? scene->textureToBindlessIdx[material->opacityMap.Get()] : 0, + .normalTextureIdx = material->HasNormalMap() ? scene->textureToBindlessIdx[material->normalMap.Get()] : 0, + .roughnessTextureIdx = material->HasRoughnessMap() ? scene->textureToBindlessIdx[material->roughnessMap.Get()] : 0, + .metalnessTextureIdx = material->HasMetalnessMap() ? scene->textureToBindlessIdx[material->metalnessMap.Get()] : 0, + .aoTextureIdx = material->HasAoMap() ? scene->textureToBindlessIdx[material->aoMap.Get()] : 0, + .heightTextureIdx = material->HasDisplacementMap() ? scene->textureToBindlessIdx[material->displacementMap.Get()] : 0, }; commandList->PushConstants("constants", &pushConstants); diff --git a/src/engine/renderer/ShadowRenderer.cpp b/src/engine/renderer/ShadowRenderer.cpp index efb390f94..26598ba72 100644 --- a/src/engine/renderer/ShadowRenderer.cpp +++ b/src/engine/renderer/ShadowRenderer.cpp @@ -168,7 +168,7 @@ namespace Atlas { .windTextureLod = mesh->windNoiseTextureLod, .windBendScale = mesh->windBendScale, .windWiggleScale = mesh->windWiggleScale, - .textureID = material->HasOpacityMap() ? scene->textureToBindlessIdx[material->opacityMap] : 0 + .textureID = material->HasOpacityMap() ? scene->textureToBindlessIdx[material->opacityMap.Get()] : 0 }; commandList->PushConstants("constants", &pushConstants); diff --git a/src/engine/resource/Resource.h b/src/engine/resource/Resource.h index e0859f832..21533426b 100644 --- a/src/engine/resource/Resource.h +++ b/src/engine/resource/Resource.h @@ -60,6 +60,7 @@ namespace Atlas { catch (const ResourceLoadException& exception) { errorOnLoad = true; exceptionOnLoad = exception; + Log::Error("Exception on load for resource " + path + ": " + std::string(exception.what())); } catch(...) { errorOnLoad = true; @@ -78,7 +79,7 @@ namespace Atlas { catch (const std::exception& exception) { errorOnLoad = true; exceptionOnLoad = exception; - Log::Error("Exception on load: " + std::string(exception.what())); + Log::Error("Exception on load for resource " + path + ": " + std::string(exception.what())); } catch(...) { errorOnLoad = true; @@ -134,7 +135,7 @@ namespace Atlas { Ref data; std::atomic_bool isLoaded = false; - std::future future; + std::shared_future future; int32_t framesToDeletion = RESOURCE_RETENTION_FRAME_COUNT; }; @@ -156,7 +157,12 @@ namespace Atlas { } inline void WaitForLoad() { - if (!IsLoaded()) { + if (IsValid()) { + // We might be in a situation where one thread hasn't created the future + // and the other already tries to wait for it + while (!resource->future.valid() && !resource->isLoaded) + std::this_thread::sleep_for(std::chrono::microseconds(1)); + // Then ask future for a state again and return if there is none if (!resource->future.valid()) return; resource->future.wait(); diff --git a/src/engine/resource/ResourceManager.h b/src/engine/resource/ResourceManager.h index 815f36d8d..c08f3a13a 100644 --- a/src/engine/resource/ResourceManager.h +++ b/src/engine/resource/ResourceManager.h @@ -64,6 +64,8 @@ namespace Atlas { handle = ResourceHandle(resource); } + handle.WaitForLoad(); + return handle; } @@ -107,6 +109,8 @@ namespace Atlas { handle = ResourceHandle(resource); } + handle.WaitForLoad(); + return handle; } @@ -385,6 +389,13 @@ namespace Atlas { } static void ShutdownHandler() { + + for (const auto& [_, resource] : resources) { + if (!resource->future.valid()) + continue; + resource->future.wait(); + resource->future.get(); + } resources.clear(); diff --git a/src/engine/scene/Scene.cpp b/src/engine/scene/Scene.cpp index 91f257580..06953cf5c 100644 --- a/src/engine/scene/Scene.cpp +++ b/src/engine/scene/Scene.cpp @@ -634,20 +634,22 @@ namespace Atlas { if (!mesh.IsLoaded()) continue; for (auto& material : mesh->data.materials) { + if (!material.IsLoaded()) + Log::Warning("Nooooo"); if (material->HasBaseColorMap()) - textures.insert(material->baseColorMap); + textures.insert(material->baseColorMap.Get()); if (material->HasOpacityMap()) - textures.insert(material->opacityMap); + textures.insert(material->opacityMap.Get()); if (material->HasNormalMap()) - textures.insert(material->normalMap); + textures.insert(material->normalMap.Get()); if (material->HasRoughnessMap()) - textures.insert(material->roughnessMap); + textures.insert(material->roughnessMap.Get()); if (material->HasMetalnessMap()) - textures.insert(material->metalnessMap); + textures.insert(material->metalnessMap.Get()); if (material->HasAoMap()) - textures.insert(material->aoMap); + textures.insert(material->aoMap.Get()); if (material->HasDisplacementMap()) - textures.insert(material->displacementMap); + textures.insert(material->displacementMap.Get()); } // Not all meshes might have a bvh diff --git a/src/engine/scene/SceneSerializer.cpp b/src/engine/scene/SceneSerializer.cpp index d7c5c613b..c5d84c0e2 100644 --- a/src/engine/scene/SceneSerializer.cpp +++ b/src/engine/scene/SceneSerializer.cpp @@ -174,6 +174,8 @@ namespace Atlas::Scene { j["ao"] = *scene->ao; if (scene->reflection) j["reflection"] = *scene->reflection; + if (scene->rtgi) + j["rtgi"] = *scene->rtgi; if (scene->sss) j["sss"] = *scene->sss; if (scene->ssgi) @@ -223,6 +225,10 @@ namespace Atlas::Scene { scene->reflection = CreateRef(); *scene->reflection = j["reflection"]; } + if (j.contains("rtgi")) { + scene->rtgi = CreateRef(); + *scene->rtgi = j["rtgi"]; + } if (j.contains("sss")) { scene->sss = CreateRef(); *scene->sss = j["sss"]; diff --git a/src/engine/scene/components/ComponentSerializer.cpp b/src/engine/scene/components/ComponentSerializer.cpp index 9ab4f668b..703abddf3 100644 --- a/src/engine/scene/components/ComponentSerializer.cpp +++ b/src/engine/scene/components/ComponentSerializer.cpp @@ -6,6 +6,7 @@ #include "resource/ResourceManager.h" #include "audio/AudioManager.h" +#include "loader/MeshLoader.h" namespace Atlas::Scene::Components { @@ -176,7 +177,7 @@ namespace Atlas::Scene::Components { j.at("resourcePath").get_to(resourcePath); p.mesh = ResourceManager::GetOrLoadResourceWithLoaderAsync(resourcePath, - ResourceOrigin::User, Loader::ModelImporter::ImportMesh, false, 8192); + ResourceOrigin::User, Loader::MeshLoader::LoadMesh, false); } } diff --git a/src/engine/scripting/LuaScriptBindings.cpp b/src/engine/scripting/LuaScriptBindings.cpp index 13460026d..c9fa14409 100644 --- a/src/engine/scripting/LuaScriptBindings.cpp +++ b/src/engine/scripting/LuaScriptBindings.cpp @@ -4,7 +4,7 @@ #include "scene/Scene.h" #include "Clock.h" #include "input/KeyboardMap.h" -#include "loader/ModelLoader.h" +#include "loader/ModelImporter.h" #include "bindings/AudioBindings.h" #include "bindings/GraphicsBindings.h" diff --git a/src/engine/scripting/bindings/MeshBindings.cpp b/src/engine/scripting/bindings/MeshBindings.cpp index ffc259d15..074916ce2 100644 --- a/src/engine/scripting/bindings/MeshBindings.cpp +++ b/src/engine/scripting/bindings/MeshBindings.cpp @@ -17,15 +17,17 @@ namespace Atlas::Scripting::Bindings { }); ns->new_usertype("MeshData", - "filename", &Mesh::MeshData::filename, + "filename", &Mesh::MeshData::name, "materials", &Mesh::MeshData::materials, "primitiveType", &Mesh::MeshData::primitiveType, "aabb", &Mesh::MeshData::aabb, - "transform", &Mesh::MeshData::transform, "radius", &Mesh::MeshData::radius ); ns->new_usertype("Mesh", + "UpdateData", &Mesh::Mesh::UpdateData, + "UpdateMaterials", &Mesh::Mesh::UpdateMaterials, + "UpdateVertexArray", &Mesh::Mesh::UpdateVertexArray, "name", &Mesh::Mesh::name, "data", &Mesh::Mesh::data, "mobility", &Mesh::Mesh::mobility, @@ -57,6 +59,7 @@ namespace Atlas::Scripting::Bindings { "HasMetalnessMap", &Material::HasMetalnessMap, "HasAoMap", &Material::HasAoMap, "HasDisplacementMap", &Material::HasDisplacementMap, + "SetChanged", &Material::SetChanged, "name", &Material::name, "baseColor", &Material::baseColor, "transmissiveColor", &Material::transmissiveColor, diff --git a/src/engine/scripting/bindings/ResourceBindings.cpp b/src/engine/scripting/bindings/ResourceBindings.cpp index 993b57b30..0b5333212 100644 --- a/src/engine/scripting/bindings/ResourceBindings.cpp +++ b/src/engine/scripting/bindings/ResourceBindings.cpp @@ -4,13 +4,15 @@ #include "mesh/Mesh.h" #include "scripting/Script.h" -#include "loader/ModelLoader.h" +#include "loader/ModelImporter.h" namespace Atlas::Scripting::Bindings { void GenerateResourceManagerBindings(sol::table* ns) { GenerateResourceBinding(ns, "AudioResourceHandle"); + GenerateResourceBinding(ns, "MaterialResourceHandle"); + GenerateResourceBinding(ns, "Texture2DResourceHandle"); GenerateResourceBinding(ns, "MeshResourceHandle"); GenerateResourceBinding(ns, "ScriptResourceHandle"); diff --git a/src/tests/App.h b/src/tests/App.h index 0b53f7b8a..a7bc33409 100644 --- a/src/tests/App.h +++ b/src/tests/App.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include