Merge changes I89471ca9,I866ffdec into 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-toolkit/public-api/particle-system/particle-emitter.h>
19 #include <dali-toolkit/public-api/particle-system/particle-domain.h>
20 #include <dali-toolkit/public-api/particle-system/particle-modifier.h>
21 #include <dali-toolkit/public-api/particle-system/particle-source.h>
22 #include <dali-toolkit/public-api/particle-system/particle-renderer.h>
23 #include <dali-toolkit/public-api/particle-system/particle-list.h>
24 #include <dali-toolkit/public-api/particle-system/particle.h>
25 #include <dali-test-suite-utils.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 // Create fake time getter
48 namespace Dali::Toolkit::ParticleSystem::Internal
49 {
50 struct ParticleEmitter
51 {
52   [[nodiscard]] std::chrono::milliseconds GetCurrentTimeMillis() const;
53
54   static std::chrono::milliseconds currentTime;
55
56   static void AdvanceTimeByMs( uint32_t ms)
57   {
58     currentTime += std::chrono::milliseconds(ms);
59   }
60 };
61
62 std::chrono::milliseconds ParticleEmitter::currentTime(1u);
63
64 std::chrono::milliseconds ParticleEmitter::GetCurrentTimeMillis() const
65 {
66   [[maybe_unused]] auto value = InvokeNext<std::chrono::milliseconds>(this);
67    return std::chrono::milliseconds(currentTime);
68 }
69 }
70
71 using ParticleEmitterWrapper = Dali::Toolkit::ParticleSystem::Internal::ParticleEmitter;
72
73 Texture CreateTexture()
74 {
75   Texture texture = Texture::New(Dali::TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, 100, 100);
76   uint8_t* data = reinterpret_cast<uint8_t*>(malloc(100*100*4));
77   PixelData pixelData = PixelData::New(data, 100*100*4, 100, 100, Pixel::Format::RGBA8888, PixelData::FREE);
78   texture.Upload(pixelData);
79   return texture;
80 }
81
82
83 /**
84  * Test particle source
85  */
86 class TestSource : public ParticleSourceInterface
87 {
88 public:
89
90   TestSource(ParticleEmitter* emitter)
91   {
92     mEmitter = *emitter;
93   }
94
95   void NewFrame()
96   {
97     mPromise = std::promise<uint32_t>();
98     mFuture = mPromise.get_future();
99   }
100
101   uint32_t Update(ParticleList& outList, uint32_t count) override
102   {
103     mPromise.set_value(count);
104     auto i = count;
105     while(--i)
106     {
107       outList.NewParticle(1.0f);
108     }
109     return count;
110   }
111
112   void Init() override
113   {
114     // calls initialized
115     mInitialized = true;
116   }
117
118   bool mInitialized{false};
119   std::future<uint32_t> mFuture;
120   std::promise<uint32_t> mPromise;
121   ParticleEmitter mEmitter;
122 };
123
124 class TestSource2 : public ParticleSourceInterface
125 {
126 public:
127
128   TestSource2(ParticleEmitter* emitter)
129   {
130     mEmitter = *emitter;
131   }
132
133   void NewFrame()
134   {
135     mPromise = std::promise<uint32_t>();
136     mFuture = mPromise.get_future();
137   }
138
139   uint32_t Update(ParticleList& outList, uint32_t count) override
140   {
141     mPromise.set_value(count);
142
143     while(count--)
144     {
145       auto particle = outList.NewParticle(1.0);
146       if(!particle)
147       {
148         return 0u;
149       }
150
151       [[maybe_unused]] auto& pos = particle.GetByIndex<Vector3>(mStreamBasePos);
152
153       [[maybe_unused]] auto& gpos = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
154       [[maybe_unused]] auto& col = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
155       [[maybe_unused]] auto& vel = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
156       [[maybe_unused]] auto& sca = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
157       //auto& basePos = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
158     }
159
160     return count;
161   }
162
163   void Init() override
164   {
165     // calls initialized
166     mStreamBasePos = mEmitter.GetParticleList().AddLocalStream<Vector3>(Vector3::ZERO);
167     mInitialized = true;
168   }
169
170   bool mInitialized{false};
171   std::future<uint32_t> mFuture;
172   std::promise<uint32_t> mPromise;
173   uint32_t mStreamBasePos{0u};
174   ParticleEmitter mEmitter;
175
176 };
177 /**
178  * Sample of FlameModifier
179  */
180 struct TestModifier : public ParticleModifierInterface
181 {
182   void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
183   {
184
185   }
186 };
187
188 struct TestModifierMT : public ParticleModifierInterface
189 {
190   void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
191   {
192
193   }
194
195   bool IsMultiThreaded() override
196   {
197     return true;
198   }
199 };
200
201 /**
202  * Another modifier to test modifier stack
203  */
204 struct TestModifier2 : public ParticleModifierInterface
205 {
206   void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
207   {
208
209   }
210 };
211
212 struct EmitterGroup
213 {
214   ParticleEmitter emitter;
215   ParticleRenderer renderer;
216   ParticleModifier modifier;
217   ParticleSource source;
218 };
219
220 // Helper function to create emitter (every test will be doing that)
221 template<class SOURCE, class MODIFIER>
222 ParticleEmitter CreateEmitter(EmitterGroup* output = nullptr)
223 {
224   auto emitter = ParticleEmitter::New();
225
226   bool result = (emitter != nullptr);
227   DALI_TEST_EQUALS( result, true, TEST_LOCATION );
228
229   // Create test source
230   auto source = ParticleSource::New<SOURCE>(&emitter);
231
232   {
233     BaseHandle handle(source);
234     auto       newHandle = ParticleSource::DownCast(handle);
235     DALI_TEST_EQUALS(newHandle, source, TEST_LOCATION);
236   }
237
238   // Create test renderer
239   auto renderer = ParticleRenderer::New();
240
241   {
242     BaseHandle handle(renderer);
243     auto       newHandle = ParticleRenderer::DownCast(handle);
244     DALI_TEST_EQUALS(newHandle, renderer, TEST_LOCATION);
245   }
246
247   // Create modifier
248   auto modifier = ParticleModifier::New<MODIFIER>();
249
250   {
251     BaseHandle handle(modifier);
252     auto       newHandle = ParticleModifier::DownCast(handle);
253     DALI_TEST_EQUALS(newHandle, modifier, TEST_LOCATION);
254   }
255
256   auto domain = ParticleDomain::New();
257
258   {
259     BaseHandle handle(domain);
260     auto       newHandle = ParticleDomain::DownCast(handle);
261     DALI_TEST_EQUALS(newHandle, domain, TEST_LOCATION);
262   }
263
264   // Test emitter readiness
265   auto ready = emitter.GetStatus();
266
267   // Emitter should return status incomplete
268   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
269
270   // Attach all components to the emitter
271   emitter.SetSource( source );
272   emitter.SetRenderer( renderer );
273   emitter.AddModifier( modifier );
274   emitter.SetDomain( domain );
275
276   auto domain0 = emitter.GetDomain();
277   auto renderer0 = emitter.GetRenderer();
278
279   DALI_TEST_EQUALS( renderer0, renderer, TEST_LOCATION);
280   DALI_TEST_EQUALS( domain0, domain, TEST_LOCATION);
281
282   if(output)
283   {
284     output->emitter = emitter;
285     output->renderer = renderer;
286     output->modifier = modifier;
287     output->source = source;
288   }
289
290   return emitter;
291 }
292
293 int UtcDaliParticleSystemEmitterNew(void)
294 {
295   // create particle emitter
296   auto emitter = ParticleEmitter::New();
297
298   bool result = (emitter != nullptr);
299   DALI_TEST_EQUALS( result, true, TEST_LOCATION );
300
301   // Create test source
302   auto source = ParticleSource::New<TestSource>(&emitter);
303
304   // Create test renderer
305   auto renderer = ParticleRenderer::New();
306
307   // Create modifier
308   auto modifier = ParticleModifier::New<TestModifier>();
309
310   // Create domain
311   auto domain = ParticleDomain::New();
312
313   // Test emitter readiness
314   auto ready = emitter.GetStatus();
315
316   // Emitter should return status incomplete
317   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
318
319   // Attach all components to the emitter
320   emitter.SetSource( source );
321   emitter.SetRenderer( renderer );
322   emitter.AddModifier( modifier );
323   emitter.SetDomain( domain );
324
325   // test status again (domain is optional);
326   ready = emitter.GetStatus();
327
328   // Emitter should return status incomplete
329   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
330
331   END_TEST;
332 }
333
334 int UtcDaliParticleSystemEmitterModifierStack(void)
335 {
336   // create particle emitter
337   auto emitter = ParticleEmitter::New();
338
339   bool result = (emitter != nullptr);
340   DALI_TEST_EQUALS( result, true, TEST_LOCATION );
341
342   // Create test source
343   auto source = ParticleSource::New<TestSource>(&emitter);
344
345   // Create test renderer
346   auto renderer = ParticleRenderer::New();
347
348   // Create modifier
349   auto modifier0 = ParticleModifier::New<TestModifier>();
350   auto modifier1 = ParticleModifier::New<TestModifier>();
351   auto modifier2 = ParticleModifier::New<TestModifier>();
352
353   // Create domain
354   auto domain = ParticleDomain::New();
355
356   // Test emitter readiness
357   auto ready = emitter.GetStatus();
358
359   // Emitter should return status incomplete
360   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
361
362   // Attach all components to the emitter
363   emitter.SetSource( source );
364   emitter.SetRenderer( renderer );
365   emitter.AddModifier( modifier0 );
366   emitter.AddModifier( modifier1 );
367   emitter.AddModifier( modifier2 );
368
369   emitter.SetDomain( domain );
370
371   // test status again (domain is optional);
372   ready = emitter.GetStatus();
373
374   // Emitter should return status incomplete
375   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
376
377   auto modifier = emitter.GetModifierAt(1);
378   DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
379
380   emitter.RemoveModifierAt(0);
381   modifier = emitter.GetModifierAt(0);
382   DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
383
384   END_TEST;
385 }
386
387 int UtcDaliParticleSystemTest(void)
388 {
389   TestApplication application;
390
391   // Create actor to be used with emitter
392   Actor actor = Actor::New();
393   application.GetScene().Add(actor);
394   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
395
396   auto emitter = CreateEmitter<TestSource, TestModifier>();
397
398   // test status again (domain is optional);
399   auto ready = emitter.GetStatus();
400
401   // Emitter should return status incomplete
402   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
403
404   // Set initial parameters of system
405   emitter.SetInitialParticleCount( 1000 );
406   emitter.SetActiveParticlesLimit( 5000 );
407
408   // Test getters
409   auto initialParticleCount = emitter.GetInitialParticleCount();
410   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
411
412   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
413   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
414
415   // Attach emitter to actor
416   emitter.AttachTo(actor);
417
418   // Start emitter
419   emitter.Start();
420
421   auto status = emitter.GetStatus();
422   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
423
424   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
425
426   // Run simulation
427   sourceCallback.NewFrame();
428   application.SendNotification();
429   application.Render();
430
431   // First call into source callback should emit initial number of particles
432   auto emittedParticleCount = sourceCallback.mFuture.get();
433   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
434
435   // Run 3 more frames advancing by 1000ms which should
436   // emit particles based on emission rate
437   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
438
439   sourceCallback.NewFrame();
440   application.SendNotification();
441   application.Render();
442
443   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
444
445   sourceCallback.NewFrame();
446   application.SendNotification();
447   application.Render();
448
449   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
450
451   sourceCallback.NewFrame();
452   application.SendNotification();
453   application.Render();
454
455   END_TEST;
456 }
457
458 int UtcDaliParticleSystemTestWithTextureScreen(void)
459 {
460   TestApplication application;
461
462   // Create actor to be used with emitter
463   Actor actor = Actor::New();
464   application.GetScene().Add(actor);
465   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
466
467   EmitterGroup group;
468
469   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
470
471   // Blending mode with screen
472   auto texture = CreateTexture();
473   group.renderer.SetTexture( texture );
474   group.renderer.SetBlendingMode( BlendingMode::SCREEN );
475
476   // test status again (domain is optional);
477   auto ready = emitter.GetStatus();
478
479   // Emitter should return status incomplete
480   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
481
482   // Set initial parameters of system
483   emitter.SetInitialParticleCount( 1000 );
484   emitter.SetActiveParticlesLimit( 5000 );
485
486   // Test getters
487   auto initialParticleCount = emitter.GetInitialParticleCount();
488   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
489
490   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
491   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
492
493   // Attach emitter to actor
494   emitter.AttachTo(actor);
495
496   // Start emitter
497   emitter.Start();
498
499   auto status = emitter.GetStatus();
500   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
501
502   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
503
504   // Run simulation
505   sourceCallback.NewFrame();
506   application.SendNotification();
507   application.Render();
508
509   // First call into source callback should emit initial number of particles
510   auto emittedParticleCount = sourceCallback.mFuture.get();
511   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
512
513   // Run 3 more frames advancing by 1000ms which should
514   // emit particles based on emission rate
515   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
516
517   sourceCallback.NewFrame();
518   application.SendNotification();
519   application.Render();
520
521   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
522
523   sourceCallback.NewFrame();
524   application.SendNotification();
525   application.Render();
526
527   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
528
529   sourceCallback.NewFrame();
530   application.SendNotification();
531   application.Render();
532
533   END_TEST;
534 }
535
536 int UtcDaliParticleSystemTestWithTextureAdd(void)
537 {
538   TestApplication application;
539
540   // Create actor to be used with emitter
541   Actor actor = Actor::New();
542   application.GetScene().Add(actor);
543   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
544
545   EmitterGroup group;
546
547   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
548
549   // Blending mode with screen
550   auto texture = CreateTexture();
551   group.renderer.SetTexture( texture );
552   group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
553
554   // test status again (domain is optional);
555   auto ready = emitter.GetStatus();
556
557   // Emitter should return status incomplete
558   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
559
560   // Set initial parameters of system
561   emitter.SetInitialParticleCount( 1000 );
562   emitter.SetActiveParticlesLimit( 5000 );
563
564   // Test getters
565   auto initialParticleCount = emitter.GetInitialParticleCount();
566   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
567
568   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
569   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
570
571   // Attach emitter to actor
572   emitter.AttachTo(actor);
573
574   // Start emitter
575   emitter.Start();
576
577   auto status = emitter.GetStatus();
578   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
579
580   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
581
582   // Run simulation
583   sourceCallback.NewFrame();
584   application.SendNotification();
585   application.Render();
586
587   // First call into source callback should emit initial number of particles
588   auto emittedParticleCount = sourceCallback.mFuture.get();
589   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
590
591   // Run 3 more frames advancing by 1000ms which should
592   // emit particles based on emission rate
593   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
594
595   sourceCallback.NewFrame();
596   application.SendNotification();
597   application.Render();
598
599   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
600
601   sourceCallback.NewFrame();
602   application.SendNotification();
603   application.Render();
604
605   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
606
607   sourceCallback.NewFrame();
608   application.SendNotification();
609   application.Render();
610
611   END_TEST;
612 }
613
614 int UtcDaliParticleSystemTestInitialSetup(void)
615 {
616   TestApplication application;
617
618   // Create actor to be used with emitter
619   Actor actor = Actor::New();
620   application.GetScene().Add(actor);
621   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
622
623   EmitterGroup group;
624
625   auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
626
627   emitter.SetEmissionRate( 1000 );
628   emitter.SetInitialParticleCount( 1000 );
629   emitter.SetActiveParticlesLimit( 10000 );
630
631   auto emissionRate = emitter.GetEmissionRate();
632   auto initialCount = emitter.GetInitialParticleCount();
633   auto activeCount = emitter.GetActiveParticlesLimit();
634
635   DALI_TEST_EQUALS( emissionRate, 1000, TEST_LOCATION);
636   DALI_TEST_EQUALS( initialCount, 1000, TEST_LOCATION);
637   DALI_TEST_EQUALS( activeCount, 10000, TEST_LOCATION);
638
639   // Blending mode with screen
640   auto texture = CreateTexture();
641   group.renderer.SetTexture( texture );
642   group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
643
644   // test status again (domain is optional);
645   auto ready = emitter.GetStatus();
646
647   // Emitter should return status incomplete
648   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
649
650   // Set initial parameters of system
651   emitter.SetInitialParticleCount( 1000 );
652   emitter.SetActiveParticlesLimit( 5000 );
653
654   // Test getters
655   auto initialParticleCount = emitter.GetInitialParticleCount();
656   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
657
658   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
659   DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
660
661   // Attach emitter to actor
662   emitter.AttachTo(actor);
663
664   // Start emitter
665   emitter.Start();
666
667   auto status = emitter.GetStatus();
668   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
669
670   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
671
672   // Run simulation
673   sourceCallback.NewFrame();
674   application.SendNotification();
675   application.Render();
676
677   // First call into source callback should emit initial number of particles
678   auto emittedParticleCount = sourceCallback.mFuture.get();
679   DALI_TEST_EQUALS(emittedParticleCount, 1000, TEST_LOCATION);
680
681   // Run 3 more frames advancing by 1000ms which should
682   // emit particles based on emission rate
683   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
684
685   sourceCallback.NewFrame();
686   application.SendNotification();
687   application.Render();
688
689   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
690
691   sourceCallback.NewFrame();
692   application.SendNotification();
693   application.Render();
694
695   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
696
697   sourceCallback.NewFrame();
698   application.SendNotification();
699   application.Render();
700
701   END_TEST;
702 }
703
704 int UtcDaliParticleSystemTestMT(void)
705 {
706   TestApplication application;
707
708   // Create actor to be used with emitter
709   Actor actor = Actor::New();
710   application.GetScene().Add(actor);
711   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
712
713   EmitterGroup group;
714
715   auto emitter = CreateEmitter<TestSource, TestModifierMT>(&group);
716
717   emitter.SetEmissionRate( 10000 );
718   emitter.SetInitialParticleCount( 10000 );
719   emitter.SetActiveParticlesLimit( 20000 );
720   emitter.SetParticleCount( 300000 );
721
722   auto emissionRate = emitter.GetEmissionRate();
723   auto initialCount = emitter.GetInitialParticleCount();
724   auto activeCount = emitter.GetActiveParticlesLimit();
725
726   DALI_TEST_EQUALS( emissionRate, 10000, TEST_LOCATION);
727   DALI_TEST_EQUALS( initialCount, 10000, TEST_LOCATION);
728   DALI_TEST_EQUALS( activeCount, 20000, TEST_LOCATION);
729
730   emitter.EnableParallelProcessing(true);
731
732   auto mtEnabled = emitter.IsParallelProcessingEnabled();
733   DALI_TEST_EQUALS(mtEnabled, true, TEST_LOCATION);
734
735   // Blending mode with screen
736   auto texture = CreateTexture();
737   group.renderer.SetTexture( texture );
738   group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
739   
740   // test status again (domain is optional);
741   auto ready = emitter.GetStatus();
742
743   // Emitter should return status incomplete
744   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
745
746   // Attach emitter to actor
747   emitter.AttachTo(actor);
748
749   // Start emitter
750   emitter.Start();
751
752   auto status = emitter.GetStatus();
753   DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
754
755   auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
756
757   // Run simulation
758   sourceCallback.NewFrame();
759   application.SendNotification();
760   application.Render();
761
762   // First call into source callback should emit initial number of particles
763   auto emittedParticleCount = sourceCallback.mFuture.get();
764   DALI_TEST_EQUALS(emittedParticleCount, 10000, TEST_LOCATION);
765
766   // Run 3 more frames advancing by 1000ms which should
767   // emit particles based on emission rate
768   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
769
770   sourceCallback.NewFrame();
771   application.SendNotification();
772   application.Render();
773
774   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
775
776   sourceCallback.NewFrame();
777   application.SendNotification();
778   application.Render();
779
780   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
781
782   sourceCallback.NewFrame();
783   application.SendNotification();
784   application.Render();
785
786   END_TEST;
787 }
788
789 int UtcDaliParticleSystemTestParticleSource(void)
790 {
791   TestApplication application;
792
793   // Create actor to be used with emitter
794   Actor actor = Actor::New();
795   application.GetScene().Add(actor);
796   actor.SetProperty(Actor::Property::SIZE, Vector2(100, 100));
797
798   EmitterGroup group;
799
800   auto emitter = CreateEmitter<TestSource2, TestModifier>(&group);
801
802   emitter.SetEmissionRate( 1000 );
803   emitter.SetInitialParticleCount( 1000 );
804   emitter.SetActiveParticlesLimit( 10000 );
805
806   auto emissionRate = emitter.GetEmissionRate();
807   auto initialCount = emitter.GetInitialParticleCount();
808   auto activeCount = emitter.GetActiveParticlesLimit();
809
810   DALI_TEST_EQUALS( emissionRate, 1000, TEST_LOCATION);
811   DALI_TEST_EQUALS( initialCount, 1000, TEST_LOCATION);
812   DALI_TEST_EQUALS( activeCount, 10000, TEST_LOCATION);
813
814   emitter.EnableParallelProcessing(true);
815
816   // Blending mode with screen
817   auto texture = CreateTexture();
818   group.renderer.SetTexture( texture );
819   group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
820
821   // test status again (domain is optional);
822   auto ready = emitter.GetStatus();
823
824   // Emitter should return status incomplete
825   DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
826
827   // Set initial parameters of system
828   emitter.SetInitialParticleCount( 1000 );
829   emitter.SetActiveParticlesLimit( 5000 );
830
831   // Test getters
832   auto initialParticleCount = emitter.GetInitialParticleCount();
833   auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
834
835   DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
836   DALI_TEST_EQUALS(activeParticlesLimit, 5000, 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 = static_cast<TestSource2&>(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, 1000, TEST_LOCATION);
857
858   // Run 3 more frames advancing by 1000ms which should
859   // emit particles based on emission rate
860   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
861
862   sourceCallback.NewFrame();
863   application.SendNotification();
864   application.Render();
865
866   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
867
868   sourceCallback.NewFrame();
869   application.SendNotification();
870   application.Render();
871
872   ParticleEmitterWrapper::AdvanceTimeByMs(1000);
873
874   sourceCallback.NewFrame();
875   application.SendNotification();
876   application.Render();
877
878   // Stop the emitter
879   emitter.Stop();
880
881   sourceCallback.NewFrame();
882   application.SendNotification();
883   application.Render();
884
885   END_TEST;
886 }