2026-03-26 01:26:26 +08:00
|
|
|
#include "Components/CameraComponent.h"
|
|
|
|
|
|
2026-04-06 00:39:08 +08:00
|
|
|
#include "Core/Asset/ResourceManager.h"
|
|
|
|
|
#include "Resources/Material/Material.h"
|
|
|
|
|
|
2026-03-26 01:26:26 +08:00
|
|
|
#include <algorithm>
|
2026-04-06 14:56:43 +08:00
|
|
|
#include <cctype>
|
2026-03-26 01:26:26 +08:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Components {
|
|
|
|
|
|
2026-04-06 00:39:08 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
std::string ToStdString(const Containers::String& value) {
|
|
|
|
|
return std::string(value.CStr());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ToStdString(assetRef.assetGuid.ToString()) + "," +
|
|
|
|
|
std::to_string(assetRef.localID) + "," +
|
|
|
|
|
std::to_string(static_cast<int>(assetRef.resourceType));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TryDecodeAssetRef(const std::string& value, Resources::AssetRef& outRef) {
|
|
|
|
|
const size_t firstComma = value.find(',');
|
|
|
|
|
const size_t secondComma = firstComma == std::string::npos ? std::string::npos : value.find(',', firstComma + 1);
|
|
|
|
|
if (firstComma == std::string::npos || secondComma == std::string::npos) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outRef.assetGuid = Resources::AssetGUID::ParseOrDefault(Containers::String(value.substr(0, firstComma).c_str()));
|
|
|
|
|
outRef.localID = static_cast<Resources::LocalID>(std::stoull(value.substr(firstComma + 1, secondComma - firstComma - 1)));
|
|
|
|
|
outRef.resourceType = static_cast<Resources::ResourceType>(std::stoi(value.substr(secondComma + 1)));
|
|
|
|
|
return outRef.IsValid();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 14:37:54 +08:00
|
|
|
std::string EncodeVector4(const Math::Vector4& value) {
|
|
|
|
|
std::ostringstream stream;
|
|
|
|
|
stream << value.x << "," << value.y << "," << value.z << "," << value.w;
|
|
|
|
|
return stream.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TryParseVector4(const std::string& value, Math::Vector4& outValue) {
|
|
|
|
|
std::string normalized = value;
|
|
|
|
|
std::replace(normalized.begin(), normalized.end(), ',', ' ');
|
|
|
|
|
std::istringstream stream(normalized);
|
|
|
|
|
stream >> outValue.x >> outValue.y >> outValue.z >> outValue.w;
|
|
|
|
|
return !stream.fail();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 14:56:43 +08:00
|
|
|
Rendering::CameraPostProcessStack BuildColorScalePostProcessStack(
|
|
|
|
|
const std::vector<Math::Vector4>& values) {
|
|
|
|
|
Rendering::CameraPostProcessStack passes;
|
|
|
|
|
passes.reserve(values.size());
|
|
|
|
|
for (const Math::Vector4& value : values) {
|
|
|
|
|
passes.push_back(Rendering::CameraPostProcessPassDesc::MakeColorScale(value));
|
|
|
|
|
}
|
|
|
|
|
return passes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t FindFirstColorScalePassIndex(const Rendering::CameraPostProcessStack& passes) {
|
|
|
|
|
for (size_t index = 0; index < passes.size(); ++index) {
|
|
|
|
|
if (passes[index].type == Rendering::CameraPostProcessPassType::ColorScale) {
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return passes.size();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 00:39:08 +08:00
|
|
|
} // namespace
|
|
|
|
|
|
2026-04-06 14:56:43 +08:00
|
|
|
void CameraComponent::SetPostProcessPasses(const Rendering::CameraPostProcessStack& values) {
|
|
|
|
|
m_postProcessPasses = values;
|
|
|
|
|
for (const Rendering::CameraPostProcessPassDesc& pass : m_postProcessPasses) {
|
|
|
|
|
if (pass.type == Rendering::CameraPostProcessPassType::ColorScale) {
|
|
|
|
|
m_colorScalePostProcessDefaultScale = pass.colorScale.scale;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::AddPostProcessPass(const Rendering::CameraPostProcessPassDesc& value) {
|
|
|
|
|
if (!value.IsValid()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value.type == Rendering::CameraPostProcessPassType::ColorScale &&
|
|
|
|
|
FindFirstColorScalePassIndex(m_postProcessPasses) == m_postProcessPasses.size()) {
|
|
|
|
|
m_colorScalePostProcessDefaultScale = value.colorScale.scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_postProcessPasses.push_back(value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 14:37:54 +08:00
|
|
|
bool CameraComponent::IsColorScalePostProcessEnabled() const {
|
2026-04-06 14:56:43 +08:00
|
|
|
return FindFirstColorScalePassIndex(m_postProcessPasses) != m_postProcessPasses.size();
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetColorScalePostProcessEnabled(bool value) {
|
|
|
|
|
if (value) {
|
2026-04-06 14:56:43 +08:00
|
|
|
if (!IsColorScalePostProcessEnabled()) {
|
|
|
|
|
m_postProcessPasses.push_back(
|
|
|
|
|
Rendering::CameraPostProcessPassDesc::MakeColorScale(
|
|
|
|
|
m_colorScalePostProcessDefaultScale));
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 14:56:43 +08:00
|
|
|
ClearColorScalePostProcessPasses();
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Math::Vector4& CameraComponent::GetColorScalePostProcessScale() const {
|
2026-04-06 14:56:43 +08:00
|
|
|
const size_t firstColorScalePassIndex = FindFirstColorScalePassIndex(m_postProcessPasses);
|
|
|
|
|
return firstColorScalePassIndex == m_postProcessPasses.size()
|
2026-04-06 14:37:54 +08:00
|
|
|
? m_colorScalePostProcessDefaultScale
|
2026-04-06 14:56:43 +08:00
|
|
|
: m_postProcessPasses[firstColorScalePassIndex].colorScale.scale;
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetColorScalePostProcessScale(const Math::Vector4& value) {
|
|
|
|
|
m_colorScalePostProcessDefaultScale = value;
|
2026-04-06 14:56:43 +08:00
|
|
|
const size_t firstColorScalePassIndex = FindFirstColorScalePassIndex(m_postProcessPasses);
|
|
|
|
|
if (firstColorScalePassIndex != m_postProcessPasses.size()) {
|
|
|
|
|
m_postProcessPasses[firstColorScalePassIndex].colorScale.scale = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<Math::Vector4> CameraComponent::GetColorScalePostProcessPasses() const {
|
|
|
|
|
std::vector<Math::Vector4> values;
|
|
|
|
|
values.reserve(m_postProcessPasses.size());
|
|
|
|
|
for (const Rendering::CameraPostProcessPassDesc& pass : m_postProcessPasses) {
|
|
|
|
|
if (pass.type == Rendering::CameraPostProcessPassType::ColorScale) {
|
|
|
|
|
values.push_back(pass.colorScale.scale);
|
|
|
|
|
}
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
2026-04-06 14:56:43 +08:00
|
|
|
return values;
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetColorScalePostProcessPasses(const std::vector<Math::Vector4>& values) {
|
2026-04-06 14:56:43 +08:00
|
|
|
SetPostProcessPasses(BuildColorScalePostProcessStack(values));
|
|
|
|
|
if (!values.empty()) {
|
|
|
|
|
m_colorScalePostProcessDefaultScale = values.front();
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::AddColorScalePostProcessPass(const Math::Vector4& value) {
|
2026-04-06 14:56:43 +08:00
|
|
|
if (!IsColorScalePostProcessEnabled()) {
|
2026-04-06 14:37:54 +08:00
|
|
|
m_colorScalePostProcessDefaultScale = value;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 14:56:43 +08:00
|
|
|
m_postProcessPasses.push_back(Rendering::CameraPostProcessPassDesc::MakeColorScale(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::ClearColorScalePostProcessPasses() {
|
|
|
|
|
m_postProcessPasses.erase(
|
|
|
|
|
std::remove_if(
|
|
|
|
|
m_postProcessPasses.begin(),
|
|
|
|
|
m_postProcessPasses.end(),
|
|
|
|
|
[](const Rendering::CameraPostProcessPassDesc& pass) {
|
|
|
|
|
return pass.type == Rendering::CameraPostProcessPassType::ColorScale;
|
|
|
|
|
}),
|
|
|
|
|
m_postProcessPasses.end());
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 01:26:26 +08:00
|
|
|
void CameraComponent::SetFieldOfView(float value) {
|
|
|
|
|
m_fieldOfView = std::clamp(value, 1.0f, 179.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetOrthographicSize(float value) {
|
|
|
|
|
m_orthographicSize = std::max(0.001f, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetNearClipPlane(float value) {
|
|
|
|
|
m_nearClipPlane = std::max(0.001f, value);
|
|
|
|
|
if (m_farClipPlane <= m_nearClipPlane) {
|
|
|
|
|
m_farClipPlane = m_nearClipPlane + 0.001f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetFarClipPlane(float value) {
|
|
|
|
|
m_farClipPlane = std::max(m_nearClipPlane + 0.001f, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 13:01:11 +08:00
|
|
|
void CameraComponent::SetViewportRect(const Math::Rect& value) {
|
|
|
|
|
const float x = std::clamp(value.x, 0.0f, 1.0f);
|
|
|
|
|
const float y = std::clamp(value.y, 0.0f, 1.0f);
|
|
|
|
|
const float width = std::clamp(value.width, 0.0f, 1.0f);
|
|
|
|
|
const float height = std::clamp(value.height, 0.0f, 1.0f);
|
|
|
|
|
const float right = std::min(1.0f, x + width);
|
|
|
|
|
const float bottom = std::min(1.0f, y + height);
|
|
|
|
|
m_viewportRect = Math::Rect(x, y, right - x, bottom - y);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-06 00:39:08 +08:00
|
|
|
void CameraComponent::SetSkyboxMaterialPath(const std::string& materialPath) {
|
|
|
|
|
m_skyboxMaterialPath = materialPath;
|
|
|
|
|
m_skyboxMaterialRef.Reset();
|
|
|
|
|
|
|
|
|
|
if (materialPath.empty()) {
|
|
|
|
|
m_skyboxMaterial.Reset();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_skyboxMaterial = Resources::ResourceManager::Get().Load<Resources::Material>(materialPath.c_str());
|
|
|
|
|
if (!Resources::ResourceManager::Get().TryGetAssetRef(
|
|
|
|
|
materialPath.c_str(),
|
|
|
|
|
Resources::ResourceType::Material,
|
|
|
|
|
m_skyboxMaterialRef)) {
|
|
|
|
|
m_skyboxMaterialRef.Reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetSkyboxMaterial(const Resources::ResourceHandle<Resources::Material>& material) {
|
|
|
|
|
m_skyboxMaterial = material;
|
|
|
|
|
m_skyboxMaterialPath =
|
|
|
|
|
material.Get() != nullptr
|
|
|
|
|
? ToStdString(material->GetPath())
|
|
|
|
|
: std::string();
|
|
|
|
|
|
|
|
|
|
if (m_skyboxMaterialPath.empty() ||
|
|
|
|
|
!Resources::ResourceManager::Get().TryGetAssetRef(
|
|
|
|
|
m_skyboxMaterialPath.c_str(),
|
|
|
|
|
Resources::ResourceType::Material,
|
|
|
|
|
m_skyboxMaterialRef)) {
|
|
|
|
|
m_skyboxMaterialRef.Reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::SetSkyboxMaterial(Resources::Material* material) {
|
|
|
|
|
SetSkyboxMaterial(Resources::ResourceHandle<Resources::Material>(material));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 01:26:26 +08:00
|
|
|
void CameraComponent::Serialize(std::ostream& os) const {
|
2026-04-06 00:39:08 +08:00
|
|
|
Resources::AssetRef serializedSkyboxMaterialRef = m_skyboxMaterialRef;
|
|
|
|
|
std::string serializedSkyboxMaterialPath = m_skyboxMaterialPath;
|
|
|
|
|
if (serializedSkyboxMaterialPath.empty() && m_skyboxMaterial.Get() != nullptr) {
|
|
|
|
|
serializedSkyboxMaterialPath = ToStdString(m_skyboxMaterial->GetPath());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!serializedSkyboxMaterialRef.IsValid() &&
|
|
|
|
|
!serializedSkyboxMaterialPath.empty() &&
|
|
|
|
|
!HasVirtualPathScheme(serializedSkyboxMaterialPath) &&
|
|
|
|
|
Resources::ResourceManager::Get().TryGetAssetRef(
|
|
|
|
|
serializedSkyboxMaterialPath.c_str(),
|
|
|
|
|
Resources::ResourceType::Material,
|
|
|
|
|
serializedSkyboxMaterialRef)) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (serializedSkyboxMaterialRef.IsValid() || !HasVirtualPathScheme(serializedSkyboxMaterialPath)) {
|
|
|
|
|
serializedSkyboxMaterialPath.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 01:26:26 +08:00
|
|
|
os << "projection=" << static_cast<int>(m_projectionType) << ";";
|
|
|
|
|
os << "fov=" << m_fieldOfView << ";";
|
|
|
|
|
os << "orthoSize=" << m_orthographicSize << ";";
|
|
|
|
|
os << "near=" << m_nearClipPlane << ";";
|
|
|
|
|
os << "far=" << m_farClipPlane << ";";
|
|
|
|
|
os << "depth=" << m_depth << ";";
|
|
|
|
|
os << "primary=" << (m_primary ? 1 : 0) << ";";
|
2026-04-01 01:33:46 +08:00
|
|
|
os << "clearMode=" << static_cast<int>(m_clearMode) << ";";
|
2026-04-01 13:10:32 +08:00
|
|
|
os << "stackType=" << static_cast<int>(m_stackType) << ";";
|
2026-04-01 01:42:06 +08:00
|
|
|
os << "cullingMask=" << m_cullingMask << ";";
|
2026-04-01 13:01:11 +08:00
|
|
|
os << "viewportRect=" << m_viewportRect.x << "," << m_viewportRect.y << "," << m_viewportRect.width << "," << m_viewportRect.height << ";";
|
2026-03-26 01:26:26 +08:00
|
|
|
os << "clearColor=" << m_clearColor.r << "," << m_clearColor.g << "," << m_clearColor.b << "," << m_clearColor.a << ";";
|
2026-04-05 23:44:32 +08:00
|
|
|
os << "skyboxEnabled=" << (m_skyboxEnabled ? 1 : 0) << ";";
|
2026-04-06 00:39:08 +08:00
|
|
|
os << "skyboxMaterialPath=" << serializedSkyboxMaterialPath << ";";
|
|
|
|
|
os << "skyboxMaterialRef=" << EncodeAssetRef(serializedSkyboxMaterialRef) << ";";
|
2026-04-05 23:44:32 +08:00
|
|
|
os << "skyboxTopColor=" << m_skyboxTopColor.r << "," << m_skyboxTopColor.g << "," << m_skyboxTopColor.b << "," << m_skyboxTopColor.a << ";";
|
|
|
|
|
os << "skyboxHorizonColor=" << m_skyboxHorizonColor.r << "," << m_skyboxHorizonColor.g << "," << m_skyboxHorizonColor.b << "," << m_skyboxHorizonColor.a << ";";
|
|
|
|
|
os << "skyboxBottomColor=" << m_skyboxBottomColor.r << "," << m_skyboxBottomColor.g << "," << m_skyboxBottomColor.b << "," << m_skyboxBottomColor.a << ";";
|
2026-04-06 14:56:43 +08:00
|
|
|
os << "postProcessPassCount=" << m_postProcessPasses.size() << ";";
|
|
|
|
|
for (size_t index = 0; index < m_postProcessPasses.size(); ++index) {
|
|
|
|
|
const Rendering::CameraPostProcessPassDesc& pass = m_postProcessPasses[index];
|
|
|
|
|
os << "postProcessPass" << index << "Type=" << static_cast<int>(pass.type) << ";";
|
|
|
|
|
switch (pass.type) {
|
|
|
|
|
case Rendering::CameraPostProcessPassType::ColorScale:
|
|
|
|
|
os << "postProcessPass" << index << "ColorScale="
|
|
|
|
|
<< EncodeVector4(pass.colorScale.scale) << ";";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-04-06 14:37:54 +08:00
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CameraComponent::Deserialize(std::istream& is) {
|
2026-04-06 00:39:08 +08:00
|
|
|
m_skyboxMaterial.Reset();
|
|
|
|
|
m_skyboxMaterialPath.clear();
|
|
|
|
|
m_skyboxMaterialRef.Reset();
|
2026-04-06 14:37:54 +08:00
|
|
|
m_colorScalePostProcessDefaultScale = Math::Vector4::One();
|
2026-04-06 14:56:43 +08:00
|
|
|
m_postProcessPasses.clear();
|
2026-04-06 00:39:08 +08:00
|
|
|
|
2026-03-26 01:26:26 +08:00
|
|
|
std::string token;
|
2026-04-06 00:39:08 +08:00
|
|
|
std::string pendingSkyboxMaterialPath;
|
|
|
|
|
Resources::AssetRef pendingSkyboxMaterialRef;
|
2026-04-06 14:56:43 +08:00
|
|
|
size_t postProcessPassCount = 0;
|
|
|
|
|
Rendering::CameraPostProcessStack deserializedPostProcessPasses;
|
2026-04-06 14:37:54 +08:00
|
|
|
bool legacyColorScaleEnabled = false;
|
|
|
|
|
size_t colorScalePassCount = 0;
|
|
|
|
|
std::vector<Math::Vector4> deserializedColorScalePasses;
|
2026-03-26 01:26:26 +08:00
|
|
|
while (std::getline(is, token, ';')) {
|
|
|
|
|
if (token.empty()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t eqPos = token.find('=');
|
|
|
|
|
if (eqPos == std::string::npos) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string key = token.substr(0, eqPos);
|
|
|
|
|
std::string value = token.substr(eqPos + 1);
|
|
|
|
|
|
|
|
|
|
if (key == "projection") {
|
|
|
|
|
m_projectionType = static_cast<CameraProjectionType>(std::stoi(value));
|
|
|
|
|
} else if (key == "fov") {
|
|
|
|
|
SetFieldOfView(std::stof(value));
|
|
|
|
|
} else if (key == "orthoSize") {
|
|
|
|
|
SetOrthographicSize(std::stof(value));
|
|
|
|
|
} else if (key == "near") {
|
|
|
|
|
SetNearClipPlane(std::stof(value));
|
|
|
|
|
} else if (key == "far") {
|
|
|
|
|
SetFarClipPlane(std::stof(value));
|
|
|
|
|
} else if (key == "depth") {
|
|
|
|
|
m_depth = std::stof(value);
|
|
|
|
|
} else if (key == "primary") {
|
|
|
|
|
m_primary = (std::stoi(value) != 0);
|
2026-04-01 01:33:46 +08:00
|
|
|
} else if (key == "clearMode") {
|
|
|
|
|
m_clearMode = static_cast<CameraClearMode>(std::stoi(value));
|
2026-04-01 13:10:32 +08:00
|
|
|
} else if (key == "stackType") {
|
|
|
|
|
m_stackType = static_cast<CameraStackType>(std::stoi(value));
|
2026-04-01 01:42:06 +08:00
|
|
|
} else if (key == "cullingMask") {
|
|
|
|
|
m_cullingMask = static_cast<uint32_t>(std::stoul(value));
|
2026-04-01 13:01:11 +08:00
|
|
|
} else if (key == "viewportRect") {
|
|
|
|
|
std::replace(value.begin(), value.end(), ',', ' ');
|
|
|
|
|
std::istringstream ss(value);
|
|
|
|
|
Math::Rect viewportRect;
|
|
|
|
|
ss >> viewportRect.x >> viewportRect.y >> viewportRect.width >> viewportRect.height;
|
|
|
|
|
SetViewportRect(viewportRect);
|
2026-03-26 01:26:26 +08:00
|
|
|
} else if (key == "clearColor") {
|
|
|
|
|
std::replace(value.begin(), value.end(), ',', ' ');
|
|
|
|
|
std::istringstream ss(value);
|
|
|
|
|
ss >> m_clearColor.r >> m_clearColor.g >> m_clearColor.b >> m_clearColor.a;
|
2026-04-05 23:44:32 +08:00
|
|
|
} else if (key == "skyboxEnabled") {
|
|
|
|
|
m_skyboxEnabled = (std::stoi(value) != 0);
|
2026-04-06 00:39:08 +08:00
|
|
|
} else if (key == "skyboxMaterialPath") {
|
|
|
|
|
pendingSkyboxMaterialPath = value;
|
|
|
|
|
} else if (key == "skyboxMaterialRef") {
|
|
|
|
|
TryDecodeAssetRef(value, pendingSkyboxMaterialRef);
|
2026-04-05 23:44:32 +08:00
|
|
|
} else if (key == "skyboxTopColor") {
|
|
|
|
|
std::replace(value.begin(), value.end(), ',', ' ');
|
|
|
|
|
std::istringstream ss(value);
|
|
|
|
|
ss >> m_skyboxTopColor.r >> m_skyboxTopColor.g >> m_skyboxTopColor.b >> m_skyboxTopColor.a;
|
|
|
|
|
} else if (key == "skyboxHorizonColor") {
|
|
|
|
|
std::replace(value.begin(), value.end(), ',', ' ');
|
|
|
|
|
std::istringstream ss(value);
|
|
|
|
|
ss >> m_skyboxHorizonColor.r >> m_skyboxHorizonColor.g >> m_skyboxHorizonColor.b >> m_skyboxHorizonColor.a;
|
|
|
|
|
} else if (key == "skyboxBottomColor") {
|
|
|
|
|
std::replace(value.begin(), value.end(), ',', ' ');
|
|
|
|
|
std::istringstream ss(value);
|
|
|
|
|
ss >> m_skyboxBottomColor.r >> m_skyboxBottomColor.g >> m_skyboxBottomColor.b >> m_skyboxBottomColor.a;
|
2026-04-06 14:56:43 +08:00
|
|
|
} else if (key == "postProcessPassCount") {
|
|
|
|
|
postProcessPassCount = static_cast<size_t>(std::stoul(value));
|
|
|
|
|
deserializedPostProcessPasses.clear();
|
|
|
|
|
deserializedPostProcessPasses.resize(postProcessPassCount);
|
|
|
|
|
} else if (key.rfind("postProcessPass", 0) == 0) {
|
|
|
|
|
const size_t prefixLength = std::string("postProcessPass").size();
|
|
|
|
|
size_t propertyPos = prefixLength;
|
|
|
|
|
while (propertyPos < key.size() &&
|
|
|
|
|
std::isdigit(static_cast<unsigned char>(key[propertyPos])) != 0) {
|
|
|
|
|
++propertyPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (propertyPos > prefixLength) {
|
|
|
|
|
const size_t index = static_cast<size_t>(
|
|
|
|
|
std::stoul(key.substr(prefixLength, propertyPos - prefixLength)));
|
|
|
|
|
if (index >= deserializedPostProcessPasses.size()) {
|
|
|
|
|
deserializedPostProcessPasses.resize(index + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rendering::CameraPostProcessPassDesc& pass = deserializedPostProcessPasses[index];
|
|
|
|
|
const std::string property = key.substr(propertyPos);
|
|
|
|
|
if (property == "Type") {
|
|
|
|
|
pass.type = static_cast<Rendering::CameraPostProcessPassType>(std::stoi(value));
|
|
|
|
|
} else if (property == "ColorScale") {
|
|
|
|
|
TryParseVector4(value, pass.colorScale.scale);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-06 14:14:11 +08:00
|
|
|
} else if (key == "colorScalePostProcessEnabled") {
|
2026-04-06 14:37:54 +08:00
|
|
|
legacyColorScaleEnabled = (std::stoi(value) != 0);
|
2026-04-06 14:14:11 +08:00
|
|
|
} else if (key == "colorScalePostProcessScale") {
|
2026-04-06 14:37:54 +08:00
|
|
|
TryParseVector4(value, m_colorScalePostProcessDefaultScale);
|
|
|
|
|
} else if (key == "colorScalePostProcessPassCount") {
|
|
|
|
|
colorScalePassCount = static_cast<size_t>(std::stoul(value));
|
|
|
|
|
deserializedColorScalePasses.clear();
|
|
|
|
|
deserializedColorScalePasses.resize(colorScalePassCount, Math::Vector4::One());
|
|
|
|
|
} else if (key.rfind("colorScalePostProcessPass", 0) == 0) {
|
|
|
|
|
const std::string indexString = key.substr(std::string("colorScalePostProcessPass").size());
|
|
|
|
|
if (!indexString.empty()) {
|
|
|
|
|
const size_t index = static_cast<size_t>(std::stoul(indexString));
|
|
|
|
|
if (index >= deserializedColorScalePasses.size()) {
|
|
|
|
|
deserializedColorScalePasses.resize(index + 1, Math::Vector4::One());
|
|
|
|
|
}
|
|
|
|
|
TryParseVector4(value, deserializedColorScalePasses[index]);
|
|
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-06 00:39:08 +08:00
|
|
|
|
|
|
|
|
if (pendingSkyboxMaterialRef.IsValid()) {
|
|
|
|
|
m_skyboxMaterialRef = pendingSkyboxMaterialRef;
|
|
|
|
|
m_skyboxMaterial = Resources::ResourceManager::Get().Load<Resources::Material>(pendingSkyboxMaterialRef);
|
|
|
|
|
if (m_skyboxMaterial.Get() != nullptr) {
|
|
|
|
|
m_skyboxMaterialPath = ToStdString(m_skyboxMaterial->GetPath());
|
|
|
|
|
} else {
|
|
|
|
|
Containers::String resolvedPath;
|
|
|
|
|
if (Resources::ResourceManager::Get().TryResolveAssetPath(pendingSkyboxMaterialRef, resolvedPath)) {
|
|
|
|
|
SetSkyboxMaterialPath(ToStdString(resolvedPath));
|
|
|
|
|
m_skyboxMaterialRef = pendingSkyboxMaterialRef;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_skyboxMaterial.Get() == nullptr && !pendingSkyboxMaterialPath.empty()) {
|
|
|
|
|
SetSkyboxMaterialPath(pendingSkyboxMaterialPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_skyboxMaterial.Get() == nullptr && pendingSkyboxMaterialRef.IsValid()) {
|
|
|
|
|
m_skyboxMaterialRef = pendingSkyboxMaterialRef;
|
|
|
|
|
}
|
2026-04-06 14:37:54 +08:00
|
|
|
|
2026-04-06 14:56:43 +08:00
|
|
|
if (!deserializedPostProcessPasses.empty()) {
|
|
|
|
|
SetPostProcessPasses(deserializedPostProcessPasses);
|
|
|
|
|
} else if (!deserializedColorScalePasses.empty()) {
|
2026-04-06 14:37:54 +08:00
|
|
|
SetColorScalePostProcessPasses(deserializedColorScalePasses);
|
|
|
|
|
} else if (legacyColorScaleEnabled) {
|
|
|
|
|
SetColorScalePostProcessEnabled(true);
|
|
|
|
|
}
|
2026-03-26 01:26:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Components
|
|
|
|
|
} // namespace XCEngine
|