Fix FBX winding for Nahida preview
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <XCEngine/Core/Asset/AssetDatabase.h>
|
||||
|
||||
#include <XCEngine/Core/Asset/ArtifactContainer.h>
|
||||
#include <XCEngine/Core/Asset/ArtifactFormats.h>
|
||||
#include <XCEngine/Debug/Logger.h>
|
||||
#include <XCEngine/RHI/D3D12/D3D12Shader.h>
|
||||
@@ -18,6 +19,7 @@
|
||||
#include <XCEngine/Resources/BuiltinResources.h>
|
||||
#include "Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.h"
|
||||
#include <XCEngine/Resources/Shader/ShaderLoader.h>
|
||||
#include <XCEngine/Resources/Texture/TextureImportHeuristics.h>
|
||||
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
||||
#include <XCEngine/Resources/UI/UIDocumentCompiler.h>
|
||||
#include <XCEngine/Resources/Volume/VolumeField.h>
|
||||
@@ -63,7 +65,24 @@ Containers::String ToContainersString(const std::string& value) {
|
||||
|
||||
Containers::String NormalizeArtifactPathString(const fs::path& path);
|
||||
Containers::String NormalizeArtifactPathString(const Containers::String& path);
|
||||
bool SerializeTextureArtifactPayload(const Texture& texture,
|
||||
Containers::Array<Core::uint8>& outPayload);
|
||||
bool SerializeMaterialArtifactPayload(
|
||||
const Material& material,
|
||||
Containers::Array<Core::uint8>& outPayload,
|
||||
const std::unordered_map<const Texture*, Containers::String>& textureArtifactPaths,
|
||||
const std::unordered_map<const Texture*, AssetRef>& textureAssetRefs,
|
||||
const AssetDatabase* assetDatabase);
|
||||
bool SerializeShaderArtifactPayload(const Shader& shader,
|
||||
Containers::Array<Core::uint8>& outPayload);
|
||||
bool WriteSingleEntryArtifactContainerFile(const fs::path& artifactPath,
|
||||
ResourceType resourceType,
|
||||
const Containers::Array<Core::uint8>& payload);
|
||||
constexpr const char* kModelSubAssetManifestFileName = "subassets.tsv";
|
||||
constexpr const char* kSourceAssetDbFileName = "assets.db";
|
||||
constexpr const char* kArtifactDbFileName = "artifacts.db";
|
||||
constexpr const char* kLegacySourceAssetDbDirectory = "SourceAssetDB";
|
||||
constexpr const char* kLegacyArtifactDbDirectory = "ArtifactDB";
|
||||
|
||||
struct ModelSubAssetManifestEntry {
|
||||
LocalID localID = kInvalidLocalID;
|
||||
@@ -114,6 +133,39 @@ bool IsProjectRelativePath(const fs::path& path) {
|
||||
generic.rfind("../", 0) != 0;
|
||||
}
|
||||
|
||||
void TryMigrateLegacyLibraryDatabaseFile(
|
||||
const fs::path& libraryRoot,
|
||||
const char* legacyDirectoryName,
|
||||
const char* fileName) {
|
||||
const fs::path legacyFilePath = libraryRoot / legacyDirectoryName / fileName;
|
||||
const fs::path currentFilePath = libraryRoot / fileName;
|
||||
|
||||
std::error_code ec;
|
||||
if (fs::exists(currentFilePath, ec)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ec.clear();
|
||||
if (!fs::exists(legacyFilePath, ec)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs::rename(legacyFilePath, currentFilePath, ec);
|
||||
if (ec) {
|
||||
ec.clear();
|
||||
fs::copy_file(legacyFilePath, currentFilePath, fs::copy_options::overwrite_existing, ec);
|
||||
if (ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
ec.clear();
|
||||
fs::remove(legacyFilePath, ec);
|
||||
}
|
||||
|
||||
ec.clear();
|
||||
fs::remove(legacyFilePath.parent_path(), ec);
|
||||
}
|
||||
|
||||
void AddUniqueDependencyPath(const fs::path& path,
|
||||
std::unordered_set<std::string>& seenPaths,
|
||||
std::vector<fs::path>& outPaths) {
|
||||
@@ -133,6 +185,23 @@ void AddUniqueDependencyPath(const fs::path& path,
|
||||
}
|
||||
|
||||
bool IsCurrentShaderArtifactFile(const fs::path& artifactPath) {
|
||||
Containers::Array<Core::uint8> data;
|
||||
Containers::String payloadError;
|
||||
if (ReadArtifactContainerMainEntryPayload(
|
||||
NormalizeArtifactPathString(artifactPath),
|
||||
ResourceType::Shader,
|
||||
data,
|
||||
&payloadError)) {
|
||||
if (data.Size() < sizeof(ShaderArtifactFileHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShaderArtifactFileHeader header = {};
|
||||
std::memcpy(&header, data.Data(), sizeof(header));
|
||||
return std::memcmp(header.magic, "XCSHD06", 7) == 0 &&
|
||||
header.schemaVersion == kShaderArtifactSchemaVersion;
|
||||
}
|
||||
|
||||
std::ifstream input(artifactPath, std::ios::binary);
|
||||
if (!input.is_open()) {
|
||||
return false;
|
||||
@@ -330,12 +399,19 @@ bool TryPrecompileShaderVariantForBackend(const Containers::String& shaderPath,
|
||||
|
||||
RHI::CompiledSpirvShader compiledShader = {};
|
||||
std::string errorMessage;
|
||||
const RHI::SpirvTargetEnvironment spirvTargetEnvironment =
|
||||
(targetBackend == ShaderBackend::OpenGL &&
|
||||
compileDesc.sourceLanguage == RHI::ShaderLanguage::HLSL)
|
||||
? RHI::SpirvTargetEnvironment::Vulkan
|
||||
: (targetBackend == ShaderBackend::Vulkan
|
||||
? RHI::SpirvTargetEnvironment::Vulkan
|
||||
: RHI::SpirvTargetEnvironment::OpenGL);
|
||||
const bool compiled =
|
||||
targetBackend == ShaderBackend::Vulkan
|
||||
? RHI::CompileVulkanShader(compileDesc, compiledShader, &errorMessage)
|
||||
: RHI::CompileSpirvShader(
|
||||
compileDesc,
|
||||
RHI::SpirvTargetEnvironment::OpenGL,
|
||||
spirvTargetEnvironment,
|
||||
compiledShader,
|
||||
&errorMessage);
|
||||
if (!compiled) {
|
||||
@@ -705,7 +781,7 @@ bool TryResolveModelSubAssetArtifactPath(const fs::path& manifestPath,
|
||||
return false;
|
||||
}
|
||||
|
||||
void WriteString(std::ofstream& stream, const Containers::String& value) {
|
||||
void WriteString(std::ostream& stream, const Containers::String& value) {
|
||||
const Core::uint32 length = static_cast<Core::uint32>(value.Length());
|
||||
stream.write(reinterpret_cast<const char*>(&length), sizeof(length));
|
||||
if (length > 0) {
|
||||
@@ -713,6 +789,45 @@ void WriteString(std::ofstream& stream, const Containers::String& value) {
|
||||
}
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> ToByteArray(const std::string& text) {
|
||||
Containers::Array<Core::uint8> bytes;
|
||||
if (text.empty()) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bytes.ResizeUninitialized(text.size());
|
||||
std::memcpy(bytes.Data(), text.data(), text.size());
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bool SerializeTextureArtifactPayload(const Texture& texture,
|
||||
Containers::Array<Core::uint8>& outPayload) {
|
||||
std::ostringstream output(std::ios::binary | std::ios::out);
|
||||
|
||||
TextureArtifactHeader header;
|
||||
header.textureType = static_cast<Core::uint32>(texture.GetTextureType());
|
||||
header.textureFormat = static_cast<Core::uint32>(texture.GetFormat());
|
||||
header.width = texture.GetWidth();
|
||||
header.height = texture.GetHeight();
|
||||
header.depth = texture.GetDepth();
|
||||
header.mipLevels = texture.GetMipLevels();
|
||||
header.arraySize = texture.GetArraySize();
|
||||
header.pixelDataSize = static_cast<Core::uint64>(texture.GetPixelDataSize());
|
||||
|
||||
output.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
if (texture.GetPixelDataSize() > 0) {
|
||||
output.write(static_cast<const char*>(texture.GetPixelData()), texture.GetPixelDataSize());
|
||||
}
|
||||
|
||||
if (!output) {
|
||||
outPayload.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
outPayload = ToByteArray(output.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
Containers::String ReadString(std::ifstream& stream) {
|
||||
Core::uint32 length = 0;
|
||||
stream.read(reinterpret_cast<char*>(&length), sizeof(length));
|
||||
@@ -730,35 +845,24 @@ Containers::String ReadString(std::ifstream& stream) {
|
||||
}
|
||||
|
||||
bool WriteTextureArtifactFile(const fs::path& artifactPath, const Texture& texture) {
|
||||
Containers::Array<Core::uint8> payload;
|
||||
if (!SerializeTextureArtifactPayload(texture, payload)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextureArtifactHeader header;
|
||||
header.textureType = static_cast<Core::uint32>(texture.GetTextureType());
|
||||
header.textureFormat = static_cast<Core::uint32>(texture.GetFormat());
|
||||
header.width = texture.GetWidth();
|
||||
header.height = texture.GetHeight();
|
||||
header.depth = texture.GetDepth();
|
||||
header.mipLevels = texture.GetMipLevels();
|
||||
header.arraySize = texture.GetArraySize();
|
||||
header.pixelDataSize = static_cast<Core::uint64>(texture.GetPixelDataSize());
|
||||
|
||||
output.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
if (texture.GetPixelDataSize() > 0) {
|
||||
output.write(static_cast<const char*>(texture.GetPixelData()), texture.GetPixelDataSize());
|
||||
if (!payload.Empty()) {
|
||||
output.write(reinterpret_cast<const char*>(payload.Data()),
|
||||
static_cast<std::streamsize>(payload.Size()));
|
||||
}
|
||||
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool WriteVolumeFieldArtifactFile(const fs::path& artifactPath, const VolumeField& volumeField) {
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> payload;
|
||||
VolumeFieldArtifactHeader header;
|
||||
header.storageKind = static_cast<Core::uint32>(volumeField.GetStorageKind());
|
||||
header.boundsMin = volumeField.GetBounds().GetMin();
|
||||
@@ -774,9 +878,22 @@ bool WriteVolumeFieldArtifactFile(const fs::path& artifactPath, const VolumeFiel
|
||||
header.gridClass = volumeField.GetGridClass();
|
||||
header.payloadSize = static_cast<Core::uint64>(volumeField.GetPayloadSize());
|
||||
|
||||
output.write(reinterpret_cast<const char*>(&header), sizeof(header));
|
||||
payload.Resize(sizeof(header) + volumeField.GetPayloadSize());
|
||||
std::memcpy(payload.Data(), &header, sizeof(header));
|
||||
if (volumeField.GetPayloadSize() > 0) {
|
||||
output.write(static_cast<const char*>(volumeField.GetPayloadData()), volumeField.GetPayloadSize());
|
||||
std::memcpy(
|
||||
payload.Data() + sizeof(header),
|
||||
volumeField.GetPayloadData(),
|
||||
volumeField.GetPayloadSize());
|
||||
}
|
||||
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!payload.Empty()) {
|
||||
output.write(reinterpret_cast<const char*>(payload.Data()), static_cast<std::streamsize>(payload.Size()));
|
||||
}
|
||||
|
||||
return static_cast<bool>(output);
|
||||
@@ -856,17 +973,41 @@ Containers::String ResolveTextureBindingPath(
|
||||
|
||||
return NormalizeArtifactPathString(material.GetTextureBindingPath(bindingIndex));
|
||||
}
|
||||
|
||||
bool WriteMaterialArtifactFile(
|
||||
const fs::path& artifactPath,
|
||||
const Material& material,
|
||||
const std::unordered_map<const Texture*, Containers::String>& textureArtifactPaths = {},
|
||||
const std::unordered_map<const Texture*, AssetRef>& textureAssetRefs = {},
|
||||
const AssetDatabase* assetDatabase = nullptr) {
|
||||
Containers::Array<Core::uint8> payload;
|
||||
if (!SerializeMaterialArtifactPayload(
|
||||
material,
|
||||
payload,
|
||||
textureArtifactPaths,
|
||||
textureAssetRefs,
|
||||
assetDatabase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
if (!payload.Empty()) {
|
||||
output.write(reinterpret_cast<const char*>(payload.Data()),
|
||||
static_cast<std::streamsize>(payload.Size()));
|
||||
}
|
||||
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool SerializeMaterialArtifactPayload(
|
||||
const Material& material,
|
||||
Containers::Array<Core::uint8>& outPayload,
|
||||
const std::unordered_map<const Texture*, Containers::String>& textureArtifactPaths,
|
||||
const std::unordered_map<const Texture*, AssetRef>& textureAssetRefs,
|
||||
const AssetDatabase* assetDatabase) {
|
||||
std::ostringstream output(std::ios::binary | std::ios::out);
|
||||
|
||||
MaterialArtifactFileHeader fileHeader;
|
||||
output.write(reinterpret_cast<const char*>(&fileHeader), sizeof(fileHeader));
|
||||
@@ -929,15 +1070,32 @@ bool WriteMaterialArtifactFile(
|
||||
WriteString(output, ResolveTextureBindingPath(material, bindingIndex, textureArtifactPaths));
|
||||
}
|
||||
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool WriteShaderArtifactFile(const fs::path& artifactPath, const Shader& shader) {
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
if (!output) {
|
||||
outPayload.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
outPayload = ToByteArray(output.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteSingleEntryArtifactContainerFile(const fs::path& artifactPath,
|
||||
ResourceType resourceType,
|
||||
const Containers::Array<Core::uint8>& payload) {
|
||||
ArtifactContainerWriter writer;
|
||||
ArtifactContainerEntry entry;
|
||||
entry.name = "main";
|
||||
entry.resourceType = resourceType;
|
||||
entry.localID = kMainAssetLocalID;
|
||||
entry.payload = payload;
|
||||
writer.AddEntry(std::move(entry));
|
||||
return writer.WriteToFile(NormalizeArtifactPathString(artifactPath));
|
||||
}
|
||||
|
||||
bool SerializeShaderArtifactPayload(const Shader& shader,
|
||||
Containers::Array<Core::uint8>& outPayload) {
|
||||
std::ostringstream output(std::ios::binary | std::ios::out);
|
||||
|
||||
ShaderArtifactFileHeader fileHeader;
|
||||
output.write(reinterpret_cast<const char*>(&fileHeader), sizeof(fileHeader));
|
||||
|
||||
@@ -1037,6 +1195,30 @@ bool WriteShaderArtifactFile(const fs::path& artifactPath, const Shader& shader)
|
||||
}
|
||||
}
|
||||
|
||||
if (!output) {
|
||||
outPayload.Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
outPayload = ToByteArray(output.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteShaderArtifactFile(const fs::path& artifactPath, const Shader& shader) {
|
||||
Containers::Array<Core::uint8> payload;
|
||||
if (!SerializeShaderArtifactPayload(shader, payload)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream output(artifactPath, std::ios::binary | std::ios::trunc);
|
||||
if (!output.is_open()) {
|
||||
return false;
|
||||
}
|
||||
if (!payload.Empty()) {
|
||||
output.write(reinterpret_cast<const char*>(payload.Data()),
|
||||
static_cast<std::streamsize>(payload.Size()));
|
||||
}
|
||||
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
@@ -1103,10 +1285,20 @@ void AssetDatabase::Initialize(const Containers::String& projectRoot) {
|
||||
m_projectRoot = NormalizePathString(projectRoot);
|
||||
m_assetsRoot = NormalizePathString(fs::path(m_projectRoot.CStr()) / "Assets");
|
||||
m_libraryRoot = NormalizePathString(fs::path(m_projectRoot.CStr()) / "Library");
|
||||
m_sourceDbPath = NormalizePathString(fs::path(m_libraryRoot.CStr()) / "SourceAssetDB" / "assets.db");
|
||||
m_artifactDbPath = NormalizePathString(fs::path(m_libraryRoot.CStr()) / "ArtifactDB" / "artifacts.db");
|
||||
m_sourceDbPath =
|
||||
NormalizePathString(fs::path(m_libraryRoot.CStr()) / kSourceAssetDbFileName);
|
||||
m_artifactDbPath =
|
||||
NormalizePathString(fs::path(m_libraryRoot.CStr()) / kArtifactDbFileName);
|
||||
|
||||
EnsureProjectLayout();
|
||||
TryMigrateLegacyLibraryDatabaseFile(
|
||||
fs::path(m_libraryRoot.CStr()),
|
||||
kLegacySourceAssetDbDirectory,
|
||||
kSourceAssetDbFileName);
|
||||
TryMigrateLegacyLibraryDatabaseFile(
|
||||
fs::path(m_libraryRoot.CStr()),
|
||||
kLegacyArtifactDbDirectory,
|
||||
kArtifactDbFileName);
|
||||
LoadSourceAssetDB();
|
||||
LoadArtifactDB();
|
||||
}
|
||||
@@ -1441,9 +1633,7 @@ void AssetDatabase::EnsureProjectLayout() {
|
||||
std::error_code ec;
|
||||
fs::create_directories(fs::path(m_assetsRoot.CStr()), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_libraryRoot.CStr()) / "SourceAssetDB", ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_libraryRoot.CStr()) / "ArtifactDB", ec);
|
||||
fs::create_directories(fs::path(m_libraryRoot.CStr()), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_libraryRoot.CStr()) / "Artifacts", ec);
|
||||
}
|
||||
@@ -1666,12 +1856,15 @@ Core::uint32 AssetDatabase::CleanupOrphanedArtifacts() const {
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> retainedArtifactPathKeys;
|
||||
retainedArtifactPathKeys.reserve(m_artifactsByGuid.size());
|
||||
retainedArtifactPathKeys.reserve(m_artifactsByGuid.size() * 2u);
|
||||
for (const auto& [guid, record] : m_artifactsByGuid) {
|
||||
(void)guid;
|
||||
if (!record.artifactDirectory.Empty()) {
|
||||
retainedArtifactPathKeys.insert(ToStdString(MakeKey(record.artifactDirectory)));
|
||||
}
|
||||
if (!record.mainArtifactPath.Empty()) {
|
||||
retainedArtifactPathKeys.insert(ToStdString(MakeKey(record.mainArtifactPath)));
|
||||
}
|
||||
}
|
||||
|
||||
Core::uint32 removedArtifactCount = 0;
|
||||
@@ -1743,13 +1936,13 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath,
|
||||
outRecord = SourceAssetRecord();
|
||||
outRecord.relativePath = relativePath;
|
||||
outRecord.importerName = GetImporterNameForPath(relativePath, isFolder);
|
||||
outRecord.importerVersion = kCurrentImporterVersion;
|
||||
outRecord.importerVersion = GetCurrentImporterVersion(outRecord.importerName);
|
||||
}
|
||||
|
||||
outRecord.relativePath = relativePath;
|
||||
outRecord.isFolder = isFolder;
|
||||
outRecord.importerName = GetImporterNameForPath(relativePath, isFolder);
|
||||
outRecord.importerVersion = kCurrentImporterVersion;
|
||||
outRecord.importerVersion = GetCurrentImporterVersion(outRecord.importerName);
|
||||
|
||||
if (UsesExternalSyntheticSourceRecord(relativePath)) {
|
||||
if (!outRecord.guid.IsValid()) {
|
||||
@@ -1795,6 +1988,7 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath,
|
||||
const fs::path metaPath(sourcePath.string() + ".meta");
|
||||
outRecord.metaPath = NormalizeRelativePath(metaPath);
|
||||
const Containers::String expectedImporterName = GetImporterNameForPath(relativePath, isFolder);
|
||||
const Core::uint32 expectedImporterVersion = GetCurrentImporterVersion(expectedImporterName);
|
||||
|
||||
bool shouldRewriteMeta = false;
|
||||
if (!fs::exists(metaPath) || !ReadMetaFile(metaPath, outRecord) || !outRecord.guid.IsValid()) {
|
||||
@@ -1807,8 +2001,8 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath,
|
||||
outRecord.importerName = expectedImporterName;
|
||||
shouldRewriteMeta = true;
|
||||
}
|
||||
if (outRecord.importerVersion != kCurrentImporterVersion) {
|
||||
outRecord.importerVersion = kCurrentImporterVersion;
|
||||
if (outRecord.importerVersion != expectedImporterVersion) {
|
||||
outRecord.importerVersion = expectedImporterVersion;
|
||||
shouldRewriteMeta = true;
|
||||
}
|
||||
|
||||
@@ -1879,7 +2073,7 @@ bool AssetDatabase::ReadMetaFile(const fs::path& metaPath,
|
||||
inOutRecord.importerName = GetImporterNameForPath(inOutRecord.relativePath, inOutRecord.isFolder);
|
||||
}
|
||||
if (inOutRecord.importerVersion == 0) {
|
||||
inOutRecord.importerVersion = kCurrentImporterVersion;
|
||||
inOutRecord.importerVersion = GetCurrentImporterVersion(inOutRecord.importerName);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1962,6 +2156,34 @@ Containers::String AssetDatabase::GetImporterNameForPath(const Containers::Strin
|
||||
return Containers::String("DefaultImporter");
|
||||
}
|
||||
|
||||
Core::uint32 AssetDatabase::GetCurrentImporterVersion(const Containers::String& importerName) {
|
||||
if (importerName == "TextureImporter") {
|
||||
return 9;
|
||||
}
|
||||
|
||||
if (importerName == "MaterialImporter") {
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (importerName == "ShaderImporter") {
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (importerName == "ModelImporter") {
|
||||
return 10;
|
||||
}
|
||||
|
||||
if (importerName == "GaussianSplatImporter") {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (importerName == "VolumeFieldImporter") {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return kBaseImporterVersion;
|
||||
}
|
||||
|
||||
ResourceType AssetDatabase::GetPrimaryResourceTypeForImporter(const Containers::String& importerName) {
|
||||
if (importerName == "UIViewImporter") {
|
||||
return ResourceType::UIView;
|
||||
@@ -2187,27 +2409,41 @@ bool AssetDatabase::EnsureArtifact(const Containers::String& requestPath,
|
||||
bool AssetDatabase::ImportTextureAsset(const SourceAssetRecord& sourceRecord,
|
||||
ArtifactRecord& outRecord) {
|
||||
TextureLoader loader;
|
||||
const Containers::String absolutePath = NormalizePathString(fs::path(m_projectRoot.CStr()) / sourceRecord.relativePath.CStr());
|
||||
LoadResult result = loader.Load(absolutePath);
|
||||
const Containers::String absolutePath =
|
||||
NormalizePathString(fs::path(m_projectRoot.CStr()) / sourceRecord.relativePath.CStr());
|
||||
const TextureImportSettings importSettings =
|
||||
BuildTextureImportSettingsFromIdentifier(sourceRecord.relativePath);
|
||||
LoadResult result = loader.Load(absolutePath, &importSettings);
|
||||
if (!result || result.resource == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Texture* texture = static_cast<Texture*>(result.resource);
|
||||
const Containers::String artifactKey = BuildArtifactKey(sourceRecord);
|
||||
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath = NormalizePathString(fs::path(artifactDir.CStr()) / "main.xctex");
|
||||
const Containers::String legacyArtifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath = BuildArtifactFilePath(artifactKey, ".xctex");
|
||||
const Containers::String artifactDir =
|
||||
NormalizePathString(fs::path(mainArtifactPath.CStr()).parent_path());
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / legacyArtifactDir.CStr(), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::create_directories(
|
||||
(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr()).parent_path(),
|
||||
ec);
|
||||
if (ec) {
|
||||
delete texture;
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool writeOk = WriteTextureArtifactFile(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(), *texture);
|
||||
Containers::Array<Core::uint8> payload;
|
||||
const bool serialized = SerializeTextureArtifactPayload(*texture, payload);
|
||||
const bool writeOk =
|
||||
serialized &&
|
||||
WriteSingleEntryArtifactContainerFile(
|
||||
fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(),
|
||||
ResourceType::Texture,
|
||||
payload);
|
||||
delete texture;
|
||||
if (!writeOk) {
|
||||
return false;
|
||||
@@ -2243,21 +2479,30 @@ bool AssetDatabase::ImportMaterialAsset(const SourceAssetRecord& sourceRecord,
|
||||
std::vector<ArtifactDependencyRecord> dependencies;
|
||||
CollectMaterialDependencies(*material, dependencies);
|
||||
const Containers::String artifactKey = BuildArtifactKey(sourceRecord, dependencies);
|
||||
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath =
|
||||
NormalizePathString(fs::path(artifactDir.CStr()) / "main.xcmat");
|
||||
const Containers::String legacyArtifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath = BuildArtifactFilePath(artifactKey, ".xcmat");
|
||||
const Containers::String artifactDir =
|
||||
NormalizePathString(fs::path(mainArtifactPath.CStr()).parent_path());
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / legacyArtifactDir.CStr(), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::create_directories(
|
||||
(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr()).parent_path(),
|
||||
ec);
|
||||
if (ec) {
|
||||
delete material;
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> payload;
|
||||
const bool serialized = SerializeMaterialArtifactPayload(*material, payload, {}, {}, this);
|
||||
const bool writeOk =
|
||||
WriteMaterialArtifactFile(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(), *material, {}, {}, this);
|
||||
serialized &&
|
||||
WriteSingleEntryArtifactContainerFile(
|
||||
fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(),
|
||||
ResourceType::Material,
|
||||
payload);
|
||||
delete material;
|
||||
if (!writeOk) {
|
||||
return false;
|
||||
@@ -2285,6 +2530,11 @@ bool AssetDatabase::ImportModelAsset(const SourceAssetRecord& sourceRecord,
|
||||
NormalizePathString(fs::path(m_projectRoot.CStr()) / sourceRecord.relativePath.CStr());
|
||||
|
||||
MeshImportSettings importSettings;
|
||||
const std::string extension = ToLowerCopy(fs::path(sourceRecord.relativePath.CStr()).extension().string());
|
||||
if (extension == ".fbx") {
|
||||
importSettings.AddImportFlag(MeshImportFlags::FlipUVs);
|
||||
}
|
||||
|
||||
ImportedModelData importedModel;
|
||||
Containers::String importErrorMessage;
|
||||
if (!ImportAssimpModel(absolutePath, importSettings, importedModel, &importErrorMessage)) {
|
||||
@@ -2460,21 +2710,30 @@ bool AssetDatabase::ImportShaderAsset(const SourceAssetRecord& sourceRecord,
|
||||
return false;
|
||||
}
|
||||
const Containers::String artifactKey = BuildArtifactKey(sourceRecord, dependencies);
|
||||
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath =
|
||||
NormalizePathString(fs::path(artifactDir.CStr()) / "main.xcshader");
|
||||
const Containers::String legacyArtifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath = BuildArtifactFilePath(artifactKey, ".xcshader");
|
||||
const Containers::String artifactDir =
|
||||
NormalizePathString(fs::path(mainArtifactPath.CStr()).parent_path());
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / legacyArtifactDir.CStr(), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::create_directories(
|
||||
(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr()).parent_path(),
|
||||
ec);
|
||||
if (ec) {
|
||||
delete shader;
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> payload;
|
||||
const bool serialized = SerializeShaderArtifactPayload(*shader, payload);
|
||||
const bool writeOk =
|
||||
WriteShaderArtifactFile(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(), *shader);
|
||||
serialized &&
|
||||
WriteSingleEntryArtifactContainerFile(
|
||||
fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(),
|
||||
ResourceType::Shader,
|
||||
payload);
|
||||
delete shader;
|
||||
if (!writeOk) {
|
||||
return false;
|
||||
@@ -2511,26 +2770,32 @@ bool AssetDatabase::ImportGaussianSplatAsset(const SourceAssetRecord& sourceReco
|
||||
|
||||
GaussianSplat* gaussianSplat = static_cast<GaussianSplat*>(result.resource);
|
||||
const Containers::String artifactKey = BuildArtifactKey(sourceRecord);
|
||||
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath =
|
||||
NormalizePathString(fs::path(artifactDir.CStr()) / "main.xcgsplat");
|
||||
const Containers::String legacyArtifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath = BuildArtifactFilePath(artifactKey, ".xcgsplat");
|
||||
const Containers::String artifactDir =
|
||||
NormalizePathString(fs::path(mainArtifactPath.CStr()).parent_path());
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / legacyArtifactDir.CStr(), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::create_directories(
|
||||
(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr()).parent_path(),
|
||||
ec);
|
||||
if (ec) {
|
||||
delete gaussianSplat;
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::String writeErrorMessage;
|
||||
const Containers::String gaussianSplatArtifactWritePath =
|
||||
NormalizePathString(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr());
|
||||
const bool writeOk = WriteGaussianSplatArtifactFile(
|
||||
gaussianSplatArtifactWritePath,
|
||||
*gaussianSplat,
|
||||
&writeErrorMessage);
|
||||
Containers::Array<Core::uint8> payload;
|
||||
const bool serialized =
|
||||
SerializeGaussianSplatArtifactPayload(*gaussianSplat, payload, &writeErrorMessage);
|
||||
const bool writeOk =
|
||||
serialized &&
|
||||
WriteSingleEntryArtifactContainerFile(
|
||||
fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(),
|
||||
ResourceType::GaussianSplat,
|
||||
payload);
|
||||
delete gaussianSplat;
|
||||
if (!writeOk) {
|
||||
if (!writeErrorMessage.Empty()) {
|
||||
@@ -2567,21 +2832,52 @@ bool AssetDatabase::ImportVolumeFieldAsset(const SourceAssetRecord& sourceRecord
|
||||
|
||||
VolumeField* volumeField = static_cast<VolumeField*>(result.resource);
|
||||
const Containers::String artifactKey = BuildArtifactKey(sourceRecord);
|
||||
const Containers::String artifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath =
|
||||
NormalizePathString(fs::path(artifactDir.CStr()) / "main.xcvol");
|
||||
const Containers::String legacyArtifactDir = BuildArtifactDirectory(artifactKey);
|
||||
const Containers::String mainArtifactPath = BuildArtifactFilePath(artifactKey, ".xcvol");
|
||||
const Containers::String artifactDir =
|
||||
NormalizePathString(fs::path(mainArtifactPath.CStr()).parent_path());
|
||||
|
||||
std::error_code ec;
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::remove_all(fs::path(m_projectRoot.CStr()) / legacyArtifactDir.CStr(), ec);
|
||||
ec.clear();
|
||||
fs::create_directories(fs::path(m_projectRoot.CStr()) / artifactDir.CStr(), ec);
|
||||
fs::create_directories(
|
||||
(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr()).parent_path(),
|
||||
ec);
|
||||
if (ec) {
|
||||
delete volumeField;
|
||||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<Core::uint8> payload;
|
||||
VolumeFieldArtifactHeader header;
|
||||
header.storageKind = static_cast<Core::uint32>(volumeField->GetStorageKind());
|
||||
header.boundsMin = volumeField->GetBounds().GetMin();
|
||||
header.boundsMax = volumeField->GetBounds().GetMax();
|
||||
header.voxelSize = volumeField->GetVoxelSize();
|
||||
header.indexBoundsMin[0] = volumeField->GetIndexBounds().minX;
|
||||
header.indexBoundsMin[1] = volumeField->GetIndexBounds().minY;
|
||||
header.indexBoundsMin[2] = volumeField->GetIndexBounds().minZ;
|
||||
header.indexBoundsMax[0] = volumeField->GetIndexBounds().maxX;
|
||||
header.indexBoundsMax[1] = volumeField->GetIndexBounds().maxY;
|
||||
header.indexBoundsMax[2] = volumeField->GetIndexBounds().maxZ;
|
||||
header.gridType = volumeField->GetGridType();
|
||||
header.gridClass = volumeField->GetGridClass();
|
||||
header.payloadSize = static_cast<Core::uint64>(volumeField->GetPayloadSize());
|
||||
|
||||
payload.Resize(sizeof(header) + volumeField->GetPayloadSize());
|
||||
std::memcpy(payload.Data(), &header, sizeof(header));
|
||||
if (volumeField->GetPayloadSize() > 0) {
|
||||
std::memcpy(
|
||||
payload.Data() + sizeof(header),
|
||||
volumeField->GetPayloadData(),
|
||||
volumeField->GetPayloadSize());
|
||||
}
|
||||
|
||||
const bool writeOk =
|
||||
WriteVolumeFieldArtifactFile(fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(), *volumeField);
|
||||
WriteSingleEntryArtifactContainerFile(
|
||||
fs::path(m_projectRoot.CStr()) / mainArtifactPath.CStr(),
|
||||
ResourceType::VolumeField,
|
||||
payload);
|
||||
delete volumeField;
|
||||
if (!writeOk) {
|
||||
return false;
|
||||
@@ -2922,6 +3218,21 @@ Containers::String AssetDatabase::BuildArtifactDirectory(const Containers::Strin
|
||||
return Containers::String("Library/Artifacts/") + shard + "/" + artifactKey;
|
||||
}
|
||||
|
||||
Containers::String AssetDatabase::BuildArtifactFilePath(const Containers::String& artifactKey,
|
||||
const char* extension) const {
|
||||
if (artifactKey.Length() < 2) {
|
||||
return Containers::String("Library/Artifacts/00/invalid") +
|
||||
Containers::String(extension == nullptr ? "" : extension);
|
||||
}
|
||||
|
||||
const Containers::String shard = artifactKey.Substring(0, 2);
|
||||
return Containers::String("Library/Artifacts/") +
|
||||
shard +
|
||||
"/" +
|
||||
artifactKey +
|
||||
Containers::String(extension == nullptr ? "" : extension);
|
||||
}
|
||||
|
||||
Containers::String AssetDatabase::ReadWholeFileText(const fs::path& path) {
|
||||
std::ifstream input(path, std::ios::binary);
|
||||
if (!input.is_open()) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <XCEngine/Resources/Mesh/MeshImportSettings.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Texture/Texture.h>
|
||||
#include <XCEngine/Resources/Texture/TextureImportHeuristics.h>
|
||||
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
||||
#include <XCEngine/Resources/Texture/TextureImportSettings.h>
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
@@ -93,7 +94,7 @@ Core::uint32 BuildPostProcessFlags(const MeshImportSettings& settings) {
|
||||
|
||||
if (settings.GetAxisConversion()) {
|
||||
flags |= aiProcess_MakeLeftHanded;
|
||||
flags |= aiProcess_FlipWindingOrder;
|
||||
// The engine treats CCW as front-facing, so keep the imported winding unchanged.
|
||||
}
|
||||
|
||||
if (settings.HasImportFlag(MeshImportFlags::FlipUVs)) {
|
||||
@@ -174,11 +175,7 @@ Containers::String BuildSubResourcePath(const Containers::String& sourcePath,
|
||||
}
|
||||
|
||||
TextureImportSettings BuildMaterialTextureImportSettings(const char* propertyName) {
|
||||
TextureImportSettings settings;
|
||||
(void)propertyName;
|
||||
settings.SetSRGB(false);
|
||||
settings.SetTargetFormat(TextureFormat::RGBA8_UNORM);
|
||||
return settings;
|
||||
return BuildTextureImportSettingsForMaterialProperty(propertyName);
|
||||
}
|
||||
|
||||
std::string BuildTextureCacheKey(const std::string& pathKey, const TextureImportSettings& settings) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <XCEngine/Resources/Model/Model.h>
|
||||
#include <XCEngine/Resources/Shader/Shader.h>
|
||||
#include <XCEngine/Resources/Texture/Texture.h>
|
||||
#include <XCEngine/Resources/Texture/TextureImportHeuristics.h>
|
||||
#include <XCEngine/Resources/Texture/TextureImportSettings.h>
|
||||
#include <XCEngine/Resources/Texture/TextureLoader.h>
|
||||
|
||||
@@ -185,7 +186,7 @@ Core::uint32 BuildPostProcessFlags(const MeshImportSettings& settings) {
|
||||
|
||||
if (settings.GetAxisConversion()) {
|
||||
flags |= aiProcess_MakeLeftHanded;
|
||||
flags |= aiProcess_FlipWindingOrder;
|
||||
// The engine treats CCW as front-facing, so keep the imported winding unchanged.
|
||||
}
|
||||
|
||||
if (settings.HasImportFlag(MeshImportFlags::FlipUVs)) {
|
||||
@@ -214,11 +215,7 @@ Core::uint32 BuildPostProcessFlags(const MeshImportSettings& settings) {
|
||||
}
|
||||
|
||||
TextureImportSettings BuildMaterialTextureImportSettings(const char* propertyName) {
|
||||
TextureImportSettings settings;
|
||||
(void)propertyName;
|
||||
settings.SetSRGB(false);
|
||||
settings.SetTargetFormat(TextureFormat::RGBA8_UNORM);
|
||||
return settings;
|
||||
return BuildTextureImportSettingsForMaterialProperty(propertyName);
|
||||
}
|
||||
|
||||
std::string BuildTextureCacheKey(const std::string& pathKey, const TextureImportSettings& settings) {
|
||||
|
||||
Reference in New Issue
Block a user