1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "animation/rs_render_particle_effector.h"
17
18 #include <cmath>
19 #include <iostream>
20 #include <random>
21 #ifdef ENABLE_RUST
22 #include "cxx.h"
23 #include "lib.rs.h"
24 #endif
25
26 #include "animation/rs_value_estimator.h"
27 namespace OHOS {
28 namespace Rosen {
29 constexpr float DEGREE_TO_RADIAN = M_PI / 180;
RSRenderParticleEffector()30 RSRenderParticleEffector::RSRenderParticleEffector() {}
31
CalculateColorInt(const std::shared_ptr<RSRenderParticle> & particle,Vector4<int16_t> colorInt,Vector4<float> colorF,Vector4<float> colorSpeed,float deltaTime)32 Vector4<int16_t> RSRenderParticleEffector::CalculateColorInt(const std::shared_ptr<RSRenderParticle>& particle,
33 Vector4<int16_t> colorInt, Vector4<float> colorF, Vector4<float> colorSpeed, float deltaTime)
34 {
35 for (int i = 0; i < 4; i++) { // 4 is color tunnel count
36 if (!((colorInt.data_[i] <= 0 && colorSpeed.data_[i] <= 0.f) ||
37 (colorInt.data_[i] >= UINT8_MAX && colorSpeed.data_[i] >= 0.f))) {
38 colorF.data_[i] += colorSpeed.data_[i] * deltaTime;
39 if (std::abs(colorF.data_[i]) >= 1.f) {
40 colorInt.data_[i] += static_cast<int16_t>(colorF.data_[i]);
41 colorF.data_[i] -= std::floor(colorF.data_[i]);
42 }
43 if (particle != nullptr) {
44 particle->SetRedF(colorF.data_[i]);
45 }
46 colorInt.data_[i] = std::clamp<int16_t>(colorInt.data_[i], 0, UINT8_MAX);
47 }
48 }
49 return colorInt;
50 }
51
UpdateCurveValue(float & value,const std::vector<std::shared_ptr<ChangeInOverLife<float>>> & valChangeOverLife,int64_t activeTime)52 void RSRenderParticleEffector::UpdateCurveValue(
53 float& value, const std::vector<std::shared_ptr<ChangeInOverLife<float>>>& valChangeOverLife, int64_t activeTime)
54 {
55 for (size_t i = 0; i < valChangeOverLife.size(); i++) {
56 if (valChangeOverLife[i] != nullptr) {
57 int startTime = valChangeOverLife[i]->startMillis_;
58 int endTime = valChangeOverLife[i]->endMillis_;
59 if (activeTime < startTime || activeTime > endTime) {
60 continue;
61 }
62 float startValue = valChangeOverLife[i]->fromValue_;
63 float endValue = valChangeOverLife[i]->toValue_;
64 #ifdef ENABLE_RUST
65 value = generate_value(startValue, endValue, startTime, endTime, activeTime);
66 #else
67 if (endTime - startTime > 0) {
68 float t = static_cast<float>(activeTime - startTime) / static_cast<float>(endTime - startTime);
69 auto& interpolator = valChangeOverLife[i]->interpolator_;
70 t = (interpolator != nullptr) ? interpolator->Interpolate(t) : t;
71 value = startValue * (1.0f - t) + endValue * t;
72 }
73 #endif
74 break;
75 }
76 }
77 }
78
UpdateColorCurveValue(Color & color,const std::vector<std::shared_ptr<ChangeInOverLife<Color>>> & valChangeOverLife,int64_t activeTime)79 void RSRenderParticleEffector::UpdateColorCurveValue(
80 Color& color, const std::vector<std::shared_ptr<ChangeInOverLife<Color>>>& valChangeOverLife, int64_t activeTime)
81 {
82 for (size_t i = 0; i < valChangeOverLife.size(); i++) {
83 if (valChangeOverLife[i] != nullptr) {
84 int startTime = valChangeOverLife[i]->startMillis_;
85 int endTime = valChangeOverLife[i]->endMillis_;
86 if (activeTime < startTime || activeTime > endTime) {
87 continue;
88 }
89 if (endTime - startTime > 0) {
90 Color startValue = valChangeOverLife[i]->fromValue_;
91 Color endValue = valChangeOverLife[i]->toValue_;
92 float t = static_cast<float>(activeTime - startTime) / static_cast<float>(endTime - startTime);
93 auto& interpolator = valChangeOverLife[i]->interpolator_;
94 t = (interpolator != nullptr) ? interpolator->Interpolate(t) : t;
95 color = RSRenderParticle::Lerp(startValue, endValue, t);
96 }
97 color = Color(color.AsRgbaInt());
98 break;
99 }
100 }
101 }
102
UpdateColor(const std::shared_ptr<RSRenderParticle> & particle,float deltaTime)103 void RSRenderParticleEffector::UpdateColor(const std::shared_ptr<RSRenderParticle>& particle, float deltaTime)
104 {
105 if (particle == nullptr || particle->GetParticleType() == ParticleType::IMAGES) {
106 return;
107 }
108 Color color = particle->GetColor();
109 auto particleRenderParams = particle->GetParticleRenderParams();
110 if (particleRenderParams != nullptr) {
111 auto colorUpdator = particleRenderParams->GetColorUpdator();
112 if (colorUpdator == ParticleUpdator::RANDOM) {
113 auto colorInt = Vector4<int16_t>(color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha());
114 auto colorSpeed = Vector4f(particle->GetRedSpeed(), particle->GetGreenSpeed(), particle->GetBlueSpeed(),
115 particle->GetAlphaSpeed());
116 auto colorF =
117 Vector4f(particle->GetRedF(), particle->GetGreenF(), particle->GetBlueF(), particle->GetAlphaF());
118 colorInt = CalculateColorInt(particle, colorInt, colorF, colorSpeed, deltaTime);
119 color.SetRed(colorInt.x_);
120 color.SetGreen(colorInt.y_);
121 color.SetBlue(colorInt.z_);
122 color.SetAlpha(colorInt.w_);
123 } else if (colorUpdator == ParticleUpdator::CURVE) {
124 int64_t activeTime = particle->GetActiveTime() / NS_PER_MS;
125 auto& valChangeOverLife = particleRenderParams->GetColorChangeOverLife();
126 UpdateColorCurveValue(color, valChangeOverLife, activeTime);
127 }
128 }
129
130 particle->SetColor(color);
131 }
132
UpdateOpacity(const std::shared_ptr<RSRenderParticle> & particle,float deltaTime)133 void RSRenderParticleEffector::UpdateOpacity(const std::shared_ptr<RSRenderParticle>& particle, float deltaTime)
134 {
135 if (particle == nullptr) {
136 return;
137 }
138 auto opacity = particle->GetOpacity();
139 auto particleRenderParams = particle->GetParticleRenderParams();
140 if (particleRenderParams != nullptr) {
141 auto opacityUpdator = particleRenderParams->GetOpacityUpdator();
142 if (opacityUpdator == ParticleUpdator::RANDOM) {
143 auto opacitySpeed = particle->GetOpacitySpeed();
144 if (opacity <= 0 && opacitySpeed <= 0) {
145 particle->SetIsDead();
146 return;
147 }
148 if (opacity >= 1.0 && opacitySpeed >= 0.f) {
149 return;
150 }
151 opacity += opacitySpeed * deltaTime;
152 opacity = std::clamp<float>(opacity, 0.f, 1.f);
153 } else if (opacityUpdator == ParticleUpdator::CURVE) {
154 int64_t activeTime = particle->GetActiveTime() / NS_PER_MS;
155 auto& valChangeOverLife = particleRenderParams->GetOpacityChangeOverLife();
156 UpdateCurveValue(opacity, valChangeOverLife, activeTime);
157 }
158 }
159 particle->SetOpacity(opacity);
160 }
161
UpdateScale(const std::shared_ptr<RSRenderParticle> & particle,float deltaTime)162 void RSRenderParticleEffector::UpdateScale(const std::shared_ptr<RSRenderParticle>& particle, float deltaTime)
163 {
164 if (particle == nullptr) {
165 return;
166 }
167 auto scale = particle->GetScale();
168 auto particleRenderParams = particle->GetParticleRenderParams();
169 if (particleRenderParams != nullptr) {
170 auto scaleUpdator = particleRenderParams->GetScaleUpdator();
171 if (scaleUpdator == ParticleUpdator::RANDOM) {
172 auto scaleSpeed = particle->GetScaleSpeed();
173 if (scale <= 0 && scaleSpeed <= 0) {
174 particle->SetIsDead();
175 return;
176 }
177 scale += scaleSpeed * deltaTime;
178 } else if (scaleUpdator == ParticleUpdator::CURVE) {
179 int64_t activeTime = particle->GetActiveTime() / NS_PER_MS;
180 auto& valChangeOverLife = particleRenderParams->GetScaleChangeOverLife();
181 UpdateCurveValue(scale, valChangeOverLife, activeTime);
182 }
183 }
184 particle->SetScale(scale);
185 }
186
UpdateSpin(const std::shared_ptr<RSRenderParticle> & particle,float deltaTime)187 void RSRenderParticleEffector::UpdateSpin(const std::shared_ptr<RSRenderParticle>& particle, float deltaTime)
188 {
189 if (particle == nullptr) {
190 return;
191 }
192 auto spin = particle->GetSpin();
193 auto particleRenderParams = particle->GetParticleRenderParams();
194 if (particleRenderParams != nullptr) {
195 auto spinUpdator = particleRenderParams->GetSpinUpdator();
196 if (spinUpdator == ParticleUpdator::RANDOM) {
197 auto spinSpeed = particle->GetSpinSpeed();
198 spin += spinSpeed * deltaTime;
199 } else if (spinUpdator == ParticleUpdator::CURVE) {
200 int64_t activeTime = particle->GetActiveTime() / NS_PER_MS;
201 auto& valChangeOverLife = particleRenderParams->GetSpinChangeOverLife();
202 UpdateCurveValue(spin, valChangeOverLife, activeTime);
203 }
204 }
205 particle->SetSpin(spin);
206 }
207
UpdateAccelerationAngle(const std::shared_ptr<RSRenderParticle> & particle,float deltaTime)208 void RSRenderParticleEffector::UpdateAccelerationAngle(
209 const std::shared_ptr<RSRenderParticle>& particle, float deltaTime)
210 {
211 if (particle == nullptr) {
212 return;
213 }
214 auto accelerationAngle = particle->GetAccelerationAngle();
215 auto particleRenderParams = particle->GetParticleRenderParams();
216 if (particleRenderParams != nullptr) {
217 auto acceAngleUpdator = particleRenderParams->GetAccelerationAngleUpdator();
218 if (acceAngleUpdator == ParticleUpdator::RANDOM) {
219 float acceAngleSpeed = particle->GetAccelerationAngleSpeed();
220 accelerationAngle += acceAngleSpeed * deltaTime;
221 } else if (acceAngleUpdator == ParticleUpdator::CURVE) {
222 int64_t activeTime = particle->GetActiveTime() / NS_PER_MS;
223 auto& valChangeOverLife = particleRenderParams->GetAcceAngChangeOverLife();
224 UpdateCurveValue(accelerationAngle, valChangeOverLife, activeTime);
225 }
226 }
227 particle->SetAccelerationAngle(accelerationAngle);
228 }
229
UpdateAccelerationValue(const std::shared_ptr<RSRenderParticle> & particle,float deltaTime)230 void RSRenderParticleEffector::UpdateAccelerationValue(
231 const std::shared_ptr<RSRenderParticle>& particle, float deltaTime)
232 {
233 if (particle == nullptr) {
234 return;
235 }
236 auto accelerationValue = particle->GetAccelerationValue();
237 auto particleRenderParams = particle->GetParticleRenderParams();
238 if (particleRenderParams != nullptr) {
239 auto acceValueUpdator = particleRenderParams->GetAccelerationValueUpdator();
240 if (acceValueUpdator == ParticleUpdator::RANDOM) {
241 float acceValueSpeed = particle->GetAccelerationValueSpeed();
242 accelerationValue += acceValueSpeed * deltaTime;
243 } else if (acceValueUpdator == ParticleUpdator::CURVE) {
244 int64_t activeTime = particle->GetActiveTime() / NS_PER_MS;
245 auto& valChangeOverLife = particleRenderParams->GetAcceValChangeOverLife();
246 UpdateCurveValue(accelerationValue, valChangeOverLife, activeTime);
247 }
248 }
249 particle->SetAccelerationValue(accelerationValue);
250 }
251
UpdatePosition(const std::shared_ptr<RSRenderParticle> & particle,const std::shared_ptr<ParticleNoiseFields> & particleNoiseFields,float deltaTime)252 void RSRenderParticleEffector::UpdatePosition(const std::shared_ptr<RSRenderParticle>& particle,
253 const std::shared_ptr<ParticleNoiseFields>& particleNoiseFields, float deltaTime)
254 {
255 if (particle == nullptr) {
256 return;
257 }
258 auto position = particle->GetPosition();
259 auto fieldForce = Vector2f(0.f, 0.f);
260 if (particleNoiseFields != nullptr) {
261 fieldForce = particleNoiseFields->ApplyAllFields(position, deltaTime);
262 }
263 auto accelerationValue = particle->GetAccelerationValue();
264 auto accelerationAngle = particle->GetAccelerationAngle();
265 accelerationAngle *= DEGREE_TO_RADIAN;
266 auto acceleration =
267 Vector2f { accelerationValue * std::cos(accelerationAngle), accelerationValue * std::sin(accelerationAngle) };
268 particle->SetAcceleration(acceleration);
269
270 Vector2f velocity = particle->GetVelocity();
271 if (!(ROSEN_EQ(acceleration.x_, 0.f) && ROSEN_EQ(acceleration.y_, 0.f))) {
272 velocity.x_ += acceleration.x_ * deltaTime;
273 velocity.y_ += acceleration.y_ * deltaTime;
274 particle->SetVelocity(velocity);
275 }
276 velocity += fieldForce;
277 if (!(ROSEN_EQ(velocity.x_, 0.f) && ROSEN_EQ(velocity.y_, 0.f))) {
278 position.x_ += velocity.x_ * deltaTime;
279 position.y_ += velocity.y_ * deltaTime;
280 particle->SetPosition(position);
281 }
282 }
283
UpdateActiveTime(const std::shared_ptr<RSRenderParticle> & particle,int64_t deltaTime)284 void RSRenderParticleEffector::UpdateActiveTime(const std::shared_ptr<RSRenderParticle>& particle, int64_t deltaTime)
285 {
286 if (particle == nullptr) {
287 return;
288 }
289 int64_t activeTime = particle->GetActiveTime();
290 activeTime += deltaTime;
291 particle->SetActiveTime(activeTime);
292 }
293
294 // Apply effector to particle
Update(const std::shared_ptr<RSRenderParticle> & particle,const std::shared_ptr<ParticleNoiseFields> & particleNoiseFields,int64_t deltaTime)295 void RSRenderParticleEffector::Update(const std::shared_ptr<RSRenderParticle>& particle,
296 const std::shared_ptr<ParticleNoiseFields>& particleNoiseFields, int64_t deltaTime)
297 {
298 if (particle == nullptr) {
299 return;
300 }
301 float dt = static_cast<float>(deltaTime) / NS_TO_S;
302 UpdateAccelerationValue(particle, dt);
303 UpdateAccelerationAngle(particle, dt);
304 UpdateColor(particle, dt);
305 UpdateOpacity(particle, dt);
306 UpdateScale(particle, dt);
307 UpdateSpin(particle, dt);
308 UpdatePosition(particle, particleNoiseFields, dt);
309 UpdateActiveTime(particle, deltaTime);
310 }
311
312 } // namespace Rosen
313 } // namespace OHOS
314