#include "Viewport/SceneViewportOverlayFrameCache.h" #include #include #include #include #include #include #include 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(data); for (size_t index = 0; index < size; ++index) { hash ^= static_cast(bytes[index]); hash *= kSceneViewportOverlaySignaturePrime; } } template 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& selectedObjectIds) { uint64_t hash = kSceneViewportOverlaySignatureOffsetBasis; HashSceneViewportOverlayValue(hash, static_cast(selectedObjectIds.size())); for (uint64_t entityId : selectedObjectIds) { HashSceneViewportOverlayValue(hash, entityId); } if (scene == nullptr) { return hash; } for (Components::CameraComponent* camera : scene->FindObjectsOfType()) { Components::GameObject* gameObject = camera != nullptr ? camera->GetGameObject() : nullptr; HashSceneViewportOverlayValue(hash, static_cast(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(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::GameObject* gameObject = light != nullptr ? light->GetGameObject() : nullptr; HashSceneViewportOverlayValue(hash, static_cast(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(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& 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& 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