Files
XCEngine/editor/src/Viewport/SceneViewportOverlayFrameCache.cpp

201 lines
8.0 KiB
C++

#include "Viewport/SceneViewportOverlayFrameCache.h"
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Components/LightComponent.h>
#include <XCEngine/Components/TransformComponent.h>
#include <XCEngine/Scene/Scene.h>
#include <cmath>
#include <cstring>
namespace XCEngine {
namespace Editor {
namespace {
constexpr uint64_t kSceneViewportOverlaySignatureOffsetBasis = 14695981039346656037ull;
constexpr uint64_t kSceneViewportOverlaySignaturePrime = 1099511628211ull;
void HashSceneViewportOverlayBytes(uint64_t& hash, const void* data, size_t size) {
const auto* bytes = static_cast<const uint8_t*>(data);
for (size_t index = 0; index < size; ++index) {
hash ^= static_cast<uint64_t>(bytes[index]);
hash *= kSceneViewportOverlaySignaturePrime;
}
}
template <typename TValue>
void HashSceneViewportOverlayValue(uint64_t& hash, const TValue& value) {
HashSceneViewportOverlayBytes(hash, &value, sizeof(TValue));
}
void HashSceneViewportOverlayFloat(uint64_t& hash, float value) {
uint32_t bits = 0u;
std::memcpy(&bits, &value, sizeof(bits));
HashSceneViewportOverlayValue(hash, bits);
}
void HashSceneViewportOverlayVector3(uint64_t& hash, const Math::Vector3& value) {
HashSceneViewportOverlayFloat(hash, value.x);
HashSceneViewportOverlayFloat(hash, value.y);
HashSceneViewportOverlayFloat(hash, value.z);
}
void HashSceneViewportOverlayQuaternion(uint64_t& hash, const Math::Quaternion& value) {
HashSceneViewportOverlayFloat(hash, value.x);
HashSceneViewportOverlayFloat(hash, value.y);
HashSceneViewportOverlayFloat(hash, value.z);
HashSceneViewportOverlayFloat(hash, value.w);
}
void HashSceneViewportOverlayRect(uint64_t& hash, const Math::Rect& value) {
HashSceneViewportOverlayFloat(hash, value.x);
HashSceneViewportOverlayFloat(hash, value.y);
HashSceneViewportOverlayFloat(hash, value.width);
HashSceneViewportOverlayFloat(hash, value.height);
}
void HashSceneViewportOverlayTransform(uint64_t& hash, const Components::TransformComponent& transform) {
HashSceneViewportOverlayVector3(hash, transform.GetPosition());
HashSceneViewportOverlayQuaternion(hash, transform.GetRotation());
HashSceneViewportOverlayVector3(hash, transform.GetScale());
}
bool AreEqualSceneViewportVector3(const Math::Vector3& lhs, const Math::Vector3& rhs) {
constexpr float kEpsilon = 1e-4f;
return std::abs(lhs.x - rhs.x) <= kEpsilon &&
std::abs(lhs.y - rhs.y) <= kEpsilon &&
std::abs(lhs.z - rhs.z) <= kEpsilon;
}
} // namespace
void ResetSceneViewportOverlayFrameCacheState(
SceneViewportOverlayFrameCacheState& cacheState) {
cacheState = {};
}
void ResolveSceneViewportOverlayFrameViewportSize(
uint32_t requestedWidth,
uint32_t requestedHeight,
uint32_t renderWidth,
uint32_t renderHeight,
uint32_t& outWidth,
uint32_t& outHeight) {
outWidth = requestedWidth > 0u ? requestedWidth : renderWidth;
outHeight = requestedHeight > 0u ? requestedHeight : renderHeight;
}
bool AreEqualSceneViewportOverlayData(
const SceneViewportOverlayData& lhs,
const SceneViewportOverlayData& rhs) {
constexpr float kEpsilon = 1e-4f;
return lhs.valid == rhs.valid &&
AreEqualSceneViewportVector3(lhs.cameraPosition, rhs.cameraPosition) &&
AreEqualSceneViewportVector3(lhs.cameraForward, rhs.cameraForward) &&
AreEqualSceneViewportVector3(lhs.cameraRight, rhs.cameraRight) &&
AreEqualSceneViewportVector3(lhs.cameraUp, rhs.cameraUp) &&
std::abs(lhs.verticalFovDegrees - rhs.verticalFovDegrees) <= kEpsilon &&
std::abs(lhs.nearClipPlane - rhs.nearClipPlane) <= kEpsilon &&
std::abs(lhs.farClipPlane - rhs.farClipPlane) <= kEpsilon &&
std::abs(lhs.orbitDistance - rhs.orbitDistance) <= kEpsilon;
}
uint64_t BuildSceneViewportOverlayContentSignature(
const Components::Scene* scene,
const std::vector<uint64_t>& selectedObjectIds) {
uint64_t hash = kSceneViewportOverlaySignatureOffsetBasis;
HashSceneViewportOverlayValue(hash, static_cast<uint64_t>(selectedObjectIds.size()));
for (uint64_t entityId : selectedObjectIds) {
HashSceneViewportOverlayValue(hash, entityId);
}
if (scene == nullptr) {
return hash;
}
for (Components::CameraComponent* camera : scene->FindObjectsOfType<Components::CameraComponent>()) {
Components::GameObject* gameObject = camera != nullptr ? camera->GetGameObject() : nullptr;
HashSceneViewportOverlayValue(hash, static_cast<uint8_t>(1u));
HashSceneViewportOverlayValue(hash, gameObject != nullptr ? gameObject->GetID() : 0ull);
HashSceneViewportOverlayValue(hash, camera != nullptr && camera->IsEnabled());
HashSceneViewportOverlayValue(hash, gameObject != nullptr && gameObject->IsActiveInHierarchy());
if (camera == nullptr ||
gameObject == nullptr ||
!camera->IsEnabled() ||
!gameObject->IsActiveInHierarchy() ||
gameObject->GetTransform() == nullptr) {
continue;
}
HashSceneViewportOverlayTransform(hash, *gameObject->GetTransform());
HashSceneViewportOverlayValue(hash, static_cast<uint32_t>(camera->GetProjectionType()));
HashSceneViewportOverlayFloat(hash, camera->GetFieldOfView());
HashSceneViewportOverlayFloat(hash, camera->GetOrthographicSize());
HashSceneViewportOverlayFloat(hash, camera->GetNearClipPlane());
HashSceneViewportOverlayFloat(hash, camera->GetFarClipPlane());
HashSceneViewportOverlayRect(hash, camera->GetViewportRect());
}
for (Components::LightComponent* light : scene->FindObjectsOfType<Components::LightComponent>()) {
Components::GameObject* gameObject = light != nullptr ? light->GetGameObject() : nullptr;
HashSceneViewportOverlayValue(hash, static_cast<uint8_t>(2u));
HashSceneViewportOverlayValue(hash, gameObject != nullptr ? gameObject->GetID() : 0ull);
HashSceneViewportOverlayValue(hash, light != nullptr && light->IsEnabled());
HashSceneViewportOverlayValue(hash, gameObject != nullptr && gameObject->IsActiveInHierarchy());
if (light == nullptr ||
gameObject == nullptr ||
!light->IsEnabled() ||
!gameObject->IsActiveInHierarchy() ||
gameObject->GetTransform() == nullptr) {
continue;
}
HashSceneViewportOverlayTransform(hash, *gameObject->GetTransform());
HashSceneViewportOverlayValue(hash, static_cast<uint32_t>(light->GetLightType()));
}
return hash;
}
bool ShouldRebuildSceneViewportOverlayFrameCache(
const SceneViewportOverlayFrameCacheState& cacheState,
const Components::Scene* scene,
const SceneViewportOverlayData& overlay,
uint32_t viewportWidth,
uint32_t viewportHeight,
const std::vector<uint64_t>& selectedObjectIds,
uint64_t contentSignature,
bool transformGizmoOverlayDirty) {
return transformGizmoOverlayDirty ||
!cacheState.cached ||
cacheState.scene != scene ||
cacheState.viewportWidth != viewportWidth ||
cacheState.viewportHeight != viewportHeight ||
cacheState.selectedObjectIds != selectedObjectIds ||
cacheState.contentSignature != contentSignature ||
!AreEqualSceneViewportOverlayData(cacheState.frameData.overlay, overlay);
}
void UpdateSceneViewportOverlayFrameCacheState(
SceneViewportOverlayFrameCacheState& cacheState,
const Components::Scene* scene,
uint32_t viewportWidth,
uint32_t viewportHeight,
const std::vector<uint64_t>& selectedObjectIds,
uint64_t contentSignature,
const SceneViewportOverlayFrameData& frameData) {
cacheState.frameData = frameData;
cacheState.scene = scene;
cacheState.selectedObjectIds = selectedObjectIds;
cacheState.viewportWidth = viewportWidth;
cacheState.viewportHeight = viewportHeight;
cacheState.contentSignature = contentSignature;
cacheState.cached = true;
}
} // namespace Editor
} // namespace XCEngine