Implement XCUI markup import loader support
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
# Subplan 06:XCUI Markup / Import / Hot Reload
|
||||
|
||||
目标:
|
||||
|
||||
- 把 `.xcui` / `.xctheme` / `.xcschema` 拉进资源系统。
|
||||
- 建立导入、编译产物、热重载、诊断输出的第一版链路。
|
||||
|
||||
负责人边界:
|
||||
|
||||
- 负责资源类型、导入器、artifact、诊断日志。
|
||||
- 不负责 widget 运行时逻辑本身。
|
||||
|
||||
建议目录:
|
||||
|
||||
- `engine/include/XCEngine/Resources/UI/`
|
||||
- `engine/src/Resources/UI/`
|
||||
- `editor/src` 中与导入面板、诊断输出相关的接入口
|
||||
|
||||
前置依赖:
|
||||
|
||||
- 需要主计划中的资源类型命名拍板。
|
||||
- 与 `Subplan 03`、`Subplan 07` 协调格式字段。
|
||||
|
||||
现在就可以先做的内容:
|
||||
|
||||
- 定义三类资源描述结构
|
||||
- 设计导入错误诊断格式
|
||||
- 设计热重载触发和缓存失效策略
|
||||
- 先做一个最小 parser,可以把简单 `.xcui` 编成中间结构
|
||||
|
||||
明确不做:
|
||||
|
||||
- 不做完整 markup 语法大全
|
||||
- 不做 inspector 的最终渲染
|
||||
|
||||
交付物:
|
||||
|
||||
- UI 资源类型定义
|
||||
- 导入器与 artifact 结构
|
||||
- 热重载与错误输出最小闭环
|
||||
|
||||
验收标准:
|
||||
|
||||
- UI 资源可被 ResourceManager 识别
|
||||
- 导入失败时有可读诊断
|
||||
- 改动文件后可触发重新加载
|
||||
@@ -292,6 +292,10 @@ add_library(XCEngine STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Shader/ShaderLoader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AudioClip/AudioClip.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AudioClip/AudioLoader.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocumentTypes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocumentCompiler.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocuments.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocumentLoaders.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture/Texture.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture/TextureLoader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture/TextureImportSettings.cpp
|
||||
@@ -305,6 +309,9 @@ add_library(XCEngine STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderLoader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip/AudioClip.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip/AudioLoader.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/UI/UIDocumentCompiler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/UI/UIDocuments.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/UI/UIDocumentLoaders.cpp
|
||||
|
||||
# Scripting
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scripting/IScriptRuntime.h
|
||||
@@ -413,14 +420,24 @@ add_library(XCEngine STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Core/UIElementTree.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Core/UIContext.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Core/UIBuildContext.cpp
|
||||
/src/UI/Core/UIElementTree.cpp
|
||||
/include/XCEngine/UI/Style/StyleTypes.h
|
||||
/include/XCEngine/UI/Style/Theme.h
|
||||
/include/XCEngine/UI/Style/StyleSet.h
|
||||
/include/XCEngine/UI/Style/StyleResolver.h
|
||||
/src/UI/Style/StyleTypes.cpp
|
||||
/src/UI/Style/Theme.cpp
|
||||
/src/UI/Style/StyleResolver.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Core/UIElementTree.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Style/StyleTypes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Style/Theme.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Style/StyleSet.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Style/StyleResolver.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Style/StyleTypes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Style/Theme.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Style/StyleResolver.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Input/UIInputPath.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Input/UIFocusController.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Input/UIInputRouter.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Input/UIShortcutRegistry.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/UI/Input/UIInputDispatcher.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Input/UIInputPath.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Input/UIFocusController.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Input/UIInputRouter.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Input/UIShortcutRegistry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UI/Input/UIInputDispatcher.cpp
|
||||
|
||||
# Input
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/InputTypes.h
|
||||
|
||||
@@ -5,14 +5,16 @@
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
#include <XCEngine/Resources/Texture/Texture.h>
|
||||
#include <XCEngine/Resources/UI/UIDocumentTypes.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
constexpr Core::uint32 kTextureArtifactSchemaVersion = 1;
|
||||
constexpr Core::uint32 kMaterialArtifactSchemaVersion = 1;
|
||||
constexpr Core::uint32 kMaterialArtifactSchemaVersion = 2;
|
||||
constexpr Core::uint32 kMeshArtifactSchemaVersion = 2;
|
||||
constexpr Core::uint32 kShaderArtifactSchemaVersion = 1;
|
||||
constexpr Core::uint32 kUIDocumentArtifactSchemaVersion = 1;
|
||||
|
||||
struct TextureArtifactHeader {
|
||||
char magic[8] = { 'X', 'C', 'T', 'E', 'X', '0', '1', '\0' };
|
||||
@@ -44,7 +46,7 @@ struct MeshArtifactHeader {
|
||||
};
|
||||
|
||||
struct MaterialArtifactFileHeader {
|
||||
char magic[8] = { 'X', 'C', 'M', 'A', 'T', '0', '1', '\0' };
|
||||
char magic[8] = { 'X', 'C', 'M', 'A', 'T', '0', '2', '\0' };
|
||||
Core::uint32 schemaVersion = kMaterialArtifactSchemaVersion;
|
||||
};
|
||||
|
||||
@@ -94,5 +96,27 @@ struct ShaderVariantArtifactHeader {
|
||||
Core::uint64 compiledBinarySize = 0;
|
||||
};
|
||||
|
||||
struct UIDocumentArtifactFileHeader {
|
||||
char magic[8] = { 'X', 'C', 'U', 'I', 'D', '0', '1', '\0' };
|
||||
Core::uint32 schemaVersion = kUIDocumentArtifactSchemaVersion;
|
||||
Core::uint32 kind = 0;
|
||||
Core::uint32 dependencyCount = 0;
|
||||
Core::uint32 diagnosticCount = 0;
|
||||
};
|
||||
|
||||
struct UIDocumentArtifactNodeHeader {
|
||||
Core::uint32 attributeCount = 0;
|
||||
Core::uint32 childCount = 0;
|
||||
Core::uint32 line = 1;
|
||||
Core::uint32 column = 1;
|
||||
Core::uint32 selfClosing = 0;
|
||||
};
|
||||
|
||||
struct UIDocumentArtifactDiagnosticHeader {
|
||||
Core::uint32 severity = 0;
|
||||
Core::uint32 line = 1;
|
||||
Core::uint32 column = 1;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <XCEngine/Core/Asset/AssetRef.h>
|
||||
#include <XCEngine/Core/Containers/String.h>
|
||||
#include <XCEngine/Core/Types.h>
|
||||
#include <XCEngine/Resources/UI/UIDocumentTypes.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
@@ -16,6 +17,11 @@ class Material;
|
||||
|
||||
class AssetDatabase {
|
||||
public:
|
||||
struct MaintenanceStats {
|
||||
Core::uint32 importedAssetCount = 0;
|
||||
Core::uint32 removedArtifactCount = 0;
|
||||
};
|
||||
|
||||
struct ArtifactDependencyRecord {
|
||||
Containers::String path;
|
||||
Containers::String hash;
|
||||
@@ -56,6 +62,7 @@ public:
|
||||
struct ResolvedAsset {
|
||||
bool exists = false;
|
||||
bool artifactReady = false;
|
||||
bool imported = false;
|
||||
Containers::String absolutePath;
|
||||
Containers::String relativePath;
|
||||
AssetGUID assetGuid;
|
||||
@@ -67,13 +74,18 @@ public:
|
||||
|
||||
void Initialize(const Containers::String& projectRoot);
|
||||
void Shutdown();
|
||||
void Refresh();
|
||||
MaintenanceStats Refresh();
|
||||
|
||||
bool ResolvePath(const Containers::String& requestPath,
|
||||
Containers::String& outAbsolutePath,
|
||||
Containers::String& outRelativePath) const;
|
||||
bool TryGetAssetGuid(const Containers::String& requestPath, AssetGUID& outGuid) const;
|
||||
bool TryGetImportableResourceType(const Containers::String& requestPath, ResourceType& outType) const;
|
||||
bool TryGetAssetRef(const Containers::String& requestPath, ResourceType resourceType, AssetRef& outRef) const;
|
||||
bool ReimportAsset(const Containers::String& requestPath,
|
||||
ResolvedAsset& outAsset,
|
||||
MaintenanceStats* outStats = nullptr);
|
||||
bool ReimportAllAssets(MaintenanceStats* outStats = nullptr);
|
||||
bool EnsureArtifact(const Containers::String& requestPath,
|
||||
ResourceType requestedType,
|
||||
ResolvedAsset& outAsset);
|
||||
@@ -84,19 +96,21 @@ public:
|
||||
const Containers::String& GetProjectRoot() const { return m_projectRoot; }
|
||||
const Containers::String& GetAssetsRoot() const { return m_assetsRoot; }
|
||||
const Containers::String& GetLibraryRoot() const { return m_libraryRoot; }
|
||||
const Containers::String& GetLastErrorMessage() const { return m_lastErrorMessage; }
|
||||
|
||||
private:
|
||||
static constexpr Core::uint32 kCurrentImporterVersion = 4;
|
||||
static constexpr Core::uint32 kCurrentImporterVersion = 5;
|
||||
|
||||
void EnsureProjectLayout();
|
||||
void LoadSourceAssetDB();
|
||||
void SaveSourceAssetDB() const;
|
||||
void LoadArtifactDB();
|
||||
void SaveArtifactDB() const;
|
||||
void ScanAssets();
|
||||
MaintenanceStats ScanAssets();
|
||||
void ScanAssetPath(const std::filesystem::path& path,
|
||||
std::unordered_map<std::string, bool>& seenPaths);
|
||||
void RemoveMissingRecords(const std::unordered_map<std::string, bool>& seenPaths);
|
||||
Core::uint32 CleanupOrphanedArtifacts() const;
|
||||
|
||||
bool EnsureMetaForPath(const std::filesystem::path& sourcePath,
|
||||
bool isFolder,
|
||||
@@ -125,6 +139,11 @@ private:
|
||||
ArtifactRecord& outRecord);
|
||||
bool ImportShaderAsset(const SourceAssetRecord& sourceRecord,
|
||||
ArtifactRecord& outRecord);
|
||||
bool ImportUIDocumentAsset(const SourceAssetRecord& sourceRecord,
|
||||
UIDocumentKind kind,
|
||||
const char* artifactFileName,
|
||||
ResourceType resourceType,
|
||||
ArtifactRecord& outRecord);
|
||||
|
||||
Containers::String BuildArtifactKey(
|
||||
const SourceAssetRecord& sourceRecord,
|
||||
@@ -146,12 +165,15 @@ private:
|
||||
std::vector<ArtifactDependencyRecord>& outDependencies) const;
|
||||
bool CollectShaderDependencies(const SourceAssetRecord& sourceRecord,
|
||||
std::vector<ArtifactDependencyRecord>& outDependencies) const;
|
||||
void ClearLastErrorMessage();
|
||||
void SetLastErrorMessage(const Containers::String& message);
|
||||
|
||||
Containers::String m_projectRoot;
|
||||
Containers::String m_assetsRoot;
|
||||
Containers::String m_libraryRoot;
|
||||
Containers::String m_sourceDbPath;
|
||||
Containers::String m_artifactDbPath;
|
||||
Containers::String m_lastErrorMessage;
|
||||
|
||||
std::unordered_map<std::string, SourceAssetRecord> m_sourcesByPathKey;
|
||||
std::unordered_map<AssetGUID, SourceAssetRecord> m_sourcesByGuid;
|
||||
|
||||
@@ -22,7 +22,10 @@ enum class ResourceType : Core::uint8 {
|
||||
Font,
|
||||
ParticleSystem,
|
||||
Scene,
|
||||
Prefab
|
||||
Prefab,
|
||||
UIView,
|
||||
UITheme,
|
||||
UISchema
|
||||
};
|
||||
|
||||
constexpr const char* GetResourceTypeName(ResourceType type) {
|
||||
@@ -39,6 +42,9 @@ constexpr const char* GetResourceTypeName(ResourceType type) {
|
||||
case ResourceType::ParticleSystem: return "ParticleSystem";
|
||||
case ResourceType::Scene: return "Scene";
|
||||
case ResourceType::Prefab: return "Prefab";
|
||||
case ResourceType::UIView: return "UIView";
|
||||
case ResourceType::UITheme: return "UITheme";
|
||||
case ResourceType::UISchema: return "UISchema";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
@@ -89,6 +95,9 @@ template<> inline ResourceType GetResourceType<class Material>() { return Resour
|
||||
template<> inline ResourceType GetResourceType<class Shader>() { return ResourceType::Shader; }
|
||||
template<> inline ResourceType GetResourceType<class AudioClip>() { return ResourceType::AudioClip; }
|
||||
template<> inline ResourceType GetResourceType<class BinaryResource>() { return ResourceType::Binary; }
|
||||
template<> inline ResourceType GetResourceType<class UIView>() { return ResourceType::UIView; }
|
||||
template<> inline ResourceType GetResourceType<class UITheme>() { return ResourceType::UITheme; }
|
||||
template<> inline ResourceType GetResourceType<class UISchema>() { return ResourceType::UISchema; }
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
#include <XCEngine/Resources/Shader/ShaderLoader.h>
|
||||
#include <XCEngine/Resources/AudioClip/AudioClip.h>
|
||||
#include <XCEngine/Resources/AudioClip/AudioLoader.h>
|
||||
#include <XCEngine/Resources/UI/UIDocumentTypes.h>
|
||||
#include <XCEngine/Resources/UI/UIDocumentCompiler.h>
|
||||
#include <XCEngine/Resources/UI/UIDocuments.h>
|
||||
#include <XCEngine/Resources/UI/UIDocumentLoaders.h>
|
||||
|
||||
#include <XCEngine/Core/IO/ResourceFileSystem.h>
|
||||
#include <XCEngine/Core/IO/FileArchive.h>
|
||||
|
||||
167
engine/src/Resources/UI/UIDocumentLoaders.cpp
Normal file
167
engine/src/Resources/UI/UIDocumentLoaders.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include <XCEngine/Resources/UI/UIDocumentLoaders.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
namespace {
|
||||
|
||||
Containers::String GetPathExtension(const Containers::String& path) {
|
||||
const std::filesystem::path fsPath(path.CStr());
|
||||
const std::string extension = fsPath.has_extension()
|
||||
? fsPath.extension().generic_string()
|
||||
: std::string();
|
||||
if (!extension.empty() && extension.front() == '.') {
|
||||
return Containers::String(extension.substr(1).c_str());
|
||||
}
|
||||
return Containers::String(extension.c_str());
|
||||
}
|
||||
|
||||
Containers::Array<Containers::String> BuildSingleExtensionList(
|
||||
const char* sourceExtension,
|
||||
const char* artifactExtension) {
|
||||
Containers::Array<Containers::String> extensions;
|
||||
extensions.PushBack(sourceExtension);
|
||||
extensions.PushBack(artifactExtension);
|
||||
return extensions;
|
||||
}
|
||||
|
||||
bool MatchesAnyExtension(
|
||||
const Containers::String& path,
|
||||
const char* sourceExtension,
|
||||
const char* artifactExtension) {
|
||||
const Containers::String extension = GetPathExtension(path).ToLower();
|
||||
return extension == sourceExtension || extension == artifactExtension;
|
||||
}
|
||||
|
||||
Containers::String BuildDocumentDisplayName(
|
||||
const Containers::String& path,
|
||||
const UIDocumentModel& document) {
|
||||
if (!document.displayName.Empty()) {
|
||||
return document.displayName;
|
||||
}
|
||||
|
||||
const std::filesystem::path fsPath(path.CStr());
|
||||
const std::string stem = fsPath.stem().generic_string();
|
||||
return stem.empty() ? path : Containers::String(stem.c_str());
|
||||
}
|
||||
|
||||
template <typename TDocumentResource>
|
||||
LoadResult BuildDocumentLoadResult(
|
||||
const Containers::String& path,
|
||||
UIDocumentCompileResult& compileResult) {
|
||||
if (!compileResult.succeeded || !compileResult.document.valid) {
|
||||
return LoadResult(compileResult.errorMessage);
|
||||
}
|
||||
|
||||
auto* resource = new TDocumentResource();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = BuildDocumentDisplayName(path, compileResult.document);
|
||||
params.path = compileResult.document.sourcePath.Empty() ? path : compileResult.document.sourcePath;
|
||||
params.guid = ResourceGUID::Generate(params.path);
|
||||
resource->Initialize(params);
|
||||
resource->SetDocumentModel(std::move(compileResult.document));
|
||||
return LoadResult(resource);
|
||||
}
|
||||
|
||||
bool LoadDocumentWithKind(
|
||||
const Containers::String& path,
|
||||
UIDocumentKind kind,
|
||||
const char* artifactExtension,
|
||||
UIDocumentCompileResult& compileResult) {
|
||||
const Containers::String extension = GetPathExtension(path).ToLower();
|
||||
if (extension == artifactExtension) {
|
||||
if (!LoadUIDocumentArtifact(path, kind, compileResult)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CompileUIDocument(
|
||||
UIDocumentCompileRequest{kind, path, GetUIDocumentDefaultRootTag(kind)},
|
||||
compileResult)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Containers::Array<Containers::String> UIViewLoader::GetSupportedExtensions() const {
|
||||
return BuildSingleExtensionList("xcui", "xcuiasset");
|
||||
}
|
||||
|
||||
bool UIViewLoader::CanLoad(const Containers::String& path) const {
|
||||
return MatchesAnyExtension(path, "xcui", "xcuiasset");
|
||||
}
|
||||
|
||||
bool UIViewLoader::CompileDocument(const Containers::String& path, UIDocumentCompileResult& outResult) const {
|
||||
return CompileUIDocument(
|
||||
UIDocumentCompileRequest{UIDocumentKind::View, path, GetUIDocumentDefaultRootTag(UIDocumentKind::View)},
|
||||
outResult);
|
||||
}
|
||||
|
||||
LoadResult UIViewLoader::Load(const Containers::String& path, const ImportSettings* settings) {
|
||||
(void)settings;
|
||||
|
||||
UIDocumentCompileResult compileResult = {};
|
||||
if (!LoadDocumentWithKind(path, UIDocumentKind::View, "xcuiasset", compileResult)) {
|
||||
return LoadResult(compileResult.errorMessage);
|
||||
}
|
||||
|
||||
return BuildDocumentLoadResult<UIView>(path, compileResult);
|
||||
}
|
||||
|
||||
Containers::Array<Containers::String> UIThemeLoader::GetSupportedExtensions() const {
|
||||
return BuildSingleExtensionList("xctheme", "xcthemeasset");
|
||||
}
|
||||
|
||||
bool UIThemeLoader::CanLoad(const Containers::String& path) const {
|
||||
return MatchesAnyExtension(path, "xctheme", "xcthemeasset");
|
||||
}
|
||||
|
||||
bool UIThemeLoader::CompileDocument(const Containers::String& path, UIDocumentCompileResult& outResult) const {
|
||||
return CompileUIDocument(
|
||||
UIDocumentCompileRequest{UIDocumentKind::Theme, path, GetUIDocumentDefaultRootTag(UIDocumentKind::Theme)},
|
||||
outResult);
|
||||
}
|
||||
|
||||
LoadResult UIThemeLoader::Load(const Containers::String& path, const ImportSettings* settings) {
|
||||
(void)settings;
|
||||
|
||||
UIDocumentCompileResult compileResult = {};
|
||||
if (!LoadDocumentWithKind(path, UIDocumentKind::Theme, "xcthemeasset", compileResult)) {
|
||||
return LoadResult(compileResult.errorMessage);
|
||||
}
|
||||
|
||||
return BuildDocumentLoadResult<UITheme>(path, compileResult);
|
||||
}
|
||||
|
||||
Containers::Array<Containers::String> UISchemaLoader::GetSupportedExtensions() const {
|
||||
return BuildSingleExtensionList("xcschema", "xcschemaasset");
|
||||
}
|
||||
|
||||
bool UISchemaLoader::CanLoad(const Containers::String& path) const {
|
||||
return MatchesAnyExtension(path, "xcschema", "xcschemaasset");
|
||||
}
|
||||
|
||||
bool UISchemaLoader::CompileDocument(const Containers::String& path, UIDocumentCompileResult& outResult) const {
|
||||
return CompileUIDocument(
|
||||
UIDocumentCompileRequest{UIDocumentKind::Schema, path, GetUIDocumentDefaultRootTag(UIDocumentKind::Schema)},
|
||||
outResult);
|
||||
}
|
||||
|
||||
LoadResult UISchemaLoader::Load(const Containers::String& path, const ImportSettings* settings) {
|
||||
(void)settings;
|
||||
|
||||
UIDocumentCompileResult compileResult = {};
|
||||
if (!LoadDocumentWithKind(path, UIDocumentKind::Schema, "xcschemaasset", compileResult)) {
|
||||
return LoadResult(compileResult.errorMessage);
|
||||
}
|
||||
|
||||
return BuildDocumentLoadResult<UISchema>(path, compileResult);
|
||||
}
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <XCEngine/Core/Asset/ResourceTypes.h>
|
||||
#include <XCEngine/Core/Types.h>
|
||||
#include <XCEngine/Resources/UI/UIDocuments.h>
|
||||
|
||||
using namespace XCEngine::Resources;
|
||||
|
||||
@@ -14,12 +15,24 @@ TEST(Resources_Types, ResourceType_EnumValues) {
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::Shader), 4);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::AudioClip), 5);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::Binary), 6);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::AnimationClip), 7);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::Skeleton), 8);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::Font), 9);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::ParticleSystem), 10);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::Scene), 11);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::Prefab), 12);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::UIView), 13);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::UITheme), 14);
|
||||
EXPECT_EQ(static_cast<uint8_t>(ResourceType::UISchema), 15);
|
||||
}
|
||||
|
||||
TEST(Resources_Types, GetResourceTypeName) {
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::Texture), "Texture");
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::Mesh), "Mesh");
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::Material), "Material");
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::UIView), "UIView");
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::UITheme), "UITheme");
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::UISchema), "UISchema");
|
||||
EXPECT_STREQ(GetResourceTypeName(ResourceType::Unknown), "Unknown");
|
||||
}
|
||||
|
||||
@@ -30,6 +43,9 @@ TEST(Resources_Types, GetResourceType_TemplateSpecializations) {
|
||||
EXPECT_EQ(GetResourceType<Shader>(), ResourceType::Shader);
|
||||
EXPECT_EQ(GetResourceType<AudioClip>(), ResourceType::AudioClip);
|
||||
EXPECT_EQ(GetResourceType<BinaryResource>(), ResourceType::Binary);
|
||||
EXPECT_EQ(GetResourceType<UIView>(), ResourceType::UIView);
|
||||
EXPECT_EQ(GetResourceType<UITheme>(), ResourceType::UITheme);
|
||||
EXPECT_EQ(GetResourceType<UISchema>(), ResourceType::UISchema);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -7,3 +7,4 @@ add_subdirectory(Mesh)
|
||||
add_subdirectory(Material)
|
||||
add_subdirectory(Shader)
|
||||
add_subdirectory(AudioClip)
|
||||
add_subdirectory(UI)
|
||||
|
||||
Reference in New Issue
Block a user