Test harness sync
[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 UtcDaliParticleSystemEmitterModifierStack(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 modifier0 = ParticleModifier::New<TestModifier>();
339   auto modifier1 = ParticleModifier::New<TestModifier>();
340   auto modifier2 = ParticleModifier::New<TestModifier>();
341
342   // Create domain
343   auto domain = ParticleDomain::New();
344
345   // Test emitter readiness
346   auto ready = emitter.GetStatus();
347
348   // Emitter should return status incomplete
349   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
350
351   // Attach all components to the emitter
352   emitter.SetSource(source);
353   emitter.SetRenderer(renderer);
354   emitter.AddModifier(modifier0);
355   emitter.AddModifier(modifier1);
356   emitter.AddModifier(modifier2);
357
358   emitter.SetDomain(domain);
359
360   // test status again (domain is optional);
361   ready = emitter.GetStatus();
362
363   // Emitter should return status incomplete
364   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
365
366   auto modifier = emitter.GetModifierAt(1);
367   DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
368
369   emitter.RemoveModifierAt(0);
370   modifier = emitter.GetModifierAt(0);
371   DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
372
373   END_TEST;
374 }
375
376 int UtcDaliParticleSystemTest(void)
377 {
378   TestApplication application;
379
380   // Create actor to be used with emitter
381   Actor actor = Actor::New();
382   application.GetScene().Add(actor);
383   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
384
385   auto emitter = CreateEmitter<TestSource, TestModifier>();
386
387   // test status again (domain is optional);
388   auto ready = emitter.GetStatus();
389
390   // Emitter should return status incomplete
391   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
392
393   // Set initial parameters of system
394   emitter.SetInitialParticleCount(1000);
395   emitter.SetActiveParticlesLimit(5000);
396
397   // Test getters
398   auto initialParticleCount = emitter.GetInitialParticleCount();
399   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
400
401   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
402   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
403
404   // Attach emitter to actor
405   emitter.AttachTo(actor);
406
407   // Start emitter
408   emitter.Start();
409
410   auto status = emitter.GetStatus();
411   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
412
413   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
414
415   // Run simulation
416   sourceCallback.NewFrame();
417   application.SendNotification();
418   application.Render();
419
420   // First call into source callback should emit initial number of particles
421   auto emittedParticleCount = sourceCallback.mFuture.get();
422   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
423
424   // Run 3 more frames advancing by 1000ms which should
425   // emit particles based on emission rate
426   AdvanceTimeByMs(1000);
427
428   sourceCallback.NewFrame();
429   application.SendNotification();
430   application.Render();
431
432   AdvanceTimeByMs(1000);
433
434   sourceCallback.NewFrame();
435   application.SendNotification();
436   application.Render();
437
438   AdvanceTimeByMs(1000);
439
440   sourceCallback.NewFrame();
441   application.SendNotification();
442   application.Render();
443
444   END_TEST;
445 }
446
447 int UtcDaliParticleSystemTestWithTextureScreen(void)
448 {
449   TestApplication application;
450
451   // Create actor to be used with emitter
452   Actor actor = Actor::New();
453   application.GetScene().Add(actor);
454   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
455
456   EmitterGroup group;
457
458   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
459
460   // Blending mode with screen
461   auto texture = CreateTexture();
462   group.renderer.SetTexture(texture);
463   group.renderer.SetBlendingMode(BlendingMode::SCREEN);
464
465   // test status again (domain is optional);
466   auto ready = emitter.GetStatus();
467
468   // Emitter should return status incomplete
469   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
470
471   // Set initial parameters of system
472   emitter.SetInitialParticleCount(1000);
473   emitter.SetActiveParticlesLimit(5000);
474
475   // Test getters
476   auto initialParticleCount = emitter.GetInitialParticleCount();
477   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
478
479   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
480   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
481
482   // Attach emitter to actor
483   emitter.AttachTo(actor);
484
485   // Start emitter
486   emitter.Start();
487
488   auto status = emitter.GetStatus();
489   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
490
491   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
492
493   // Run simulation
494   sourceCallback.NewFrame();
495   application.SendNotification();
496   application.Render();
497
498   // First call into source callback should emit initial number of particles
499   auto emittedParticleCount = sourceCallback.mFuture.get();
500   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
501
502   // Run 3 more frames advancing by 1000ms which should
503   // emit particles based on emission rate
504   AdvanceTimeByMs(1000);
505
506   sourceCallback.NewFrame();
507   application.SendNotification();
508   application.Render();
509
510   AdvanceTimeByMs(1000);
511
512   sourceCallback.NewFrame();
513   application.SendNotification();
514   application.Render();
515
516   AdvanceTimeByMs(1000);
517
518   sourceCallback.NewFrame();
519   application.SendNotification();
520   application.Render();
521
522   END_TEST;
523 }
524
525 int UtcDaliParticleSystemTestWithTextureAdd(void)
526 {
527   TestApplication application;
528
529   // Create actor to be used with emitter
530   Actor actor = Actor::New();
531   application.GetScene().Add(actor);
532   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
533
534   EmitterGroup group;
535
536   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
537
538   // Blending mode with screen
539   auto texture = CreateTexture();
540   group.renderer.SetTexture(texture);
541   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
542
543   // test status again (domain is optional);
544   auto ready = emitter.GetStatus();
545
546   // Emitter should return status incomplete
547   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
548
549   // Set initial parameters of system
550   emitter.SetInitialParticleCount(1000);
551   emitter.SetActiveParticlesLimit(5000);
552
553   // Test getters
554   auto initialParticleCount = emitter.GetInitialParticleCount();
555   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
556
557   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
558   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
559
560   // Attach emitter to actor
561   emitter.AttachTo(actor);
562
563   // Start emitter
564   emitter.Start();
565
566   auto status = emitter.GetStatus();
567   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
568
569   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
570
571   // Run simulation
572   sourceCallback.NewFrame();
573   application.SendNotification();
574   application.Render();
575
576   // First call into source callback should emit initial number of particles
577   auto emittedParticleCount = sourceCallback.mFuture.get();
578   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
579
580   // Run 3 more frames advancing by 1000ms which should
581   // emit particles based on emission rate
582   AdvanceTimeByMs(1000);
583
584   sourceCallback.NewFrame();
585   application.SendNotification();
586   application.Render();
587
588   AdvanceTimeByMs(1000);
589
590   sourceCallback.NewFrame();
591   application.SendNotification();
592   application.Render();
593
594   AdvanceTimeByMs(1000);
595
596   sourceCallback.NewFrame();
597   application.SendNotification();
598   application.Render();
599
600   END_TEST;
601 }
602
603 int UtcDaliParticleSystemTestInitialSetup(void)
604 {
605   TestApplication application;
606
607   // Create actor to be used with emitter
608   Actor actor = Actor::New();
609   application.GetScene().Add(actor);
610   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
611
612   EmitterGroup group;
613
614   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
615
616   emitter.SetEmissionRate(1000);
617   emitter.SetInitialParticleCount(1000);
618   emitter.SetActiveParticlesLimit(10000);
619
620   auto emissionRate = emitter.GetEmissionRate();
621   auto initialCount = emitter.GetInitialParticleCount();
622   auto activeCount  = emitter.GetActiveParticlesLimit();
623
624   DALI_TEST_EQUALS(emissionRate, 1000, TEST_LOCATION);
625   DALI_TEST_EQUALS(initialCount, 1000, TEST_LOCATION);
626   DALI_TEST_EQUALS(activeCount, 10000, TEST_LOCATION);
627
628   // Blending mode with screen
629   auto texture = CreateTexture();
630   group.renderer.SetTexture(texture);
631   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
632
633   // test status again (domain is optional);
634   auto ready = emitter.GetStatus();
635
636   // Emitter should return status incomplete
637   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
638
639   // Set initial parameters of system
640   emitter.SetInitialParticleCount(1000);
641   emitter.SetActiveParticlesLimit(5000);
642
643   // Test getters
644   auto initialParticleCount = emitter.GetInitialParticleCount();
645   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
646
647   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
648   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
649
650   // Attach emitter to actor
651   emitter.AttachTo(actor);
652
653   // Start emitter
654   emitter.Start();
655
656   auto status = emitter.GetStatus();
657   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
658
659   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
660
661   // Run simulation
662   sourceCallback.NewFrame();
663   application.SendNotification();
664   application.Render();
665
666   // First call into source callback should emit initial number of particles
667   auto emittedParticleCount = sourceCallback.mFuture.get();
668   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
669
670   // Run 3 more frames advancing by 1000ms which should
671   // emit particles based on emission rate
672   AdvanceTimeByMs(1000);
673
674   sourceCallback.NewFrame();
675   application.SendNotification();
676   application.Render();
677
678   AdvanceTimeByMs(1000);
679
680   sourceCallback.NewFrame();
681   application.SendNotification();
682   application.Render();
683
684   AdvanceTimeByMs(1000);
685
686   sourceCallback.NewFrame();
687   application.SendNotification();
688   application.Render();
689
690   END_TEST;
691 }
692
693 int UtcDaliParticleSystemTestMT(void)
694 {
695   TestApplication application;
696
697   // Create actor to be used with emitter
698   Actor actor = Actor::New();
699   application.GetScene().Add(actor);
700   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
701
702   EmitterGroup group;
703
704   auto emitter = CreateEmitter<TestSource, TestModifierMT>(&group);
705
706   emitter.SetEmissionRate(10000);
707   emitter.SetInitialParticleCount(10000);
708   emitter.SetActiveParticlesLimit(20000);
709   emitter.SetParticleCount(300000);
710
711   auto emissionRate = emitter.GetEmissionRate();
712   auto initialCount = emitter.GetInitialParticleCount();
713   auto activeCount  = emitter.GetActiveParticlesLimit();
714
715   DALI_TEST_EQUALS(emissionRate, 10000, TEST_LOCATION);
716   DALI_TEST_EQUALS(initialCount, 10000, TEST_LOCATION);
717   DALI_TEST_EQUALS(activeCount, 20000, TEST_LOCATION);
718
719   emitter.EnableParallelProcessing(true);
720
721   auto mtEnabled = emitter.IsParallelProcessingEnabled();
722   DALI_TEST_EQUALS(mtEnabled, true, TEST_LOCATION);
723
724   // Blending mode with screen
725   auto texture = CreateTexture();
726   group.renderer.SetTexture(texture);
727   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
728
729   // test status again (domain is optional);
730   auto ready = emitter.GetStatus();
731
732   // Emitter should return status incomplete
733   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
734
735   // Attach emitter to actor
736   emitter.AttachTo(actor);
737
738   // Start emitter
739   emitter.Start();
740
741   auto status = emitter.GetStatus();
742   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
743
744   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
745
746   // Run simulation
747   sourceCallback.NewFrame();
748   application.SendNotification();
749   application.Render();
750
751   // First call into source callback should emit initial number of particles
752   auto emittedParticleCount = sourceCallback.mFuture.get();
753   DALI_TEST_EQUALS(emittedParticleCount, 10000, TEST_LOCATION);
754
755   // Run 3 more frames advancing by 1000ms which should
756   // emit particles based on emission rate
757   AdvanceTimeByMs(1000);
758
759   sourceCallback.NewFrame();
760   application.SendNotification();
761   application.Render();
762
763   AdvanceTimeByMs(1000);
764
765   sourceCallback.NewFrame();
766   application.SendNotification();
767   application.Render();
768
769   AdvanceTimeByMs(1000);
770
771   sourceCallback.NewFrame();
772   application.SendNotification();
773   application.Render();
774
775   END_TEST;
776 }
777
778 int UtcDaliParticleSystemTestParticleSource(void)
779 {
780   TestApplication application;
781
782   // Create actor to be used with emitter
783   Actor actor = Actor::New();
784   application.GetScene().Add(actor);
785   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
786
787   EmitterGroup group;
788
789   auto emitter = CreateEmitter<TestSource2, TestModifier>(&group);
790
791   emitter.SetEmissionRate(1000);
792   emitter.SetInitialParticleCount(1000);
793   emitter.SetActiveParticlesLimit(10000);
794
795   auto emissionRate = emitter.GetEmissionRate();
796   auto initialCount = emitter.GetInitialParticleCount();
797   auto activeCount  = emitter.GetActiveParticlesLimit();
798
799   DALI_TEST_EQUALS(emissionRate, 1000, TEST_LOCATION);
800   DALI_TEST_EQUALS(initialCount, 1000, TEST_LOCATION);
801   DALI_TEST_EQUALS(activeCount, 10000, TEST_LOCATION);
802
803   emitter.EnableParallelProcessing(true);
804
805   // Blending mode with screen
806   auto texture = CreateTexture();
807   group.renderer.SetTexture(texture);
808   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
809
810   // test status again (domain is optional);
811   auto ready = emitter.GetStatus();
812
813   // Emitter should return status incomplete
814   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
815
816   // Set initial parameters of system
817   emitter.SetInitialParticleCount(1000);
818   emitter.SetActiveParticlesLimit(5000);
819
820   // Test getters
821   auto initialParticleCount = emitter.GetInitialParticleCount();
822   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
823
824   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
825   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
826
827   // Attach emitter to actor
828   emitter.AttachTo(actor);
829
830   // Start emitter
831   emitter.Start();
832
833   auto status = emitter.GetStatus();
834   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
835
836   auto& sourceCallback = static_cast<TestSource2&>(emitter.GetSource().GetSourceCallback());
837
838   // Run simulation
839   sourceCallback.NewFrame();
840   application.SendNotification();
841   application.Render();
842
843   // First call into source callback should emit initial number of particles
844   auto emittedParticleCount = sourceCallback.mFuture.get();
845   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
846
847   // Run 3 more frames advancing by 1000ms which should
848   // emit particles based on emission rate
849   AdvanceTimeByMs(1000);
850
851   sourceCallback.NewFrame();
852   application.SendNotification();
853   application.Render();
854
855   AdvanceTimeByMs(1000);
856
857   sourceCallback.NewFrame();
858   application.SendNotification();
859   application.Render();
860
861   AdvanceTimeByMs(1000);
862
863   sourceCallback.NewFrame();
864   application.SendNotification();
865   application.Render();
866
867   // Stop the emitter
868   emitter.Stop();
869
870   sourceCallback.NewFrame();
871   application.SendNotification();
872   application.Render();
873
874   END_TEST;
875 }
876
877 int UtcDaliParticleSystemReplaceEmitter(void)
878 {
879   TestApplication application;
880
881   // Create actor to be used with emitter
882   Actor actor = Actor::New();
883   application.GetScene().Add(actor);
884   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
885
886   EmitterGroup group;
887
888   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
889
890   // Blending mode with screen
891   auto texture = CreateTexture();
892   group.renderer.SetTexture(texture);
893   group.renderer.SetBlendingMode(BlendingMode::DEFAULT);
894
895   // test status again (domain is optional);
896   auto ready = emitter.GetStatus();
897
898   // Emitter should return status incomplete
899   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
900
901   // Set initial parameters of system
902   emitter.SetInitialParticleCount(1000);
903   emitter.SetActiveParticlesLimit(5000);
904
905   // Test getters
906   auto initialParticleCount = emitter.GetInitialParticleCount();
907   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
908
909   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
910   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
911
912   // Attach emitter to actor
913   emitter.AttachTo(actor);
914
915   // Start emitter
916   emitter.Start();
917
918   auto status = emitter.GetStatus();
919   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
920
921   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
922
923   // Run simulation
924   sourceCallback.NewFrame();
925   application.SendNotification();
926   application.Render();
927
928   // First call into source callback should emit initial number of particles
929   auto emittedParticleCount = sourceCallback.mFuture.get();
930   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
931
932   // Run 3 more frames advancing by 1000ms which should
933   // emit particles based on emission rate
934   AdvanceTimeByMs(1000);
935
936   sourceCallback.NewFrame();
937   application.SendNotification();
938   application.Render();
939
940   AdvanceTimeByMs(1000);
941
942   sourceCallback.NewFrame();
943   application.SendNotification();
944   application.Render();
945
946   AdvanceTimeByMs(1000);
947
948   sourceCallback.NewFrame();
949   application.SendNotification();
950   application.Render();
951
952   // replace emitter
953   auto                  oldEmitter = emitter.GetObjectPtr(); // store old emitter
954   [[maybe_unused]] auto i          = oldEmitter->ReferenceCount();
955   // Reset group
956   group = {};
957
958   emitter = CreateEmitter<TestSource, TestModifier>(&group);
959   DALI_TEST_EQUALS(bool(emitter.GetObjectPtr() != oldEmitter), true, TEST_LOCATION);
960
961   END_TEST;
962 }