/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
Code/Engine/RendererCore/Components/Implementation/SpriteComponent.cpp
337 строк
10 KB
Jan Krassnigg
Introduced attribute to mark properties as required (#1981)
09 июл 2026, 19:48
Не верифицирован
09 июл 2026, 19:48
111b7a7
Код
Авторство
О чём код?
#include <RendererCore/RendererCorePCH.h> #include <Core/Messages/DeleteObjectMessage.h> #include <Core/Messages/SetColorMessage.h> #include <Core/WorldSerializer/WorldReader.h> #include <Core/WorldSerializer/WorldWriter.h> #include <RendererCore/Components/SpriteComponent.h> #include <RendererCore/Pipeline/RenderDataManager.h> #include <RendererCore/Pipeline/View.h> #include <RendererCore/Textures/Texture2DResource.h> // clang-format off EZ_BEGIN_STATIC_REFLECTED_ENUM(ezSpriteBlendMode, 1) EZ_ENUM_CONSTANTS(ezSpriteBlendMode::Masked, ezSpriteBlendMode::Transparent, ezSpriteBlendMode::Additive) EZ_END_STATIC_REFLECTED_ENUM; // clang-format on // static ezTempHashedString ezSpriteBlendMode::GetPermutationValue(Enum blendMode) { switch (blendMode) { case ezSpriteBlendMode::Masked: case ezSpriteBlendMode::ShapeIcon: return "BLEND_MODE_MASKED"; case ezSpriteBlendMode::Transparent: return "BLEND_MODE_TRANSPARENT"; case ezSpriteBlendMode::Additive: return "BLEND_MODE_ADDITIVE"; } return ""; } // clang-format off EZ_BEGIN_DYNAMIC_REFLECTED_TYPE(ezSpriteRenderData, 1, ezRTTIDefaultAllocator<ezSpriteRenderData>) EZ_END_DYNAMIC_REFLECTED_TYPE; // clang-format on void ezSpriteRenderData::FillSortingKey() { // ignore upper 32 bit of the resource ID hash const ezUInt32 uiTextureIDHash = static_cast<ezUInt32>(m_hTexture.GetResourceIDHash()); // Sort by mode and then by texture m_uiSortingKey = (m_BlendMode << 30) | (uiTextureIDHash & 0x3FFFFFFF); } bool ezSpriteRenderData::CanBatch(const ezRenderData& other0) const { const auto& other = ezStaticCast<const ezSpriteRenderData&>(other0); return m_BlendMode == other.m_BlendMode && m_hTexture == other.m_hTexture; } ////////////////////////////////////////////////////////////////////////// // clang-format off EZ_BEGIN_COMPONENT_TYPE(ezSpriteComponent, 4, ezComponentMode::Static) { EZ_BEGIN_PROPERTIES { EZ_RESOURCE_ACCESSOR_PROPERTY("Texture", GetTexture, SetTexture)->AddAttributes(new ezAssetBrowserAttribute("CompatibleAsset_Texture_2D"), new ezRequiredAttribute()), EZ_ENUM_MEMBER_PROPERTY("BlendMode", ezSpriteBlendMode, m_BlendMode), EZ_ACCESSOR_PROPERTY("Color", GetColor, SetColor)->AddAttributes(new ezExposeColorAlphaAttribute()), EZ_ACCESSOR_PROPERTY("Size", GetSize, SetSize)->AddAttributes(new ezClampValueAttribute(0.0f, ezVariant()), new ezDefaultValueAttribute(1.0f), new ezSuffixAttribute(" m")), EZ_MEMBER_PROPERTY("UseMaxScreenSize", m_bUseMaxScreenSize)->AddAttributes(new ezDefaultValueAttribute(true)), EZ_ACCESSOR_PROPERTY("MaxScreenSize", GetMaxScreenSize, SetMaxScreenSize)->AddAttributes(new ezClampValueAttribute(0.0f, ezVariant()), new ezDefaultValueAttribute(64.0f), new ezSuffixAttribute(" px")), EZ_MEMBER_PROPERTY("AspectRatio", m_fAspectRatio)->AddAttributes(new ezClampValueAttribute(0.0f, ezVariant()), new ezDefaultValueAttribute(1.0f)), EZ_MEMBER_PROPERTY("IsAnimated", m_bIsAnimated), EZ_MEMBER_PROPERTY("Columns", m_uiColumns)->AddAttributes(new ezClampValueAttribute(1, ezVariant()), new ezDefaultValueAttribute(1)), EZ_MEMBER_PROPERTY("Rows", m_uiRows)->AddAttributes(new ezClampValueAttribute(1, ezVariant()), new ezDefaultValueAttribute(1)), EZ_MEMBER_PROPERTY("Framerate", m_fFramerate)->AddAttributes(new ezClampValueAttribute(0.0f, ezVariant()), new ezDefaultValueAttribute(24.0f)), EZ_MEMBER_PROPERTY("Loops", m_uiLoops)->AddAttributes(new ezClampValueAttribute(0, ezVariant()), new ezDefaultValueAttribute(0), new ezMinValueTextAttribute("Infinite")), EZ_ENUM_MEMBER_PROPERTY("OnFinishedAction", ezOnComponentFinishedAction, m_OnFinishedAction) } EZ_END_PROPERTIES; EZ_BEGIN_ATTRIBUTES { new ezCategoryAttribute("Rendering"), } EZ_END_ATTRIBUTES; EZ_BEGIN_MESSAGEHANDLERS { EZ_MESSAGE_HANDLER(ezMsgExtractRenderData, OnMsgExtractRenderData), EZ_MESSAGE_HANDLER(ezMsgSetColor, OnMsgSetColor), EZ_MESSAGE_HANDLER(ezMsgDeleteGameObject, OnMsgDeleteGameObject), } EZ_END_MESSAGEHANDLERS; } EZ_END_COMPONENT_TYPE; // clang-format on ezSpriteComponent::ezSpriteComponent() = default; ezSpriteComponent::~ezSpriteComponent() = default; void ezSpriteComponent::Update() { if (!m_bIsAnimated || !m_hTexture.IsValid()) return; const ezUInt32 uiTotalFrames = m_uiColumns * m_uiRows; if (uiTotalFrames <= 1) return; // Nothing to animate. ezTime tDiff = GetWorld()->GetClock().GetTimeDiff(); m_TimeSinceStart += tDiff; const float fTotalAnimTime = uiTotalFrames / ezMath::Max(0.001f, m_fFramerate); if (m_TimeSinceStart.GetSeconds() >= fTotalAnimTime) { m_uiCurrentLoop++; m_TimeSinceStart -= ezTime::MakeFromSeconds(fTotalAnimTime); if (m_uiLoops != 0 && m_uiCurrentLoop >= m_uiLoops) { m_bIsAnimated = false; ezOnComponentFinishedAction::HandleFinishedAction(this, m_OnFinishedAction); } } } ezResult ezSpriteComponent::GetLocalBounds(ezBoundingBoxSphere& ref_bounds, bool& ref_bAlwaysVisible, ezMsgUpdateLocalBounds& ref_msg) { ref_bounds = ezBoundingSphere::MakeFromCenterAndRadius(ezVec3::MakeZero(), m_fSize * 0.5f); return EZ_SUCCESS; } void ezSpriteComponent::OnMsgExtractRenderData(ezMsgExtractRenderData& msg) const { // Don't render in shadow views if (msg.m_pView->GetCameraUsageHint() == ezCameraUsageHint::Shadow) return; if (!m_hTexture.IsValid()) return; ezSpriteRenderData* pRenderData = msg.m_pRenderDataManager->CreateRenderDataForThisFrame<ezSpriteRenderData>(GetOwner()); { pRenderData->m_hTexture = m_hTexture; pRenderData->m_fSize = m_fSize; pRenderData->m_fMaxScreenSize = m_bUseMaxScreenSize ? m_fMaxScreenSize : ezMath::HighValue<float>(); pRenderData->m_fAspectRatio = m_fAspectRatio; pRenderData->m_BlendMode = m_BlendMode; pRenderData->m_color = m_Color; pRenderData->m_uiUniqueID = GetUniqueIdForRendering(); const ezUInt16 uiTotalFrames = ezMath::Max((ezUInt16)1u, (ezUInt16)(m_uiColumns * m_uiRows)); ezUInt32 uiCurrentFrame = 0; if (uiTotalFrames > 1) { if (!m_bIsAnimated && m_OnFinishedAction == ezOnComponentFinishedAction::None) { uiCurrentFrame = uiTotalFrames - 1; // Park at the last frame. } else { uiCurrentFrame = (ezUInt32)(m_TimeSinceStart.GetSeconds() * m_fFramerate) % uiTotalFrames; } } // Protect against division by zero before clamping takes effect. const ezUInt16 safeCols = ezMath::Max((ezUInt16)1u, (ezUInt16)m_uiColumns); const ezUInt16 safeRows = ezMath::Max((ezUInt16)1u, (ezUInt16)m_uiRows); const ezUInt32 x = uiCurrentFrame % safeCols; const ezUInt32 y = uiCurrentFrame / safeCols; pRenderData->m_texCoordScale = ezVec2(1.0f / safeCols, 1.0f / safeRows); pRenderData->m_texCoordOffset = ezVec2((float)x * pRenderData->m_texCoordScale.x, (float)y * pRenderData->m_texCoordScale.y); pRenderData->FillSortingKey(); } // Determine render data category. ezRenderData::Category category = ezDefaultRenderDataCategories::LitTransparent; if (m_BlendMode == ezSpriteBlendMode::Masked) { category = ezDefaultRenderDataCategories::LitMasked; } const auto cachingFlags = m_bIsAnimated ? ezRenderData::Caching::Never : ezRenderData::Caching::IfStatic; msg.AddRenderData(pRenderData, category, cachingFlags); } void ezSpriteComponent::SerializeComponent(ezWorldWriter& inout_stream) const { SUPER::SerializeComponent(inout_stream); ezStreamWriter& s = inout_stream.GetStream(); s << m_hTexture; s << m_fSize; s << m_fMaxScreenSize; // Version 3 s << m_Color; // HDR now s << m_fAspectRatio; s << m_BlendMode; // Version 4 s << m_bUseMaxScreenSize; s << m_bIsAnimated; s << m_uiColumns; s << m_uiRows; s << m_fFramerate; s << m_uiLoops; ezOnComponentFinishedAction::StorageType type = m_OnFinishedAction; s << type; } void ezSpriteComponent::DeserializeComponent(ezWorldReader& inout_stream) { SUPER::DeserializeComponent(inout_stream); const ezUInt32 uiVersion = inout_stream.GetComponentTypeVersion(GetStaticRTTI()); ezStreamReader& s = inout_stream.GetStream(); s >> m_hTexture; if (uiVersion < 3) { ezColorGammaUB color; s >> color; m_Color = color; } s >> m_fSize; s >> m_fMaxScreenSize; if (uiVersion >= 3) { s >> m_Color; s >> m_fAspectRatio; s >> m_BlendMode; } if (uiVersion >= 4) { s >> m_bUseMaxScreenSize; s >> m_bIsAnimated; s >> m_uiColumns; s >> m_uiRows; s >> m_fFramerate; s >> m_uiLoops; ezOnComponentFinishedAction::StorageType type; s >> type; m_OnFinishedAction = (ezOnComponentFinishedAction::Enum)type; } } void ezSpriteComponent::SetTexture(const ezTexture2DResourceHandle& hTexture) { m_hTexture = hTexture; } const ezTexture2DResourceHandle& ezSpriteComponent::GetTexture() const { return m_hTexture; } void ezSpriteComponent::SetColor(ezColor color) { m_Color = color; } ezColor ezSpriteComponent::GetColor() const { return m_Color; } void ezSpriteComponent::SetSize(float fSize) { m_fSize = fSize; TriggerLocalBoundsUpdate(); } float ezSpriteComponent::GetSize() const { return m_fSize; } void ezSpriteComponent::SetMaxScreenSize(float fSize) { m_fMaxScreenSize = fSize; } float ezSpriteComponent::GetMaxScreenSize() const { return m_fMaxScreenSize; } void ezSpriteComponent::OnMsgSetColor(ezMsgSetColor& ref_msg) { ref_msg.ModifyColor(m_Color); } void ezSpriteComponent::OnMsgDeleteGameObject(ezMsgDeleteGameObject& msg) { ezOnComponentFinishedAction::HandleDeleteObjectMsg(msg, m_OnFinishedAction); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #include <Foundation/Serialization/AbstractObjectGraph.h> #include <Foundation/Serialization/GraphPatch.h> class ezSpriteComponentPatch_1_2 : public ezGraphPatch { public: ezSpriteComponentPatch_1_2() : ezGraphPatch("ezSpriteComponent", 2) { } virtual void Patch(ezGraphPatchContext& ref_context, ezAbstractObjectGraph* pGraph, ezAbstractObjectNode* pNode) const override { pNode->RenameProperty("Max Screen Size", "MaxScreenSize"); } }; ezSpriteComponentPatch_1_2 g_ezSpriteComponentPatch_1_2; EZ_STATICLINK_FILE(RendererCore, RendererCore_Components_Implementation_SpriteComponent);