2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
32 using namespace Dali::Toolkit::ParticleSystem;
35 * Helper function to invoke next function in the call chain
37 template<class R, class T, class... Args>
38 R InvokeNext(T* pObj, Args... args)
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...);
47 // Create fake time getter
48 namespace Dali::Toolkit::ParticleSystem::Internal
50 struct ParticleEmitter
52 [[nodiscard]] std::chrono::milliseconds GetCurrentTimeMillis() const;
54 static std::chrono::milliseconds currentTime;
56 static void AdvanceTimeByMs( uint32_t ms)
58 currentTime += std::chrono::milliseconds(ms);
62 std::chrono::milliseconds ParticleEmitter::currentTime(1u);
64 std::chrono::milliseconds ParticleEmitter::GetCurrentTimeMillis() const
66 [[maybe_unused]] auto value = InvokeNext<std::chrono::milliseconds>(this);
67 return std::chrono::milliseconds(currentTime);
71 using ParticleEmitterWrapper = Dali::Toolkit::ParticleSystem::Internal::ParticleEmitter;
73 Texture CreateTexture()
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);
84 * Test particle source
86 class TestSource : public ParticleSourceInterface
90 TestSource(ParticleEmitter* emitter)
97 mPromise = std::promise<uint32_t>();
98 mFuture = mPromise.get_future();
101 uint32_t Update(ParticleList& outList, uint32_t count) override
103 mPromise.set_value(count);
107 outList.NewParticle(1.0f);
118 bool mInitialized{false};
119 std::future<uint32_t> mFuture;
120 std::promise<uint32_t> mPromise;
121 ParticleEmitter mEmitter;
124 class TestSource2 : public ParticleSourceInterface
128 TestSource2(ParticleEmitter* emitter)
135 mPromise = std::promise<uint32_t>();
136 mFuture = mPromise.get_future();
139 uint32_t Update(ParticleList& outList, uint32_t count) override
141 mPromise.set_value(count);
145 auto particle = outList.NewParticle(1.0);
151 [[maybe_unused]] auto& pos = particle.GetByIndex<Vector3>(mStreamBasePos);
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);
166 mStreamBasePos = mEmitter.GetParticleList().AddLocalStream<Vector3>(Vector3::ZERO);
170 bool mInitialized{false};
171 std::future<uint32_t> mFuture;
172 std::promise<uint32_t> mPromise;
173 uint32_t mStreamBasePos{0u};
174 ParticleEmitter mEmitter;
178 * Sample of FlameModifier
180 struct TestModifier : public ParticleModifierInterface
182 void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
188 struct TestModifierMT : public ParticleModifierInterface
190 void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
195 bool IsMultiThreaded() override
202 * Another modifier to test modifier stack
204 struct TestModifier2 : public ParticleModifierInterface
206 void Update(ParticleList& particleList, uint32_t firstParticleIndex, uint32_t particleCount) override
214 ParticleEmitter emitter;
215 ParticleRenderer renderer;
216 ParticleModifier modifier;
217 ParticleSource source;
220 // Helper function to create emitter (every test will be doing that)
221 template<class SOURCE, class MODIFIER>
222 ParticleEmitter CreateEmitter(EmitterGroup* output = nullptr)
224 auto emitter = ParticleEmitter::New();
226 bool result = (emitter != nullptr);
227 DALI_TEST_EQUALS( result, true, TEST_LOCATION );
229 // Create test source
230 auto source = ParticleSource::New<SOURCE>(&emitter);
233 BaseHandle handle(source);
234 auto newHandle = ParticleSource::DownCast(handle);
235 DALI_TEST_EQUALS(newHandle, source, TEST_LOCATION);
238 // Create test renderer
239 auto renderer = ParticleRenderer::New();
242 BaseHandle handle(renderer);
243 auto newHandle = ParticleRenderer::DownCast(handle);
244 DALI_TEST_EQUALS(newHandle, renderer, TEST_LOCATION);
248 auto modifier = ParticleModifier::New<MODIFIER>();
251 BaseHandle handle(modifier);
252 auto newHandle = ParticleModifier::DownCast(handle);
253 DALI_TEST_EQUALS(newHandle, modifier, TEST_LOCATION);
256 auto domain = ParticleDomain::New();
259 BaseHandle handle(domain);
260 auto newHandle = ParticleDomain::DownCast(handle);
261 DALI_TEST_EQUALS(newHandle, domain, TEST_LOCATION);
264 // Test emitter readiness
265 auto ready = emitter.GetStatus();
267 // Emitter should return status incomplete
268 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
270 // Attach all components to the emitter
271 emitter.SetSource( source );
272 emitter.SetRenderer( renderer );
273 emitter.AddModifier( modifier );
274 emitter.SetDomain( domain );
276 auto domain0 = emitter.GetDomain();
277 auto renderer0 = emitter.GetRenderer();
279 DALI_TEST_EQUALS( renderer0, renderer, TEST_LOCATION);
280 DALI_TEST_EQUALS( domain0, domain, TEST_LOCATION);
284 output->emitter = emitter;
285 output->renderer = renderer;
286 output->modifier = modifier;
287 output->source = source;
293 int UtcDaliParticleSystemEmitterNew(void)
295 // create particle emitter
296 auto emitter = ParticleEmitter::New();
298 bool result = (emitter != nullptr);
299 DALI_TEST_EQUALS( result, true, TEST_LOCATION );
301 // Create test source
302 auto source = ParticleSource::New<TestSource>(&emitter);
304 // Create test renderer
305 auto renderer = ParticleRenderer::New();
308 auto modifier = ParticleModifier::New<TestModifier>();
311 auto domain = ParticleDomain::New();
313 // Test emitter readiness
314 auto ready = emitter.GetStatus();
316 // Emitter should return status incomplete
317 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
319 // Attach all components to the emitter
320 emitter.SetSource( source );
321 emitter.SetRenderer( renderer );
322 emitter.AddModifier( modifier );
323 emitter.SetDomain( domain );
325 // test status again (domain is optional);
326 ready = emitter.GetStatus();
328 // Emitter should return status incomplete
329 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
334 int UtcDaliParticleSystemEmitterModifierStack(void)
336 // create particle emitter
337 auto emitter = ParticleEmitter::New();
339 bool result = (emitter != nullptr);
340 DALI_TEST_EQUALS( result, true, TEST_LOCATION );
342 // Create test source
343 auto source = ParticleSource::New<TestSource>(&emitter);
345 // Create test renderer
346 auto renderer = ParticleRenderer::New();
349 auto modifier0 = ParticleModifier::New<TestModifier>();
350 auto modifier1 = ParticleModifier::New<TestModifier>();
351 auto modifier2 = ParticleModifier::New<TestModifier>();
354 auto domain = ParticleDomain::New();
356 // Test emitter readiness
357 auto ready = emitter.GetStatus();
359 // Emitter should return status incomplete
360 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::INCOMPLETE, TEST_LOCATION);
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 );
369 emitter.SetDomain( domain );
371 // test status again (domain is optional);
372 ready = emitter.GetStatus();
374 // Emitter should return status incomplete
375 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
377 auto modifier = emitter.GetModifierAt(1);
378 DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
380 emitter.RemoveModifierAt(0);
381 modifier = emitter.GetModifierAt(0);
382 DALI_TEST_EQUALS(modifier, modifier1, TEST_LOCATION);
387 int UtcDaliParticleSystemTest(void)
389 TestApplication application;
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));
396 auto emitter = CreateEmitter<TestSource, TestModifier>();
398 // test status again (domain is optional);
399 auto ready = emitter.GetStatus();
401 // Emitter should return status incomplete
402 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
404 // Set initial parameters of system
405 emitter.SetInitialParticleCount( 1000 );
406 emitter.SetActiveParticlesLimit( 5000 );
409 auto initialParticleCount = emitter.GetInitialParticleCount();
410 auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
412 DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
413 DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
415 // Attach emitter to actor
416 emitter.AttachTo(actor);
421 auto status = emitter.GetStatus();
422 DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
424 auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
427 sourceCallback.NewFrame();
428 application.SendNotification();
429 application.Render();
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);
435 // Run 3 more frames advancing by 1000ms which should
436 // emit particles based on emission rate
437 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
439 sourceCallback.NewFrame();
440 application.SendNotification();
441 application.Render();
443 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
445 sourceCallback.NewFrame();
446 application.SendNotification();
447 application.Render();
449 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
451 sourceCallback.NewFrame();
452 application.SendNotification();
453 application.Render();
458 int UtcDaliParticleSystemTestWithTextureScreen(void)
460 TestApplication application;
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));
469 auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
471 // Blending mode with screen
472 auto texture = CreateTexture();
473 group.renderer.SetTexture( texture );
474 group.renderer.SetBlendingMode( BlendingMode::SCREEN );
476 // test status again (domain is optional);
477 auto ready = emitter.GetStatus();
479 // Emitter should return status incomplete
480 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
482 // Set initial parameters of system
483 emitter.SetInitialParticleCount( 1000 );
484 emitter.SetActiveParticlesLimit( 5000 );
487 auto initialParticleCount = emitter.GetInitialParticleCount();
488 auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
490 DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
491 DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
493 // Attach emitter to actor
494 emitter.AttachTo(actor);
499 auto status = emitter.GetStatus();
500 DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
502 auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
505 sourceCallback.NewFrame();
506 application.SendNotification();
507 application.Render();
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);
513 // Run 3 more frames advancing by 1000ms which should
514 // emit particles based on emission rate
515 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
517 sourceCallback.NewFrame();
518 application.SendNotification();
519 application.Render();
521 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
523 sourceCallback.NewFrame();
524 application.SendNotification();
525 application.Render();
527 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
529 sourceCallback.NewFrame();
530 application.SendNotification();
531 application.Render();
536 int UtcDaliParticleSystemTestWithTextureAdd(void)
538 TestApplication application;
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));
547 auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
549 // Blending mode with screen
550 auto texture = CreateTexture();
551 group.renderer.SetTexture( texture );
552 group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
554 // test status again (domain is optional);
555 auto ready = emitter.GetStatus();
557 // Emitter should return status incomplete
558 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
560 // Set initial parameters of system
561 emitter.SetInitialParticleCount( 1000 );
562 emitter.SetActiveParticlesLimit( 5000 );
565 auto initialParticleCount = emitter.GetInitialParticleCount();
566 auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
568 DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
569 DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
571 // Attach emitter to actor
572 emitter.AttachTo(actor);
577 auto status = emitter.GetStatus();
578 DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
580 auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
583 sourceCallback.NewFrame();
584 application.SendNotification();
585 application.Render();
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);
591 // Run 3 more frames advancing by 1000ms which should
592 // emit particles based on emission rate
593 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
595 sourceCallback.NewFrame();
596 application.SendNotification();
597 application.Render();
599 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
601 sourceCallback.NewFrame();
602 application.SendNotification();
603 application.Render();
605 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
607 sourceCallback.NewFrame();
608 application.SendNotification();
609 application.Render();
614 int UtcDaliParticleSystemTestInitialSetup(void)
616 TestApplication application;
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));
625 auto emitter = CreateEmitter<TestSource, TestModifier>(&group);
627 emitter.SetEmissionRate( 1000 );
628 emitter.SetInitialParticleCount( 1000 );
629 emitter.SetActiveParticlesLimit( 10000 );
631 auto emissionRate = emitter.GetEmissionRate();
632 auto initialCount = emitter.GetInitialParticleCount();
633 auto activeCount = emitter.GetActiveParticlesLimit();
635 DALI_TEST_EQUALS( emissionRate, 1000, TEST_LOCATION);
636 DALI_TEST_EQUALS( initialCount, 1000, TEST_LOCATION);
637 DALI_TEST_EQUALS( activeCount, 10000, TEST_LOCATION);
639 // Blending mode with screen
640 auto texture = CreateTexture();
641 group.renderer.SetTexture( texture );
642 group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
644 // test status again (domain is optional);
645 auto ready = emitter.GetStatus();
647 // Emitter should return status incomplete
648 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
650 // Set initial parameters of system
651 emitter.SetInitialParticleCount( 1000 );
652 emitter.SetActiveParticlesLimit( 5000 );
655 auto initialParticleCount = emitter.GetInitialParticleCount();
656 auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
658 DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
659 DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
661 // Attach emitter to actor
662 emitter.AttachTo(actor);
667 auto status = emitter.GetStatus();
668 DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
670 auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
673 sourceCallback.NewFrame();
674 application.SendNotification();
675 application.Render();
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);
681 // Run 3 more frames advancing by 1000ms which should
682 // emit particles based on emission rate
683 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
685 sourceCallback.NewFrame();
686 application.SendNotification();
687 application.Render();
689 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
691 sourceCallback.NewFrame();
692 application.SendNotification();
693 application.Render();
695 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
697 sourceCallback.NewFrame();
698 application.SendNotification();
699 application.Render();
704 int UtcDaliParticleSystemTestMT(void)
706 TestApplication application;
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));
715 auto emitter = CreateEmitter<TestSource, TestModifierMT>(&group);
717 emitter.SetEmissionRate( 10000 );
718 emitter.SetInitialParticleCount( 10000 );
719 emitter.SetActiveParticlesLimit( 20000 );
720 emitter.SetParticleCount( 300000 );
722 auto emissionRate = emitter.GetEmissionRate();
723 auto initialCount = emitter.GetInitialParticleCount();
724 auto activeCount = emitter.GetActiveParticlesLimit();
726 DALI_TEST_EQUALS( emissionRate, 10000, TEST_LOCATION);
727 DALI_TEST_EQUALS( initialCount, 10000, TEST_LOCATION);
728 DALI_TEST_EQUALS( activeCount, 20000, TEST_LOCATION);
730 emitter.EnableParallelProcessing(true);
732 auto mtEnabled = emitter.IsParallelProcessingEnabled();
733 DALI_TEST_EQUALS(mtEnabled, true, TEST_LOCATION);
735 // Blending mode with screen
736 auto texture = CreateTexture();
737 group.renderer.SetTexture( texture );
738 group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
740 // test status again (domain is optional);
741 auto ready = emitter.GetStatus();
743 // Emitter should return status incomplete
744 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
746 // Attach emitter to actor
747 emitter.AttachTo(actor);
752 auto status = emitter.GetStatus();
753 DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
755 auto& sourceCallback = dynamic_cast<TestSource&>(emitter.GetSource().GetSourceCallback());
758 sourceCallback.NewFrame();
759 application.SendNotification();
760 application.Render();
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);
766 // Run 3 more frames advancing by 1000ms which should
767 // emit particles based on emission rate
768 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
770 sourceCallback.NewFrame();
771 application.SendNotification();
772 application.Render();
774 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
776 sourceCallback.NewFrame();
777 application.SendNotification();
778 application.Render();
780 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
782 sourceCallback.NewFrame();
783 application.SendNotification();
784 application.Render();
789 int UtcDaliParticleSystemTestParticleSource(void)
791 TestApplication application;
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));
800 auto emitter = CreateEmitter<TestSource2, TestModifier>(&group);
802 emitter.SetEmissionRate( 1000 );
803 emitter.SetInitialParticleCount( 1000 );
804 emitter.SetActiveParticlesLimit( 10000 );
806 auto emissionRate = emitter.GetEmissionRate();
807 auto initialCount = emitter.GetInitialParticleCount();
808 auto activeCount = emitter.GetActiveParticlesLimit();
810 DALI_TEST_EQUALS( emissionRate, 1000, TEST_LOCATION);
811 DALI_TEST_EQUALS( initialCount, 1000, TEST_LOCATION);
812 DALI_TEST_EQUALS( activeCount, 10000, TEST_LOCATION);
814 emitter.EnableParallelProcessing(true);
816 // Blending mode with screen
817 auto texture = CreateTexture();
818 group.renderer.SetTexture( texture );
819 group.renderer.SetBlendingMode( BlendingMode::DEFAULT );
821 // test status again (domain is optional);
822 auto ready = emitter.GetStatus();
824 // Emitter should return status incomplete
825 DALI_TEST_EQUALS(ready, ParticleEmitter::Status::READY, TEST_LOCATION);
827 // Set initial parameters of system
828 emitter.SetInitialParticleCount( 1000 );
829 emitter.SetActiveParticlesLimit( 5000 );
832 auto initialParticleCount = emitter.GetInitialParticleCount();
833 auto activeParticlesLimit = emitter.GetActiveParticlesLimit();
835 DALI_TEST_EQUALS(initialParticleCount, 1000, TEST_LOCATION);
836 DALI_TEST_EQUALS(activeParticlesLimit, 5000, TEST_LOCATION);
838 // Attach emitter to actor
839 emitter.AttachTo(actor);
844 auto status = emitter.GetStatus();
845 DALI_TEST_EQUALS(status, ParticleEmitter::Status::STARTED, TEST_LOCATION);
847 auto& sourceCallback = static_cast<TestSource2&>(emitter.GetSource().GetSourceCallback());
850 sourceCallback.NewFrame();
851 application.SendNotification();
852 application.Render();
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);
858 // Run 3 more frames advancing by 1000ms which should
859 // emit particles based on emission rate
860 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
862 sourceCallback.NewFrame();
863 application.SendNotification();
864 application.Render();
866 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
868 sourceCallback.NewFrame();
869 application.SendNotification();
870 application.Render();
872 ParticleEmitterWrapper::AdvanceTimeByMs(1000);
874 sourceCallback.NewFrame();
875 application.SendNotification();
876 application.Render();
881 sourceCallback.NewFrame();
882 application.SendNotification();
883 application.Render();