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