feat: expand editor scripting asset and viewport flow
This commit is contained in:
@@ -20,6 +20,10 @@ bool ShouldTraceMeshPath(const std::string& path) {
|
||||
path.find("backpack") != std::string::npos;
|
||||
}
|
||||
|
||||
bool HasVirtualPathScheme(const std::string& path) {
|
||||
return path.find("://") != std::string::npos;
|
||||
}
|
||||
|
||||
std::string EncodeAssetRef(const Resources::AssetRef& assetRef) {
|
||||
if (!assetRef.IsValid()) {
|
||||
return std::string();
|
||||
@@ -67,17 +71,20 @@ struct MeshFilterComponent::PendingMeshLoadState {
|
||||
};
|
||||
|
||||
Resources::Mesh* MeshFilterComponent::GetMesh() const {
|
||||
const_cast<MeshFilterComponent*>(this)->EnsureDeferredAsyncMeshLoadStarted();
|
||||
const_cast<MeshFilterComponent*>(this)->ResolvePendingMesh();
|
||||
return m_mesh.Get();
|
||||
}
|
||||
|
||||
const Resources::ResourceHandle<Resources::Mesh>& MeshFilterComponent::GetMeshHandle() const {
|
||||
const_cast<MeshFilterComponent*>(this)->EnsureDeferredAsyncMeshLoadStarted();
|
||||
const_cast<MeshFilterComponent*>(this)->ResolvePendingMesh();
|
||||
return m_mesh;
|
||||
}
|
||||
|
||||
void MeshFilterComponent::SetMeshPath(const std::string& meshPath) {
|
||||
m_pendingMeshLoad.reset();
|
||||
m_asyncMeshLoadRequested = false;
|
||||
m_meshPath = meshPath;
|
||||
if (m_meshPath.empty()) {
|
||||
m_mesh.Reset();
|
||||
@@ -101,6 +108,7 @@ void MeshFilterComponent::SetMeshPath(const std::string& meshPath) {
|
||||
|
||||
void MeshFilterComponent::SetMesh(const Resources::ResourceHandle<Resources::Mesh>& mesh) {
|
||||
m_pendingMeshLoad.reset();
|
||||
m_asyncMeshLoadRequested = false;
|
||||
m_mesh = mesh;
|
||||
m_meshPath = mesh.Get() != nullptr ? ToStdString(mesh->GetPath()) : std::string();
|
||||
if (m_meshPath.empty()) {
|
||||
@@ -116,18 +124,29 @@ void MeshFilterComponent::SetMesh(Resources::Mesh* mesh) {
|
||||
|
||||
void MeshFilterComponent::ClearMesh() {
|
||||
m_pendingMeshLoad.reset();
|
||||
m_asyncMeshLoadRequested = false;
|
||||
m_mesh.Reset();
|
||||
m_meshPath.clear();
|
||||
m_meshRef.Reset();
|
||||
}
|
||||
|
||||
void MeshFilterComponent::Serialize(std::ostream& os) const {
|
||||
os << "mesh=" << m_meshPath << ";";
|
||||
os << "meshRef=" << EncodeAssetRef(m_meshRef) << ";";
|
||||
Resources::AssetRef meshRef = m_meshRef;
|
||||
if (!meshRef.IsValid() &&
|
||||
!m_meshPath.empty() &&
|
||||
!HasVirtualPathScheme(m_meshPath) &&
|
||||
Resources::ResourceManager::Get().TryGetAssetRef(m_meshPath.c_str(), Resources::ResourceType::Mesh, meshRef)) {
|
||||
}
|
||||
|
||||
os << "meshRef=" << EncodeAssetRef(meshRef) << ";";
|
||||
if (!meshRef.IsValid() && !m_meshPath.empty()) {
|
||||
os << "meshPath=" << m_meshPath << ";";
|
||||
}
|
||||
}
|
||||
|
||||
void MeshFilterComponent::Deserialize(std::istream& is) {
|
||||
m_pendingMeshLoad.reset();
|
||||
m_asyncMeshLoadRequested = false;
|
||||
m_mesh.Reset();
|
||||
m_meshPath.clear();
|
||||
m_meshRef.Reset();
|
||||
@@ -148,7 +167,7 @@ void MeshFilterComponent::Deserialize(std::istream& is) {
|
||||
const std::string key = token.substr(0, eqPos);
|
||||
const std::string value = token.substr(eqPos + 1);
|
||||
|
||||
if (key == "mesh") {
|
||||
if (key == "mesh" || key == "meshPath") {
|
||||
pendingMeshPath = value;
|
||||
} else if (key == "meshRef") {
|
||||
TryDecodeAssetRef(value, pendingMeshRef);
|
||||
@@ -172,7 +191,6 @@ void MeshFilterComponent::Deserialize(std::istream& is) {
|
||||
if (ShouldTraceMeshPath(m_meshPath)) {
|
||||
TraceMeshFilter(*this, std::string("Resolved meshRef to path=") + m_meshPath);
|
||||
}
|
||||
BeginAsyncMeshLoad(m_meshPath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -191,7 +209,6 @@ void MeshFilterComponent::Deserialize(std::istream& is) {
|
||||
if (!Resources::ResourceManager::Get().TryGetAssetRef(m_meshPath.c_str(), Resources::ResourceType::Mesh, m_meshRef)) {
|
||||
m_meshRef.Reset();
|
||||
}
|
||||
BeginAsyncMeshLoad(m_meshPath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -202,10 +219,12 @@ void MeshFilterComponent::Deserialize(std::istream& is) {
|
||||
void MeshFilterComponent::BeginAsyncMeshLoad(const std::string& meshPath) {
|
||||
if (meshPath.empty()) {
|
||||
m_pendingMeshLoad.reset();
|
||||
m_asyncMeshLoadRequested = false;
|
||||
m_mesh.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
m_asyncMeshLoadRequested = true;
|
||||
m_mesh.Reset();
|
||||
m_pendingMeshLoad = std::make_shared<PendingMeshLoadState>();
|
||||
if (ShouldTraceMeshPath(meshPath)) {
|
||||
@@ -219,7 +238,15 @@ void MeshFilterComponent::BeginAsyncMeshLoad(const std::string& meshPath) {
|
||||
state->result = std::move(result);
|
||||
state->completed = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void MeshFilterComponent::EnsureDeferredAsyncMeshLoadStarted() {
|
||||
if (m_asyncMeshLoadRequested || m_mesh.Get() != nullptr || m_meshPath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BeginAsyncMeshLoad(m_meshPath);
|
||||
}
|
||||
|
||||
void MeshFilterComponent::ResolvePendingMesh() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Core/Asset/ResourceManager.h"
|
||||
#include "Debug/Logger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -21,6 +22,10 @@ bool ShouldTraceMaterialPath(const std::string& path) {
|
||||
path.find("New Material.mat") != std::string::npos;
|
||||
}
|
||||
|
||||
bool HasVirtualPathScheme(const std::string& path) {
|
||||
return path.find("://") != std::string::npos;
|
||||
}
|
||||
|
||||
std::string EncodeAssetRef(const Resources::AssetRef& assetRef) {
|
||||
if (!assetRef.IsValid()) {
|
||||
return std::string();
|
||||
@@ -145,11 +150,13 @@ struct MeshRendererComponent::PendingMaterialLoadState {
|
||||
};
|
||||
|
||||
Resources::Material* MeshRendererComponent::GetMaterial(size_t index) const {
|
||||
const_cast<MeshRendererComponent*>(this)->EnsureDeferredAsyncMaterialLoadStarted(index);
|
||||
const_cast<MeshRendererComponent*>(this)->ResolvePendingMaterials();
|
||||
return index < m_materials.size() ? m_materials[index].Get() : nullptr;
|
||||
}
|
||||
|
||||
const Resources::ResourceHandle<Resources::Material>& MeshRendererComponent::GetMaterialHandle(size_t index) const {
|
||||
const_cast<MeshRendererComponent*>(this)->EnsureDeferredAsyncMaterialLoadStarted(index);
|
||||
const_cast<MeshRendererComponent*>(this)->ResolvePendingMaterials();
|
||||
static const Resources::ResourceHandle<Resources::Material> kNullHandle;
|
||||
return index < m_materials.size() ? m_materials[index] : kNullHandle;
|
||||
@@ -163,6 +170,7 @@ const std::string& MeshRendererComponent::GetMaterialPath(size_t index) const {
|
||||
void MeshRendererComponent::SetMaterialPath(size_t index, const std::string& materialPath) {
|
||||
EnsureMaterialSlot(index);
|
||||
m_pendingMaterialLoads[index].reset();
|
||||
m_asyncMaterialLoadRequested[index] = false;
|
||||
m_materialPaths[index] = materialPath;
|
||||
if (materialPath.empty()) {
|
||||
m_materials[index].Reset();
|
||||
@@ -188,6 +196,7 @@ void MeshRendererComponent::SetMaterialPath(size_t index, const std::string& mat
|
||||
void MeshRendererComponent::SetMaterial(size_t index, const Resources::ResourceHandle<Resources::Material>& material) {
|
||||
EnsureMaterialSlot(index);
|
||||
m_pendingMaterialLoads[index].reset();
|
||||
m_asyncMaterialLoadRequested[index] = false;
|
||||
m_materials[index] = material;
|
||||
m_materialPaths[index] = MaterialPathFromHandle(material);
|
||||
if (m_materialPaths[index].empty() ||
|
||||
@@ -206,6 +215,8 @@ void MeshRendererComponent::SetMaterials(const std::vector<Resources::ResourceHa
|
||||
m_materialRefs.resize(materials.size());
|
||||
m_pendingMaterialLoads.clear();
|
||||
m_pendingMaterialLoads.resize(materials.size());
|
||||
m_asyncMaterialLoadRequested.clear();
|
||||
m_asyncMaterialLoadRequested.resize(materials.size(), false);
|
||||
for (size_t i = 0; i < materials.size(); ++i) {
|
||||
m_materialPaths[i] = MaterialPathFromHandle(materials[i]);
|
||||
if (m_materialPaths[i].empty() ||
|
||||
@@ -220,23 +231,45 @@ void MeshRendererComponent::ClearMaterials() {
|
||||
m_materialPaths.clear();
|
||||
m_materialRefs.clear();
|
||||
m_pendingMaterialLoads.clear();
|
||||
m_asyncMaterialLoadRequested.clear();
|
||||
}
|
||||
|
||||
void MeshRendererComponent::Serialize(std::ostream& os) const {
|
||||
os << "materials=";
|
||||
for (size_t i = 0; i < m_materialPaths.size(); ++i) {
|
||||
const size_t slotCount = std::max(m_materialPaths.size(), m_materialRefs.size());
|
||||
std::vector<Resources::AssetRef> serializedRefs = m_materialRefs;
|
||||
serializedRefs.resize(slotCount);
|
||||
std::vector<std::string> serializedPaths = m_materialPaths;
|
||||
serializedPaths.resize(slotCount);
|
||||
std::vector<std::string> fallbackPaths(slotCount);
|
||||
for (size_t i = 0; i < slotCount; ++i) {
|
||||
if (!serializedRefs[i].IsValid() &&
|
||||
!serializedPaths[i].empty() &&
|
||||
!HasVirtualPathScheme(serializedPaths[i]) &&
|
||||
Resources::ResourceManager::Get().TryGetAssetRef(
|
||||
serializedPaths[i].c_str(),
|
||||
Resources::ResourceType::Material,
|
||||
serializedRefs[i])) {
|
||||
}
|
||||
|
||||
if (!serializedRefs[i].IsValid()) {
|
||||
fallbackPaths[i] = serializedPaths[i];
|
||||
}
|
||||
}
|
||||
|
||||
os << "materialPaths=";
|
||||
for (size_t i = 0; i < slotCount; ++i) {
|
||||
if (i > 0) {
|
||||
os << "|";
|
||||
}
|
||||
os << m_materialPaths[i];
|
||||
os << fallbackPaths[i];
|
||||
}
|
||||
os << ";";
|
||||
os << "materialRefs=";
|
||||
for (size_t i = 0; i < m_materialRefs.size(); ++i) {
|
||||
for (size_t i = 0; i < serializedRefs.size(); ++i) {
|
||||
if (i > 0) {
|
||||
os << "|";
|
||||
}
|
||||
os << EncodeAssetRef(m_materialRefs[i]);
|
||||
os << EncodeAssetRef(serializedRefs[i]);
|
||||
}
|
||||
os << ";";
|
||||
os << "castShadows=" << (m_castShadows ? 1 : 0) << ";";
|
||||
@@ -265,11 +298,12 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
|
||||
const std::string key = token.substr(0, eqPos);
|
||||
const std::string value = token.substr(eqPos + 1);
|
||||
|
||||
if (key == "materials") {
|
||||
if (key == "materials" || key == "materialPaths") {
|
||||
m_materialPaths = SplitMaterialPaths(value);
|
||||
m_materials.resize(m_materialPaths.size());
|
||||
m_materialRefs.resize(m_materialPaths.size());
|
||||
m_pendingMaterialLoads.resize(m_materialPaths.size());
|
||||
m_asyncMaterialLoadRequested.resize(m_materialPaths.size(), false);
|
||||
} else if (key == "materialRefs") {
|
||||
pendingMaterialRefs = SplitMaterialRefs(value);
|
||||
} else if (key == "castShadows") {
|
||||
@@ -286,6 +320,7 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
|
||||
m_materials.resize(pendingMaterialRefs.size());
|
||||
m_materialRefs.resize(pendingMaterialRefs.size());
|
||||
m_pendingMaterialLoads.resize(pendingMaterialRefs.size());
|
||||
m_asyncMaterialLoadRequested.resize(pendingMaterialRefs.size(), false);
|
||||
}
|
||||
|
||||
if (ShouldTraceAnyMaterialPath(m_materialPaths)) {
|
||||
@@ -310,7 +345,6 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
|
||||
std::string("Resolved materialRef slot=") + std::to_string(i) +
|
||||
" path=" + m_materialPaths[i]);
|
||||
}
|
||||
BeginAsyncMaterialLoad(i, m_materialPaths[i]);
|
||||
restoredOrQueued = true;
|
||||
}
|
||||
}
|
||||
@@ -336,7 +370,6 @@ void MeshRendererComponent::Deserialize(std::istream& is) {
|
||||
m_materialRefs[i])) {
|
||||
m_materialRefs[i].Reset();
|
||||
}
|
||||
BeginAsyncMaterialLoad(i, m_materialPaths[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -349,10 +382,12 @@ void MeshRendererComponent::BeginAsyncMaterialLoad(size_t index, const std::stri
|
||||
EnsureMaterialSlot(index);
|
||||
if (materialPath.empty()) {
|
||||
m_pendingMaterialLoads[index].reset();
|
||||
m_asyncMaterialLoadRequested[index] = false;
|
||||
m_materials[index].Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
m_asyncMaterialLoadRequested[index] = true;
|
||||
m_materials[index].Reset();
|
||||
m_pendingMaterialLoads[index] = std::make_shared<PendingMaterialLoadState>();
|
||||
if (ShouldTraceMaterialPath(materialPath)) {
|
||||
@@ -369,7 +404,22 @@ void MeshRendererComponent::BeginAsyncMaterialLoad(size_t index, const std::stri
|
||||
state->result = std::move(result);
|
||||
state->completed = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void MeshRendererComponent::EnsureDeferredAsyncMaterialLoadStarted(size_t index) {
|
||||
if (index >= m_materialPaths.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureMaterialSlot(index);
|
||||
if (m_asyncMaterialLoadRequested[index] ||
|
||||
m_materials[index].Get() != nullptr ||
|
||||
m_materialPaths[index].empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BeginAsyncMaterialLoad(index, m_materialPaths[index]);
|
||||
}
|
||||
|
||||
void MeshRendererComponent::ResolvePendingMaterials() {
|
||||
@@ -428,6 +478,9 @@ void MeshRendererComponent::EnsureMaterialSlot(size_t index) {
|
||||
if (index >= m_pendingMaterialLoads.size()) {
|
||||
m_pendingMaterialLoads.resize(index + 1);
|
||||
}
|
||||
if (index >= m_asyncMaterialLoadRequested.size()) {
|
||||
m_asyncMaterialLoadRequested.resize(index + 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
std::string MeshRendererComponent::MaterialPathFromHandle(const Resources::ResourceHandle<Resources::Material>& material) {
|
||||
|
||||
Reference in New Issue
Block a user