[dali_2.3.12] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-toolkit / utc-Dali-ParticleSystem.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-test-suite-utils.h>
19 #include <dali-toolkit/public-api/particle-system/particle-domain.h>
20 #include <dali-toolkit/public-api/particle-system/particle-emitter.h>
21 #include <dali-toolkit/public-api/particle-system/particle-list.h>
22 #include <dali-toolkit/public-api/particle-system/particle-modifier.h>
23 #include <dali-toolkit/public-api/particle-system/particle-renderer.h>
24 #include <dali-toolkit/public-api/particle-system/particle-source.h>
25 #include <dali-toolkit/public-api/particle-system/particle.h>
26
27 #include <dlfcn.h>
28
29 #include <future>
30
31 using namespace Dali;
32 using namespace Dali::Toolkit::ParticleSystem;
33
34 /**
35  * Helper function to invoke next function in the call chain
36  */
37 template<class R, class T, class... Args>
38 R InvokeNext(T* pObj, Args... args)
39 {
40   Dl_info info;
41   dladdr(__builtin_return_address(0), &info);
42   using Func = R (*)(T*, Args...);
43   auto sym   = (Func)(dlsym(RTLD_NEXT, info.dli_sname));
44   return sym(pObj, args...);
45 }
46
47 static std::chrono::milliseconds currentTime(1u);
48 static void                      AdvanceTimeByMs(uint32_t ms)
49 {
50   currentTime += std::chrono::milliseconds(ms);
51 }
52
53 namespace Dali::Toolkit::ParticleSystem::Internal
54 {
55 // Create fake time getter
56 struct ParticleEmitter
57 {
58   [[nodiscard]] std::chrono::milliseconds GetCurrentTimeMillis() const;
59 };
60 std::chrono::milliseconds ParticleEmitter::GetCurrentTimeMillis() const
61 {
62   [[maybe_unused]] auto value = InvokeNext<std::chrono::milliseconds>(this);
63   return std::chrono::milliseconds(currentTime);
64 }
65 } // namespace Dali::Toolkit::ParticleSystem::Internal
66
67 using ParticleEmitterWrapper = Dali::Toolkit::ParticleSystem::Internal::ParticleEmitter;
68
69 Texture CreateTexture()
70 {
71   Texture   texture   = Texture::New(Dali::TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, 100, 100);
72   uint8_t*  data      = reinterpret_cast<uint8_t*>(malloc(100 * 100 * 4));
73   PixelData pixelData = PixelData::New(data, 100 * 100 * 4, 100, 100, Pixel::Format::RGBA8888, PixelData::FREE);
74   texture.Upload(pixelData);
75   return texture;
76 }
77
78 /**
79  * Test particle source
80  */
81 class TestSource : public ParticleSourceInterface
82 {
83 public:
84   TestSource(ParticleEmitter* emitter)
85   : mEmitter(*emitter)
86   {
87   }
88
89   void NewFrame()
90   {
91     mPromise = std::promise<uint32_t>();
92     mFuture  = mPromise.get_future();
93   }
94
95   uint32_t Update(ParticleList& outList, uint32_t count) override
96   {
97     mPromise.set_value(count);
98     auto i = count;
99     while(--i)
100     {
101       outList.NewParticle(1.0f);
102     }
103     return count;
104   }
105
106   void Init() override
107   {
108     // calls initialized
109     mInitialized = true;
110   }
111
112   bool                   mInitialized{false};
113   std::future<uint32_t>  mFuture;
114   std::promise<uint32_t> mPromise;
115   ParticleEmitter&       mEmitter;
116 };
117
118 class TestSource2 : public ParticleSourceInterface
119 {
120 public:
121   TestSource2(ParticleEmitter* emitter)
122   : mEmitter(*emitter)
123   {
124   }
125
126   void NewFrame()
127   {
128     mPromise = std::promise<uint32_t>();
129     mFuture  = mPromise.get_future();
130   }
131
132   uint32_t Update(ParticleList& outList, uint32_t count) override
133   {
134     mPromise.set_value(count);
135
136     while(count--)
137     {
138       auto particle = outList.NewParticle(1.0);
139       if(!particle)
140       {
141         return 0u;
142       }
143
144       [[maybe_unused]] auto& pos = particle.GetByIndex<Vector3>(mStreamBasePos);
145
146       [[maybe_unused]] auto& gpos = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
147       [[maybe_unused]] auto& col  = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
148       [[maybe_unused]] auto& vel  = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
149       [[maybe_unused]] auto& sca  = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
150       //auto& basePos = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
151     }
152
153     return count;
154   }
155
156   void Init() override
157   {
158     // calls initialized
159     mStreamBasePos = mEmitter.GetParticleList().AddLocalStream<Vector3>(Vector3::ZERO);
160     mInitialized   = true;
161   }
162
163   bool                   mInitialized{false};
164   std::future<uint32_t>  mFuture;
165   std::promise<uint32_t> mPromise;
166   uint32_t               mStreamBasePos{0u};
167   ParticleEmitter&       mEmitter;
168 };
169 /**
170  * Sample of FlameModifier
171  */
172 struct TestModifier : public ParticleModifierInterface
173 {
174   void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
175   {
176   }
177 };
178
179 struct TestModifierMT : public ParticleModifierInterface
180 {
181   void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
182   {
183   }
184
185   bool IsMultiThreaded() override
186   {
187     return true;
188   }
189 };
190
191 /**
192  * Another modifier to test modifier stack
193  */
194 struct TestModifier2 : public ParticleModifierInterface
195 {
196   void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
197   {
198   }
199 };
200
201 struct EmitterGroup
202 {
203   ParticleEmitter  emitter;
204   ParticleRenderer renderer;
205   ParticleModifier modifier;
206   ParticleSource   source;
207 };
208
209 // Helper function to create emitter (every test will be doing that)
210 template<class SOURCE, class MODIFIER>
211 ParticleEmitter CreateEmitter(EmitterGroup* output = nullptr)
212 {
213   auto emitter = ParticleEmitter::New();
214
215   bool result = (emitter != nullptr);
216   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
217
218   // Create test source
219   auto source = ParticleSource::New<SOURCE>(&emitter);
220
221   {
222     BaseHandle handle(source);
223     auto       newHandle = ParticleSource::DownCast(handle);
224     DALI_TEST_EQUALS(newHandle, source, TEST_LOCATION);
225   }
226
227   // Create test renderer
228   auto renderer = ParticleRenderer::New();
229
230   {
231     BaseHandle handle(renderer);
232     auto       newHandle = ParticleRenderer::DownCast(handle);
233     DALI_TEST_EQUALS(newHandle, renderer, TEST_LOCATION);
234   }
235
236   // Create modifier
237   auto modifier = ParticleModifier::New<MODIFIER>();
238
239   {
240     BaseHandle handle(modifier);
241     auto       newHandle = ParticleModifier::DownCast(handle);
242     DALI_TEST_EQUALS(newHandle, modifier, TEST_LOCATION);
243   }
244
245   auto domain = ParticleDomain::New();
246
247   {
248     BaseHandle handle(domain);
249     auto       newHandle = ParticleDomain::DownCast(handle);
250     DALI_TEST_EQUALS(newHandle, domain, TEST_LOCATION);
251   }
252
253   // Test emitter readiness
254   auto ready = emitter.GetStatus();
255
256   // Emitter should return status incomplete
257   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
258
259   // Attach all components to the emitter
260   emitter.SetSource(source);
261   emitter.SetRenderer(renderer);
262   emitter.AddModifier(modifier);
263   emitter.SetDomain(domain);
264
265   auto domain0   = emitter.GetDomain();
266   auto renderer0 = emitter.GetRenderer();
267
268   DALI_TEST_EQUALS(renderer0, renderer, TEST_LOCATION);
269   DALI_TEST_EQUALS(domain0, domain, TEST_LOCATION);
270
271   if(output)
272   {
273     output->emitter  = emitter;
274     output->renderer = renderer;
275     output->modifier = modifier;
276     output->source   = source;
277   }
278
279   return emitter;
280 }
281
282 int UtcDaliParticleSystemEmitterNew(void)
283 {
284   // create particle emitter
285   auto emitter = ParticleEmitter::New();
286
287   bool result = (emitter != nullptr);
288   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
289
290   // Create test source
291   auto source = ParticleSource::New<TestSource>(&emitter);
292
293   // Create test renderer
294   auto renderer = ParticleRenderer::New();
295
296   // Create modifier
297   auto modifier = ParticleModifier::New<TestModifier>();
298
299   // Create domain
300   auto domain = ParticleDomain::New();
301
302   // Test emitter readiness
303   auto ready = emitter.GetStatus();
304
305   // Emitter should return status incomplete
306   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
307
308   // Attach all components to the emitter
309   emitter.SetSource(source);
310   emitter.SetRenderer(renderer);
311   emitter.AddModifier(modifier);
312   emitter.SetDomain(domain);
313
314   // test status again (domain is optional);
315   ready = emitter.GetStatus();
316
317   // Emitter should return status incomplete
318   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
319
320   END_TEST;
321 }
322
323 int UtcDaliParticleSystemEmitterNew2(void)
324 {
325   // create particle emitter
326   auto emitter = ParticleEmitter::New();
327
328   bool result = (emitter != nullptr);
329   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
330
331   // Create test source
332   auto source = ParticleSource::New<TestSource>(&emitter);
333
334   // Create test renderer
335   auto renderer = ParticleRenderer::New();
336
337   // Create modifier
338   auto modifier = ParticleModifier::New<TestModifier>();
339
340   // Create domain
341   auto domain = ParticleDomain::New();
342
343   // Test emitter readiness
344   auto ready = emitter.GetStatus();
345
346   // Emitter should return status incomplete
347   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
348
349   // Attach all components to the emitter
350   emitter.SetSource(source);
351   emitter.SetRenderer(renderer);
352   emitter.AddModifier(modifier);
353   emitter.SetDomain(domain);
354
355   // test blending mode
356   DALI_TEST_EQUALS(renderer.GetBlendingMode(), Dali::Toolkit::ParticleSystem::BlendingMode::DEFAULT, TEST_LOCATION);
357
358   emitter.SetParticleCount(10000);
359   DALI_TEST_EQUALS(emitter.GetParticleCount(), 10000, TEST_LOCATION);
360
361   auto m = emitter.GetModifierAt(0);
362   DALI_TEST_EQUALS(m != nullptr, true, TEST_LOCATION);
363
364   m.GetModifierCallback();
365
366   // test status again (domain is optional);
367   ready = emitter.GetStatus();
368
369   // Emitter should return status incomplete
370   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
371
372   END_TEST;
373 }
374
375 int UtcDaliParticleSystemEmitterDefaultStreams(void)
376 {
377   // create particle emitter
378   auto emitter = ParticleEmitter::New();
379
380   bool result = (emitter != nullptr);
381   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
382
383   // Create test source
384   auto source = ParticleSource::New<TestSource>(&emitter);
385
386   // Create test renderer
387   auto renderer = ParticleRenderer::New();
388
389   // Create modifier
390   auto modifier = ParticleModifier::New<TestModifier>();
391
392   // Create domain
393   auto domain = ParticleDomain::New();
394
395   // Test emitter readiness
396   auto ready = emitter.GetStatus();
397
398   // Emitter should return status incomplete
399   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
400
401   // Attach all components to the emitter
402   emitter.SetSource(source);
403   emitter.SetRenderer(renderer);
404   emitter.AddModifier(modifier);
405   emitter.SetDomain(domain);
406
407   auto                  particleList   = emitter.GetParticleList();
408   std::vector<uint32_t> expectedValues = {
409     ParticleStream::POSITION_STREAM_BIT, 0, ParticleStream::COLOR_STREAM_BIT, 3, ParticleStream::VELOCITY_STREAM_BIT, 2, ParticleStream::SCALE_STREAM_BIT, 1, ParticleStream::LIFETIME_STREAM_BIT, 4, ParticleStream::LIFETIME_BASE_STREAM_BIT, 5};
410
411   for(auto i = 0u; i < expectedValues.size(); i += 2)
412   {
413     auto index = particleList.GetDefaultStreamIndex(expectedValues[i]);
414     DALI_TEST_EQUALS(index, expectedValues[i + 1], TEST_LOCATION);
415   }
416
417   // test status again (domain is optional);
418   ready = emitter.GetStatus();
419
420   // Emitter should return status incomplete
421   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
422
423   END_TEST;
424 }
425
426 int UtcDaliParticleSystemEmitterModifierStack(void)
427 {
428   // create particle emitter
429   auto emitter = ParticleEmitter::New();
430
431   bool result = (emitter != nullptr);
432   DALI_TEST_EQUALS(result, true, TEST_LOCATION);
433
434   // Create test source
435   auto source = ParticleSource::New<TestSource>(&emitter);
436
437   // Create test renderer
438   auto renderer = ParticleRenderer::New();
439
440   // Create modifier
441   auto modifier0 = ParticleModifier::New<TestModifier>();
442   auto modifier1 = ParticleModifier::New<TestModifier>();
443   auto modifier2 = ParticleModifier::New<TestModifier>();
444
445   // Create domain
446   auto domain = ParticleDomain::New();
447
448   // Test emitter readiness
449   auto ready = emitter.GetStatus();
450
451   // Emitter should return status incomplete
452   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
453
454   // Attach all components to the emitter
455   emitter.SetSource(source);
456   emitter.SetRenderer(renderer);
457   emitter.AddModifier(modifier0);
458   emitter.AddModifier(modifier1);
459   emitter.AddModifier(modifier2);
460
461   emitter.SetDomain(domain);
462
463   // test status again (domain is optional);
464   ready = emitter.GetStatus();
465
466   // Emitter should return status incomplete
467   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
468
469   auto modifier = emitter.GetModifierAt(1);
470   DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
471
472   emitter.RemoveModifierAt(0);
473   modifier = emitter.GetModifierAt(0);
474   DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
475
476   END_TEST;
477 }
478
479 int UtcDaliParticleSystemTest(void)
480 {
481   TestApplication application;
482
483   // Create actor to be used with emitter
484   Actor actor = Actor::New();
485   application.GetScene().Add(actor);
486   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
487
488   auto emitter = CreateEmitter<TestSource, TestModifier>();
489
490   // test status again (domain is optional);
491   auto ready = emitter.GetStatus();
492
493   // Emitter should return status incomplete
494   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
495
496   // Set initial parameters of system
497   emitter.SetInitialParticleCount(1000);
498   emitter.SetActiveParticlesLimit(5000);
499
500   // Test getters
501   auto initialParticleCount = emitter.GetInitialParticleCount();
502   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
503
504   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
505   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
506
507   // Attach emitter to actor
508   emitter.AttachTo(actor);
509
510   // Start emitter
511   emitter.Start();
512
513   auto status = emitter.GetStatus();
514   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
515
516   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
517
518   // Run simulation
519   sourceCallback.NewFrame();
520   application.SendNotification();
521   application.Render();
522
523   // First call into source callback should emit initial number of particles
524   auto emittedParticleCount = sourceCallback.mFuture.get();
525   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
526
527   // Run 3 more frames advancing by 1000ms which should
528   // emit particles based on emission rate
529   AdvanceTimeByMs(1000);
530
531   sourceCallback.NewFrame();
532   application.SendNotification();
533   application.Render();
534
535   AdvanceTimeByMs(1000);
536
537   sourceCallback.NewFrame();
538   application.SendNotification();
539   application.Render();
540
541   AdvanceTimeByMs(1000);
542
543   sourceCallback.NewFrame();
544   application.SendNotification();
545   application.Render();
546
547   END_TEST;
548 }
549
550 int UtcDaliParticleSystemTestWithTextureScreen(void)
551 {
552   TestApplication application;
553
554   // Create actor to be used with emitter
555   Actor actor = Actor::New();
556   application.GetScene().Add(actor);
557   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
558
559   EmitterGroup group;
560
561   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
562
563   // Blending mode with screen
564   auto texture = CreateTexture();
565   group.renderer.SetTexture(texture);
566   group.renderer.SetBlendingMode(BlendingMode::SCREEN);
567
568   // test status again (domain is optional);
569   auto ready = emitter.GetStatus();
570
571   // Emitter should return status incomplete
572   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
573
574   // Set initial parameters of system
575   emitter.SetInitialParticleCount(1000);
576   emitter.SetActiveParticlesLimit(5000);
577
578   // Test getters
579   auto initialParticleCount = emitter.GetInitialParticleCount();
580   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
581
582   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
583   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
584
585   // Attach emitter to actor
586   emitter.AttachTo(actor);
587
588   // Start emitter
589   emitter.Start();
590
591   auto status = emitter.GetStatus();
592   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
593
594   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
595
596   // Run simulation
597   sourceCallback.NewFrame();
598   application.SendNotification();
599   application.Render();
600
601   // First call into source callback should emit initial number of particles
602   auto emittedParticleCount = sourceCallback.mFuture.get();
603   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
604
605   // Run 3 more frames advancing by 1000ms which should
606   // emit particles based on emission rate
607   AdvanceTimeByMs(1000);
608
609   sourceCallback.NewFrame();
610   application.SendNotification();
611   application.Render();
612
613   AdvanceTimeByMs(1000);
614
615   sourceCallback.NewFrame();
616   application.SendNotification();
617   application.Render();
618
619   AdvanceTimeByMs(1000);
620
621   sourceCallback.NewFrame();
622   application.SendNotification();
623   application.Render();
624
625   END_TEST;
626 }
627
628 int UtcDaliParticleSystemTestWithTextureAdd(void)
629 {
630   TestApplication application;
631
632   // Create actor to be used with emitter
633   Actor actor = Actor::New();
634   application.GetScene().Add(actor);
635   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
636
637   EmitterGroup group;
638
639   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
640
641   // Blending mode with screen
642   auto texture = CreateTexture();
643   group.renderer.SetTexture(texture);
644   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
645
646   // test status again (domain is optional);
647   auto ready = emitter.GetStatus();
648
649   // Emitter should return status incomplete
650   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
651
652   // Set initial parameters of system
653   emitter.SetInitialParticleCount(1000);
654   emitter.SetActiveParticlesLimit(5000);
655
656   // Test getters
657   auto initialParticleCount = emitter.GetInitialParticleCount();
658   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
659
660   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
661   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
662
663   // Attach emitter to actor
664   emitter.AttachTo(actor);
665
666   // Start emitter
667   emitter.Start();
668
669   auto status = emitter.GetStatus();
670   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
671
672   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
673
674   // Run simulation
675   sourceCallback.NewFrame();
676   application.SendNotification();
677   application.Render();
678
679   // First call into source callback should emit initial number of particles
680   auto emittedParticleCount = sourceCallback.mFuture.get();
681   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
682
683   // Run 3 more frames advancing by 1000ms which should
684   // emit particles based on emission rate
685   AdvanceTimeByMs(1000);
686
687   sourceCallback.NewFrame();
688   application.SendNotification();
689   application.Render();
690
691   AdvanceTimeByMs(1000);
692
693   sourceCallback.NewFrame();
694   application.SendNotification();
695   application.Render();
696
697   AdvanceTimeByMs(1000);
698
699   sourceCallback.NewFrame();
700   application.SendNotification();
701   application.Render();
702
703   END_TEST;
704 }
705
706 int UtcDaliParticleSystemTestInitialSetup(void)
707 {
708   TestApplication application;
709
710   // Create actor to be used with emitter
711   Actor actor = Actor::New();
712   application.GetScene().Add(actor);
713   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
714
715   EmitterGroup group;
716
717   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
718
719   emitter.SetEmissionRate(1000);
720   emitter.SetInitialParticleCount(1000);
721   emitter.SetActiveParticlesLimit(10000);
722
723   auto emissionRate = emitter.GetEmissionRate();
724   auto initialCount = emitter.GetInitialParticleCount();
725   auto activeCount  = emitter.GetActiveParticlesLimit();
726
727   DALI_TEST_EQUALS(emissionRate, 1000, TEST_LOCATION);
728   DALI_TEST_EQUALS(initialCount, 1000, TEST_LOCATION);
729   DALI_TEST_EQUALS(activeCount, 10000, TEST_LOCATION);
730
731   // Blending mode with screen
732   auto texture = CreateTexture();
733   group.renderer.SetTexture(texture);
734   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
735
736   // test status again (domain is optional);
737   auto ready = emitter.GetStatus();
738
739   // Emitter should return status incomplete
740   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
741
742   // Set initial parameters of system
743   emitter.SetInitialParticleCount(1000);
744   emitter.SetActiveParticlesLimit(5000);
745
746   // Test getters
747   auto initialParticleCount = emitter.GetInitialParticleCount();
748   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
749
750   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
751   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
752
753   // Attach emitter to actor
754   emitter.AttachTo(actor);
755
756   // Start emitter
757   emitter.Start();
758
759   auto status = emitter.GetStatus();
760   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
761
762   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
763
764   // Run simulation
765   sourceCallback.NewFrame();
766   application.SendNotification();
767   application.Render();
768
769   // First call into source callback should emit initial number of particles
770   auto emittedParticleCount = sourceCallback.mFuture.get();
771   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
772
773   // Run 3 more frames advancing by 1000ms which should
774   // emit particles based on emission rate
775   AdvanceTimeByMs(1000);
776
777   sourceCallback.NewFrame();
778   application.SendNotification();
779   application.Render();
780
781   AdvanceTimeByMs(1000);
782
783   sourceCallback.NewFrame();
784   application.SendNotification();
785   application.Render();
786
787   AdvanceTimeByMs(1000);
788
789   sourceCallback.NewFrame();
790   application.SendNotification();
791   application.Render();
792
793   END_TEST;
794 }
795
796 int UtcDaliParticleSystemTestMT(void)
797 {
798   TestApplication application;
799
800   // Create actor to be used with emitter
801   Actor actor = Actor::New();
802   application.GetScene().Add(actor);
803   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
804
805   EmitterGroup group;
806
807   auto emitter = CreateEmitter<TestSource, TestModifierMT>(&group);
808
809   emitter.SetEmissionRate(10000);
810   emitter.SetInitialParticleCount(10000);
811   emitter.SetActiveParticlesLimit(20000);
812   emitter.SetParticleCount(300000);
813
814   auto emissionRate = emitter.GetEmissionRate();
815   auto initialCount = emitter.GetInitialParticleCount();
816   auto activeCount  = emitter.GetActiveParticlesLimit();
817
818   DALI_TEST_EQUALS(emissionRate, 10000, TEST_LOCATION);
819   DALI_TEST_EQUALS(initialCount, 10000, TEST_LOCATION);
820   DALI_TEST_EQUALS(activeCount, 20000, TEST_LOCATION);
821
822   emitter.EnableParallelProcessing(true);
823
824   auto mtEnabled = emitter.IsParallelProcessingEnabled();
825   DALI_TEST_EQUALS(mtEnabled, true, TEST_LOCATION);
826
827   // Blending mode with screen
828   auto texture = CreateTexture();
829   group.renderer.SetTexture(texture);
830   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
831
832   // test status again (domain is optional);
833   auto ready = emitter.GetStatus();
834
835   // Emitter should return status incomplete
836   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
837
838   // Attach emitter to actor
839   emitter.AttachTo(actor);
840
841   // Start emitter
842   emitter.Start();
843
844   auto status = emitter.GetStatus();
845   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
846
847   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
848
849   // Run simulation
850   sourceCallback.NewFrame();
851   application.SendNotification();
852   application.Render();
853
854   // First call into source callback should emit initial number of particles
855   auto emittedParticleCount = sourceCallback.mFuture.get();
856   DALI_TEST_EQUALS(emittedParticleCount, 10000, TEST_LOCATION);
857
858   // Run 3 more frames advancing by 1000ms which should
859   // emit particles based on emission rate
860   AdvanceTimeByMs(1000);
861
862   sourceCallback.NewFrame();
863   application.SendNotification();
864   application.Render();
865
866   AdvanceTimeByMs(1000);
867
868   sourceCallback.NewFrame();
869   application.SendNotification();
870   application.Render();
871
872   AdvanceTimeByMs(1000);
873
874   sourceCallback.NewFrame();
875   application.SendNotification();
876   application.Render();
877
878   END_TEST;
879 }
880
881 int UtcDaliParticleSystemTestParticleSource(void)
882 {
883   TestApplication application;
884
885   // Create actor to be used with emitter
886   Actor actor = Actor::New();
887   application.GetScene().Add(actor);
888   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
889
890   EmitterGroup group;
891
892   auto emitter = CreateEmitter<TestSource2, TestModifier>(&group);
893
894   emitter.SetEmissionRate(1000);
895   emitter.SetInitialParticleCount(1000);
896   emitter.SetActiveParticlesLimit(10000);
897
898   auto emissionRate = emitter.GetEmissionRate();
899   auto initialCount = emitter.GetInitialParticleCount();
900   auto activeCount  = emitter.GetActiveParticlesLimit();
901
902   DALI_TEST_EQUALS(emissionRate, 1000, TEST_LOCATION);
903   DALI_TEST_EQUALS(initialCount, 1000, TEST_LOCATION);
904   DALI_TEST_EQUALS(activeCount, 10000, TEST_LOCATION);
905
906   emitter.EnableParallelProcessing(true);
907
908   // Blending mode with screen
909   auto texture = CreateTexture();
910   group.renderer.SetTexture(texture);
911   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
912
913   // test status again (domain is optional);
914   auto ready = emitter.GetStatus();
915
916   // Emitter should return status incomplete
917   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
918
919   // Set initial parameters of system
920   emitter.SetInitialParticleCount(1000);
921   emitter.SetActiveParticlesLimit(5000);
922
923   // Test getters
924   auto initialParticleCount = emitter.GetInitialParticleCount();
925   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
926
927   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
928   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
929
930   // Attach emitter to actor
931   emitter.AttachTo(actor);
932
933   // Start emitter
934   emitter.Start();
935
936   auto status = emitter.GetStatus();
937   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
938
939   auto& sourceCallback = static_cast<TestSource2&>(emitter.GetSource().GetSourceCallback());
940
941   // Run simulation
942   sourceCallback.NewFrame();
943   application.SendNotification();
944   application.Render();
945
946   // First call into source callback should emit initial number of particles
947   auto emittedParticleCount = sourceCallback.mFuture.get();
948   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
949
950   // Run 3 more frames advancing by 1000ms which should
951   // emit particles based on emission rate
952   AdvanceTimeByMs(1000);
953
954   sourceCallback.NewFrame();
955   application.SendNotification();
956   application.Render();
957
958   AdvanceTimeByMs(1000);
959
960   sourceCallback.NewFrame();
961   application.SendNotification();
962   application.Render();
963
964   AdvanceTimeByMs(1000);
965
966   sourceCallback.NewFrame();
967   application.SendNotification();
968   application.Render();
969
970   // Stop the emitter
971   emitter.Stop();
972
973   sourceCallback.NewFrame();
974   application.SendNotification();
975   application.Render();
976
977   END_TEST;
978 }
979
980 int UtcDaliParticleSystemReplaceEmitter(void)
981 {
982   TestApplication application;
983
984   // Create actor to be used with emitter
985   Actor actor = Actor::New();
986   application.GetScene().Add(actor);
987   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
988
989   EmitterGroup group;
990
991   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
992
993   // Blending mode with screen
994   auto texture = CreateTexture();
995   group.renderer.SetTexture(texture);
996   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
997
998   // test status again (domain is optional);
999   auto ready = emitter.GetStatus();
1000
1001   // Emitter should return status incomplete
1002   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
1003
1004   // Set initial parameters of system
1005   emitter.SetInitialParticleCount(1000);
1006   emitter.SetActiveParticlesLimit(5000);
1007
1008   // Test getters
1009   auto initialParticleCount = emitter.GetInitialParticleCount();
1010   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
1011
1012   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
1013   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
1014
1015   // Attach emitter to actor
1016   emitter.AttachTo(actor);
1017
1018   // Start emitter
1019   emitter.Start();
1020
1021   auto status = emitter.GetStatus();
1022   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
1023
1024   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
1025
1026   // Run simulation
1027   sourceCallback.NewFrame();
1028   application.SendNotification();
1029   application.Render();
1030
1031   // First call into source callback should emit initial number of particles
1032   auto emittedParticleCount = sourceCallback.mFuture.get();
1033   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
1034
1035   // Run 3 more frames advancing by 1000ms which should
1036   // emit particles based on emission rate
1037   AdvanceTimeByMs(1000);
1038
1039   sourceCallback.NewFrame();
1040   application.SendNotification();
1041   application.Render();
1042
1043   AdvanceTimeByMs(1000);
1044
1045   sourceCallback.NewFrame();
1046   application.SendNotification();
1047   application.Render();
1048
1049   AdvanceTimeByMs(1000);
1050
1051   sourceCallback.NewFrame();
1052   application.SendNotification();
1053   application.Render();
1054
1055   // replace emitter
1056   auto                  oldEmitter = emitter.GetObjectPtr(); // store old emitter
1057   [[maybe_unused]] auto i          = oldEmitter->ReferenceCount();
1058   // Reset group
1059   group = {};
1060
1061   emitter = CreateEmitter<TestSource, TestModifier>(&group);
1062   DALI_TEST_EQUALS(bool(emitter.GetObjectPtr() != oldEmitter), true, TEST_LOCATION);
1063
1064   END_TEST;
1065 }