1 /*
2 * Copyright (c) 2024 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 "core/components_ng/pattern/particle/particle_pattern.h"
17
18 #include "core/components_ng/render/adapter/rosen_particle_context.h"
19
20 namespace OHOS::Ace::NG {
21 namespace {
22 std::unordered_map<ParticleDisturbanceShapeType, std::string> shapes = {
23 { ParticleDisturbanceShapeType::RECT, "RECT" },
24 { ParticleDisturbanceShapeType::CIRCLE, "CIRCLE" },
25 { ParticleDisturbanceShapeType::ELLIPSE, "ELLIPSE" } };
ShapeTypeToString(ParticleDisturbanceShapeType type)26 std::string ShapeTypeToString(ParticleDisturbanceShapeType type)
27 {
28 auto it = shapes.find(type);
29 if (it != shapes.end()) {
30 return it->second;
31 }
32 return "Unknown";
33 }
34 } // namespace
35 class RosenRenderParticle;
OnVisibleChange(bool isVisible)36 void ParticlePattern::OnVisibleChange(bool isVisible)
37 {
38 if (HaveUnVisibleParent() == !isVisible) {
39 return;
40 }
41 SetHaveUnVisibleParent(!isVisible);
42 if (isVisible) {
43 auto host = GetHost();
44 auto context = host->GetRenderContext();
45 context->OnParticleOptionArrayUpdate(context->GetParticleOptionArray().value());
46 }
47 }
48
OnAttachToMainTree()49 void ParticlePattern::OnAttachToMainTree()
50 {
51 auto host = GetHost();
52 auto parent = host->GetParent();
53 while (parent) {
54 if (InstanceOf<FrameNode>(parent)) {
55 auto frameNode = DynamicCast<FrameNode>(parent);
56 if (!frameNode->IsVisible()) {
57 SetHaveUnVisibleParent(true);
58 return;
59 }
60 }
61 parent = parent->GetParent();
62 }
63 }
64
ParseEmitterParticleJson(const ParticleOption & particleOption) const65 std::unique_ptr<JsonValue> ParticlePattern::ParseEmitterParticleJson(const ParticleOption& particleOption) const
66 {
67 auto emitterOptionOpt = particleOption.GetEmitterOption();
68 auto objectParticleJson = JsonUtil::Create(true);
69 auto particle = emitterOptionOpt.GetParticle();
70 auto particleType = particle.GetParticleType();
71 auto particleConfig = particle.GetConfig();
72 if (particleType == ParticleType::POINT) {
73 auto objectConfigJson = JsonUtil::Create(true);
74 objectParticleJson->Put("type", "ParticleType.POINT");
75 auto pointParameter = particleConfig.GetPointParticleParameter();
76 auto radius = pointParameter.GetRadius();
77 objectConfigJson->Put("radius", std::to_string(radius).c_str());
78 objectParticleJson->Put("config", objectConfigJson);
79 } else {
80 objectParticleJson->Put("type", "ParticleType.IMAGE");
81 auto objectConfigJson = JsonUtil::Create(true);
82 auto imageParameter = particleConfig.GetImageParticleParameter();
83 auto imageSource = imageParameter.GetImageSource();
84 auto imageSize = imageParameter.GetSize();
85 auto imageWidth = imageSize.first.ToString();
86 auto imageHeight = imageSize.second.ToString();
87 objectConfigJson->Put("src", imageSource.c_str());
88 auto dimension = "[" + imageWidth + "," + imageHeight + "]";
89 objectConfigJson->Put("size", dimension.c_str());
90 auto objectFit = imageParameter.GetImageFit();
91 static const char* OBJECTFITVALUE[] = { "ImageFit.Fill", "ImageFit.Contain", "ImageFit.Cover", "ImageFit.Auto",
92 "ImageFit.FitHeight", "ImageFit.None", "ImageFit.ScaleDown", "ImageFit.TOP_START", "ImageFit.TOP",
93 "ImageFit.TOP_END", "ImageFit.START", "ImageFit.CENTER", "ImageFit.END", "ImageFit.BOTTOM_START",
94 "ImageFit.BOTTOM", "ImageFit.BOTTOM_END" };
95 if (objectFit.has_value()) {
96 auto objectFitValue = static_cast<uint32_t>(objectFit.value());
97 if (objectFitValue < sizeof(OBJECTFITVALUE) / sizeof(char*)) {
98 objectConfigJson->Put("objectFit", OBJECTFITVALUE[objectFitValue]);
99 }
100 }
101 objectParticleJson->Put("config", objectConfigJson);
102 }
103 auto particleCount = particle.GetCount();
104 objectParticleJson->Put("count", std::to_string(particleCount).c_str());
105 auto lifeTimeOpt = particle.GetLifeTime();
106 if (lifeTimeOpt.has_value()) {
107 objectParticleJson->Put("lifetime", std::to_string(lifeTimeOpt.value()).c_str());
108 }
109 auto lifeTimeRangeOpt = particle.GetLifeTimeRange();
110 if (lifeTimeRangeOpt.has_value()) {
111 objectParticleJson->Put("lifetimeRange", std::to_string(lifeTimeRangeOpt.value()).c_str());
112 }
113 return objectParticleJson;
114 }
115
GetEmitterJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const116 void ParticlePattern::GetEmitterJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
117 const ParticleOption& particleOption) const
118 {
119 auto objectEmitterJson = JsonUtil::Create(true);
120 auto objectParticleJson = ParseEmitterParticleJson(particleOption);
121 objectEmitterJson->Put("particle", objectParticleJson);
122
123 auto emitterOptionOpt = particleOption.GetEmitterOption();
124 auto emitterRateOpt = emitterOptionOpt.GetEmitterRate();
125 if (emitterRateOpt.has_value()) {
126 objectEmitterJson->Put("emitRate", std::to_string(emitterRateOpt.value()).c_str());
127 }
128 auto shapeOpt = emitterOptionOpt.GetShape();
129 if (shapeOpt.has_value()) {
130 auto shapeInt = static_cast<int32_t>(shapeOpt.value());
131 if (shapeInt == ParticleEmitterShape::CIRCLE) {
132 objectEmitterJson->Put("shape", "ParticleEmitterShape.CIRCLE");
133 } else if (shapeInt == ParticleEmitterShape::ELLIPSE) {
134 objectEmitterJson->Put("shape", "ParticleEmitterShape.ELLIPSE");
135 } else {
136 objectEmitterJson->Put("shape", "ParticleEmitterShape.RECTANGLE");
137 }
138 }
139 auto pointOpt = emitterOptionOpt.GetPosition();
140 if (pointOpt.has_value()) {
141 auto position = "[" + pointOpt.value().first.ToString() + "," + pointOpt.value().second.ToString() + "]";
142 objectEmitterJson->Put("position", position.c_str());
143 }
144 auto sizeOpt = emitterOptionOpt.GetSize();
145 if (sizeOpt.has_value()) {
146 auto position = "[" + sizeOpt.value().first.ToString() + "," + sizeOpt.value().second.ToString() + "]";
147 objectEmitterJson->Put("size", position.c_str());
148 }
149 objectParticlesJson->Put("emitter", objectEmitterJson);
150 }
151
ParseColorUpdater(ParticleColorPropertyUpdater & updater) const152 std::unique_ptr<JsonValue> ParticlePattern::ParseColorUpdater(ParticleColorPropertyUpdater& updater) const
153 {
154 auto updateType = updater.GetUpdateType();
155 auto config = updater.GetConfig();
156 auto objectUpdaterJson = JsonUtil::Create(true);
157 if (updateType == UpdaterType::RANDOM) {
158 objectUpdaterJson->Put("type", "ParticleUpdater.RANDOM");
159 auto randomConfig = config.GetRandomConfig();
160 auto redRandom = randomConfig.GetRedRandom();
161 auto greenRandom = randomConfig.GetGreenRandom();
162 auto blueRandom = randomConfig.GetBlueRandom();
163 auto alphaRandom = randomConfig.GetAlphaRandom();
164 auto configJson = JsonUtil::Create(true);
165 auto rString = "[" + std::to_string(redRandom.first) + "," +
166 std::to_string(redRandom.second) + "]";
167 configJson->Put("r", rString.c_str());
168 auto gString = "[" + std::to_string(greenRandom.first) + "," +
169 std::to_string(greenRandom.second) + "]";
170 configJson->Put("g", gString.c_str());
171 auto bString = "[" + std::to_string(blueRandom.first) + "," +
172 std::to_string(blueRandom.second) + "]";
173 configJson->Put("b", bString.c_str());
174 auto aString = "[" + std::to_string(alphaRandom.first) + "," +
175 std::to_string(alphaRandom.second) + "]";
176 configJson->Put("a", aString.c_str());
177 objectUpdaterJson->Put("config", configJson);
178 } else if (updateType == UpdaterType::CURVE) {
179 objectUpdaterJson->Put("type", "ParticleUpdater.CURVE");
180 auto configArrayJson = JsonUtil::CreateArray(true);
181 auto& curveConfig = config.GetAnimationArray();
182 for (const auto& colorAnimationConfig : curveConfig) {
183 auto fromColor = colorAnimationConfig.GetFrom().ToString();
184 auto toColor = colorAnimationConfig.GetTo().ToString();
185 auto startMills = colorAnimationConfig.GetStartMills();
186 auto endMills = colorAnimationConfig.GetEndMills();
187 auto curve = colorAnimationConfig.GetCurve();
188 auto configJson = JsonUtil::Create(true);
189 configJson->Put("from", fromColor.c_str());
190 configJson->Put("to", toColor.c_str());
191 configJson->Put("startMillis", std::to_string(startMills).c_str());
192 configJson->Put("endMillis", std::to_string(endMills).c_str());
193 configJson->Put("curve", curve->ToString().c_str());
194 configArrayJson->Put(configJson);
195 }
196 objectUpdaterJson->Put("config", configArrayJson);
197 } else {
198 objectUpdaterJson->Put("type", "ParticleUpdater.NONE");
199 objectUpdaterJson->Put("config", "");
200 }
201 return objectUpdaterJson;
202 }
203
GetColorJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const204 void ParticlePattern::GetColorJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
205 const ParticleOption& particleOption) const
206 {
207 auto colorOptionOpt = particleOption.GetParticleColorOption();
208 if (!colorOptionOpt.has_value()) {
209 return;
210 }
211 auto objectColorJson = JsonUtil::Create(true);
212 auto colorOption = colorOptionOpt.value();
213 auto initRange = colorOption.GetRange();
214 auto colorDist = colorOption.GetDistribution();
215 objectColorJson->Put("range", ("[" + initRange.first.ToString() + "," +
216 initRange.second.ToString() +"]").c_str());
217 auto colorDistInt = colorDist.value_or(DistributionType::UNIFORM);
218 if (colorDistInt == DistributionType::UNIFORM) {
219 objectColorJson->Put("distributionType", "DistributionType::UNIFORM");
220 } else {
221 objectColorJson->Put("distributionType", "DistributionType::GAUSSIAN");
222 }
223 auto updaterOpt = colorOption.GetUpdater();
224 if (!updaterOpt.has_value()) {
225 objectParticlesJson->Put("color", objectColorJson);
226 return;
227 }
228 auto updater = updaterOpt.value();
229 auto objectUpdaterJson = ParseColorUpdater(updater);
230 objectColorJson->Put("updater", objectUpdaterJson);
231 objectParticlesJson->Put("color", objectColorJson);
232 }
233
GetOpacityJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const234 void ParticlePattern::GetOpacityJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
235 const ParticleOption& particleOption) const
236 {
237 auto opacityOptionOpt = particleOption.GetParticleOpacityOption();
238 if (!opacityOptionOpt.has_value()) {
239 return;
240 }
241 objectParticlesJson->Put("opacity", ParseFloatObjectJson(opacityOptionOpt.value()));
242 }
243
GetScaleJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const244 void ParticlePattern::GetScaleJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
245 const ParticleOption& particleOption) const
246 {
247 auto scaleOptionOpt = particleOption.GetParticleScaleOption();
248 if (!scaleOptionOpt.has_value()) {
249 return;
250 }
251 objectParticlesJson->Put("scale", ParseFloatObjectJson(scaleOptionOpt.value()));
252 }
253
GetVelocityJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const254 void ParticlePattern::GetVelocityJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
255 const ParticleOption& particleOption) const
256 {
257 auto velocityOptionOpt = particleOption.GetParticleVelocityOption();
258 if (!velocityOptionOpt.has_value()) {
259 return;
260 }
261 auto objectVelocityJson = JsonUtil::Create(true);
262 auto velocityValue = velocityOptionOpt.value();
263 auto speed = velocityValue.GetSpeedRange();
264 auto angle = velocityValue.GetAngleRange();
265 auto speedString = "[" + std::to_string(speed.first) + "," +
266 std::to_string(speed.second) + "]";
267 objectVelocityJson->Put("speed", speedString.c_str());
268 auto angleString = "[" + std::to_string(angle.first) + "," +
269 std::to_string(angle.second) + "]";
270 objectVelocityJson->Put("angle", angleString.c_str());
271 objectParticlesJson->Put("velocity", objectVelocityJson);
272 }
273
GetAccelerationJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const274 void ParticlePattern::GetAccelerationJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
275 const ParticleOption& particleOption) const
276 {
277 auto accelerationOpt = particleOption.GetParticleAccelerationOption();
278 if (!accelerationOpt.has_value()) {
279 return;
280 }
281 auto objectAccelerationJson = JsonUtil::Create(true);
282 auto acceleration = accelerationOpt.value();
283 auto speedOpt = acceleration.GetSpeed();
284 auto angleOpt = acceleration.GetAngle();
285 if (speedOpt.has_value()) {
286 objectAccelerationJson->Put("speed", ParseFloatObjectJson(speedOpt.value()));
287 }
288 if (angleOpt.has_value()) {
289 objectAccelerationJson->Put("angle", ParseFloatObjectJson(angleOpt.value()));
290 }
291 objectParticlesJson->Put("acceleration", objectAccelerationJson);
292 }
293
GetSpinJson(const std::unique_ptr<JsonValue> & objectParticlesJson,const ParticleOption & particleOption) const294 void ParticlePattern::GetSpinJson(const std::unique_ptr<JsonValue>& objectParticlesJson,
295 const ParticleOption& particleOption) const
296 {
297 auto spinOptionOpt = particleOption.GetParticleSpinOption();
298 auto objectSpinJson = JsonUtil::Create(true);
299 if (!spinOptionOpt.has_value()) {
300 return;
301 }
302 objectParticlesJson->Put("spin", ParseFloatObjectJson(spinOptionOpt.value()));
303 }
304
ParseFloatObjectJson(const ParticleFloatPropertyOption & floatObject) const305 std::unique_ptr<JsonValue> ParticlePattern::ParseFloatObjectJson(const ParticleFloatPropertyOption& floatObject) const
306 {
307 auto objectJson = JsonUtil::Create(true);
308 auto initRange = floatObject.GetRange();
309 objectJson->Put("range", ("[" + std::to_string(initRange.first) + "," +
310 std::to_string(initRange.second) + "]").c_str());
311
312 auto updaterOpt = floatObject.GetUpdater();
313 if (!updaterOpt.has_value()) {
314 return objectJson;
315 }
316 auto objectUpdaterJson = JsonUtil::Create(true);
317 auto updater = updaterOpt.value();
318 auto updateType = updater.GetUpdaterType();
319 auto config = updater.GetConfig();
320 if (updateType == UpdaterType::RANDOM) {
321 objectUpdaterJson->Put("type", "ParticleUpdater.RANDOM");
322 auto randomConfig = config.GetRandomConfig();
323 auto configString = "[" + std::to_string(randomConfig.first) + "," +
324 std::to_string(randomConfig.second) + "]";
325 objectUpdaterJson->Put("config", configString.c_str());
326 } else if (updateType == UpdaterType::CURVE) {
327 objectUpdaterJson->Put("type", "ParticleUpdater.CURVE");
328 auto configArrayJson = JsonUtil::CreateArray(true);
329 auto& curveConfig = config.GetAnimations();
330 for (const auto& animationConfig : curveConfig) {
331 auto fromColor = animationConfig.GetFrom();
332 auto toColor = animationConfig.GetTo();
333 auto startMills = animationConfig.GetStartMills();
334 auto endMills = animationConfig.GetEndMills();
335 auto curve = animationConfig.GetCurve();
336 auto configJson = JsonUtil::Create(true);
337 configJson->Put("from", std::to_string(fromColor).c_str());
338 configJson->Put("to", std::to_string(toColor).c_str());
339 configJson->Put("startMillis", std::to_string(startMills).c_str());
340 configJson->Put("endMillis", std::to_string(endMills).c_str());
341 configJson->Put("curve", curve->ToString().c_str());
342 configArrayJson->Put(configJson);
343 }
344 objectUpdaterJson->Put("config", configArrayJson);
345 } else if (updateType == UpdaterType::NONE_UPDATER) {
346 objectUpdaterJson->Put("type", "ParticleUpdater.NONE");
347 objectUpdaterJson->Put("config", "");
348 }
349 objectJson->Put("updater", objectUpdaterJson);
350 return objectJson;
351 }
352
ParseParticleObject(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const353 void ParticlePattern::ParseParticleObject(std::unique_ptr<JsonValue>& json,
354 const InspectorFilter& filter) const
355 {
356 auto host = GetHost();
357 CHECK_NULL_VOID(host);
358 auto context = host->GetRenderContext();
359 CHECK_NULL_VOID(context);
360 if (!context->GetParticleOptionArray().has_value()) {
361 return;
362 }
363 auto particleArray = context->GetParticleOptionArray().value();
364 auto objectParticlesArrayJson = JsonUtil::CreateArray(true);
365 for (auto& particle : particleArray) {
366 auto objectParticlesJson = JsonUtil::Create(true);
367 GetEmitterJson(objectParticlesJson, particle);
368 GetColorJson(objectParticlesJson, particle);
369 GetOpacityJson(objectParticlesJson, particle);
370 GetScaleJson(objectParticlesJson, particle);
371 GetVelocityJson(objectParticlesJson, particle);
372 GetAccelerationJson(objectParticlesJson, particle);
373 GetSpinJson(objectParticlesJson, particle);
374 objectParticlesArrayJson->Put(objectParticlesJson);
375 }
376 json->PutExtAttr("particles", objectParticlesArrayJson, filter);
377 }
378
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const379 void ParticlePattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
380 {
381 auto props = GetEmitterProperty();
382 if (props.size() > 0) {
383 auto array = JsonUtil::CreateArray(true);
384 for (size_t i = 0; i < props.size(); i++) {
385 auto object = JsonUtil::Create(true);
386 object->Put("index", std::to_string(props[i].index).c_str());
387 if (props[i].emitRate.has_value()) {
388 object->Put("emitRate", std::to_string(*props[i].emitRate).c_str());
389 }
390 if (props[i].position.has_value()) {
391 auto positionObj = JsonUtil::Create(true);
392 positionObj->Put("x", std::to_string(props[i].position->x).c_str());
393 positionObj->Put("y", std::to_string(props[i].position->y).c_str());
394 object->Put("position", positionObj);
395 }
396 if (props[i].size.has_value()) {
397 auto sizeObj = JsonUtil::Create(true);
398 sizeObj->Put("x", std::to_string(props[i].size->x).c_str());
399 sizeObj->Put("y", std::to_string(props[i].size->y).c_str());
400 object->Put("size", sizeObj);
401 }
402 array->Put(std::to_string(i).c_str(), object);
403 }
404 json->Put("emitter", array);
405 }
406 auto disturbance = GetDisturbance();
407 if (disturbance.size() > 0) {
408 auto disturbanceFieldsArray = JsonUtil::CreateArray(true);
409 for (size_t i = 0; i < disturbance.size(); i++) {
410 auto object = JsonUtil::Create(true);
411 object->Put("strength", disturbance[i].strength);
412 object->Put("shape", ShapeTypeToString(disturbance[i].shape).c_str());
413 auto size = JsonUtil::Create(true);
414 size->Put("width", disturbance[i].size[0]);
415 size->Put("height", disturbance[i].size[1]);
416 object->Put("size", size);
417 auto position = JsonUtil::Create(true);
418 size->Put("x", disturbance[i].position[0]);
419 size->Put("y", disturbance[i].position[1]);
420 object->Put("feather", disturbance[i].feather);
421 object->Put("noiseScale", disturbance[i].noiseScale);
422 object->Put("noiseFrequency", disturbance[i].noiseFrequency);
423 object->Put("noiseAmplitude", disturbance[i].noiseAmplitude);
424 disturbanceFieldsArray->Put(std::to_string(i).c_str(), object);
425 }
426 json->Put("disturbanceFields", disturbanceFieldsArray);
427 }
428 ParseParticleObject(json, filter);
429 }
430
UpdateDisturbance(const std::vector<ParticleDisturbance> & disturbanceArray)431 void ParticlePattern::UpdateDisturbance(const std::vector<ParticleDisturbance>& disturbanceArray)
432 {
433 if (disturbanceArray.size() == 0) {
434 return;
435 }
436 const std::vector<ParticleDisturbance>& disturbance = GetDisturbance();
437 if (disturbance.size() != disturbanceArray.size()) {
438 SetDisturbance(disturbanceArray);
439 auto frameNode = GetHost();
440 RosenRenderParticle::UpdateDisturbance(frameNode, disturbanceArray);
441 return;
442 }
443 bool equal = true;
444 for (size_t i = 0; i < disturbance.size(); i++) {
445 ParticleDisturbance src = disturbance[i];
446 ParticleDisturbance dst = disturbanceArray[i];
447 if (src != dst) {
448 equal = false;
449 break;
450 }
451 }
452 if (equal) {
453 return;
454 }
455 SetDisturbance(disturbanceArray);
456 auto frameNode = GetHost();
457 RosenRenderParticle::UpdateDisturbance(frameNode, disturbanceArray);
458 }
459
updateEmitterPosition(std::vector<EmitterProperty> & props)460 void ParticlePattern::updateEmitterPosition(std::vector<EmitterProperty>& props)
461 {
462 auto frameNode = GetHost();
463 for (EmitterProperty& prop : props) {
464 prop.index = prop.index >= GetEmitterCount() ? 0 : prop.index;
465 }
466 SetEmitterProperty(props);
467 RosenRenderParticle::updateEmitterPosition(frameNode, props);
468 }
469 } // namespace OHOS::Ace::NG