UiParticle.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "UiParticle.h"
  9. #include "UiParticleEmitterComponent.h"
  10. #include <LyShine/ISprite.h>
  11. ////////////////////////////////////////////////////////////////////////////////////////////////////
  12. void UiParticle::Init(UiParticle::UiParticleInitialParameters* initialParams)
  13. {
  14. m_particleAge = 0.0f;
  15. m_particleLifetime = initialParams->lifetime;
  16. m_emitterInitialOffset = initialParams->initialEmitterOffset;
  17. m_position = initialParams->position;
  18. m_positionDifference = AZ::Vector2::CreateZero();
  19. m_velocity = initialParams->initialVelocity;
  20. m_accelerationBasedVelocity = AZ::Vector2::CreateZero();
  21. m_acceleration = initialParams->acceleration;
  22. m_rotation = initialParams->rotation;
  23. m_angularVelocity = initialParams->angularVelocity;
  24. m_pivot = initialParams->pivot;
  25. m_size = initialParams->size;
  26. m_color = initialParams->color;
  27. m_spriteCellIndex = initialParams->spriteSheetCellIndex;
  28. }
  29. ////////////////////////////////////////////////////////////////////////////////////////////////////
  30. void UiParticle::Update(float deltaTime, const UiParticleUpdateParameters& updateParameters)
  31. {
  32. AZ::Vector2 previousPosition = m_position;
  33. float velocityStrength = 1.0f;
  34. if (updateParameters.isSpeedMultiplierUsed)
  35. {
  36. float particleLifetimePercentage = (updateParameters.isParticleInfinite ? 0.0f : m_particleAge / m_particleLifetime);
  37. updateParameters.speedMultiplier->GetValue(particleLifetimePercentage, velocityStrength);
  38. }
  39. AZ::Vector2 currentVelocity = m_velocity * velocityStrength;
  40. if (updateParameters.isVelocityCartesian)
  41. {
  42. m_position += currentVelocity * deltaTime;
  43. }
  44. else
  45. {
  46. AZ::Vector2 offset = m_position - m_emitterInitialOffset;
  47. float radius = AZ::GetMax<float>(offset.GetLength(), 0.1f);
  48. float newRadius = radius + currentVelocity.GetX() * deltaTime;
  49. if (newRadius > 0.0f)
  50. {
  51. offset = (offset / radius) * newRadius;
  52. float angle = (currentVelocity.GetY() * deltaTime) / newRadius;
  53. m_position.SetX(offset.GetX() * cos(angle) + offset.GetY() * sin(angle));
  54. m_position.SetY((-offset.GetX()) * sin(angle) + offset.GetY() * cos(angle));
  55. m_position += m_emitterInitialOffset;
  56. }
  57. else
  58. {
  59. m_position = m_emitterInitialOffset;
  60. }
  61. }
  62. if (updateParameters.isAccelerationCartesian)
  63. {
  64. m_position += m_accelerationBasedVelocity * deltaTime;
  65. m_position += 0.5f * deltaTime * deltaTime * m_acceleration;
  66. }
  67. else
  68. {
  69. AZ::Vector2 offset = m_position - m_emitterInitialOffset;
  70. float radius = AZ::GetMax<float>(offset.GetLength(), 0.1f);
  71. float newRadius = radius + m_accelerationBasedVelocity.GetX() * deltaTime;
  72. if (newRadius > 0.0f)
  73. {
  74. offset = (offset / radius) * newRadius;
  75. float angle = (m_accelerationBasedVelocity.GetY() * deltaTime) / newRadius;
  76. m_position.SetX(offset.GetX() * cos(angle) + offset.GetY() * sin(angle));
  77. m_position.SetY((-offset.GetX()) * sin(angle) + offset.GetY() * cos(angle));
  78. m_position += m_emitterInitialOffset;
  79. }
  80. else
  81. {
  82. m_position = m_emitterInitialOffset;
  83. }
  84. }
  85. m_positionDifference = m_position - previousPosition;
  86. m_accelerationBasedVelocity += m_acceleration * deltaTime;
  87. m_rotation += m_angularVelocity * deltaTime;
  88. m_particleAge += deltaTime;
  89. }
  90. ////////////////////////////////////////////////////////////////////////////////////////////////////
  91. bool UiParticle::FillVertices(LyShine::UiPrimitiveVertex* outputVertices, const UiParticleRenderParameters& renderParameters, const AZ::Matrix4x4& transform)
  92. {
  93. float particleLifetimePercentage = (renderParameters.isParticleInfinite ? 0.0f : m_particleAge / m_particleLifetime);
  94. float alphaStrength = 1.0f;
  95. AZ::Color currentColor = m_color;
  96. if (renderParameters.isColorOverrideUsed)
  97. {
  98. currentColor = renderParameters.colorOverride;
  99. }
  100. if (renderParameters.isAlphaOverrideUsed)
  101. {
  102. currentColor.SetA(renderParameters.alphaOverride);
  103. }
  104. if (renderParameters.isAlphaMultiplierUsed)
  105. {
  106. renderParameters.alphaMultiplier->GetValue(particleLifetimePercentage, alphaStrength);
  107. }
  108. AZ::u8 currentAlpha = static_cast<AZ::u8>(currentColor.GetA8() * alphaStrength * renderParameters.alphaFadeMultiplier);
  109. if (currentAlpha == 0)
  110. {
  111. return false;
  112. }
  113. int currentIndex = m_spriteCellIndex;
  114. if (renderParameters.spritesheetCellIndexAnimated)
  115. {
  116. int unwrappedIndex = m_spriteCellIndex + static_cast<int>(m_particleAge / renderParameters.spritesheetFrameDelay);
  117. int clampedIndex = unwrappedIndex - renderParameters.spritesheetStartFrame;
  118. if (!renderParameters.spritesheetCellIndexAnimationLooped)
  119. {
  120. clampedIndex = AZ::GetClamp<int>(clampedIndex, 0, renderParameters.spritesheetFrameRange);
  121. }
  122. int rangeIncludingEndFrame = renderParameters.spritesheetFrameRange + 1;
  123. currentIndex = renderParameters.spritesheetStartFrame + (clampedIndex % rangeIncludingEndFrame);
  124. }
  125. const UiTransformInterface::RectPoints& uvCoords = (renderParameters.sprite ? renderParameters.sprite->GetCellUvCoords(currentIndex) : UiTransformInterface::RectPoints(0, 1, 0, 1));
  126. const AZ::Vector2 uvs[4] =
  127. {
  128. uvCoords.TopLeft(),
  129. uvCoords.TopRight(),
  130. uvCoords.BottomRight(),
  131. uvCoords.BottomLeft(),
  132. };
  133. float widthMultiplier = 1.0f;
  134. float heightMultiplier = 1.0f;
  135. if (renderParameters.isWidthMultiplierUsed)
  136. {
  137. renderParameters.sizeWidthMultiplier->GetValue(particleLifetimePercentage, widthMultiplier);
  138. }
  139. if (renderParameters.isAspectRatioLocked)
  140. {
  141. heightMultiplier = widthMultiplier;
  142. }
  143. else if (renderParameters.isHeightMultiplierUsed)
  144. {
  145. renderParameters.sizeHeightMultiplier->GetValue(particleLifetimePercentage, heightMultiplier);
  146. }
  147. AZ::Color colorStrength(1.0f, 1.0f, 1.0f, 1.0f);
  148. if (renderParameters.isColorMultiplierUsed)
  149. {
  150. renderParameters.colorMultiplier->GetValue(particleLifetimePercentage, colorStrength);
  151. }
  152. currentColor = currentColor * colorStrength;
  153. uint32 packedColor = (currentAlpha << 24) | (currentColor.GetR8() << 16) | (currentColor.GetG8() << 8) | currentColor.GetB8();
  154. AZ::Vector2 unitQuadQuarters[4];
  155. unitQuadQuarters[0].Set(0.0f - m_pivot.GetX(), 0.0f - m_pivot.GetY());
  156. unitQuadQuarters[1].Set(1.0f - m_pivot.GetX(), 0.0f - m_pivot.GetY());
  157. unitQuadQuarters[2].Set(1.0f - m_pivot.GetX(), 1.0f - m_pivot.GetY());
  158. unitQuadQuarters[3].Set(0.0f - m_pivot.GetX(), 1.0f - m_pivot.GetY());
  159. float sinRotation = sin(m_rotation);
  160. float cosRotation = cos(m_rotation);
  161. AZ::Vector2 particleDirectionVectors[2];
  162. if (renderParameters.isRotationVelocityBased)
  163. {
  164. particleDirectionVectors[1] = m_positionDifference.GetNormalizedSafe() * -1.0f;
  165. particleDirectionVectors[0] = particleDirectionVectors[1].GetPerpendicular() * -1.0f;
  166. }
  167. else
  168. {
  169. particleDirectionVectors[0].Set(cosRotation, sinRotation);
  170. particleDirectionVectors[1].Set(-sinRotation, cosRotation);
  171. }
  172. AZ::Vector2 particlePosition = m_position;
  173. if (renderParameters.isRelativeToEmitter)
  174. {
  175. particlePosition += (*renderParameters.particleOffset) - m_emitterInitialOffset;
  176. }
  177. const int verticesPerParticle = 4;
  178. for (int i = 0; i < verticesPerParticle; ++i)
  179. {
  180. AZ::Vector2 cornerVector = particlePosition + (unitQuadQuarters[i].GetX() * particleDirectionVectors[0] * m_size.GetX() * widthMultiplier) + (unitQuadQuarters[i].GetY() * particleDirectionVectors[1] * m_size.GetY() * heightMultiplier);
  181. AZ::Vector3 point3(cornerVector.GetX(), cornerVector.GetY(), 1.0f);
  182. point3 = transform * point3;
  183. outputVertices[i].xy = Vec2(point3.GetX(), point3.GetY());
  184. outputVertices[i].color.dcolor = packedColor;
  185. outputVertices[i].st = Vec2(uvs[i].GetX(), uvs[i].GetY());
  186. outputVertices[i].texIndex = 0;
  187. outputVertices[i].texHasColorChannel = 1;
  188. outputVertices[i].texIndex2 = 0;
  189. outputVertices[i].pad = 0;
  190. }
  191. return true;
  192. }
  193. ////////////////////////////////////////////////////////////////////////////////////////////////////
  194. bool UiParticle::IsActive(bool infiniteLifetime) const
  195. {
  196. return (m_particleAge < m_particleLifetime || infiniteLifetime);
  197. }