summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/tizen/examples/CMakeLists.txt2
-rw-r--r--demo/dali-demo.cpp3
-rw-r--r--examples-reel/dali-examples-reel.cpp3
-rw-r--r--examples/particle-system/effects/fire-ring-effect-modifier.cpp102
-rw-r--r--examples/particle-system/effects/fire-ring-effect-modifier.h88
-rw-r--r--examples/particle-system/effects/fire-ring-effect-source.cpp87
-rw-r--r--examples/particle-system/effects/fire-ring-effect-source.h55
-rw-r--r--examples/particle-system/effects/image-effect-modifier.cpp77
-rw-r--r--examples/particle-system/effects/image-effect-modifier.h53
-rw-r--r--examples/particle-system/effects/image-effect-source.cpp119
-rw-r--r--examples/particle-system/effects/image-effect-source.h62
-rw-r--r--examples/particle-system/effects/particle-effect.cpp106
-rw-r--r--examples/particle-system/effects/particle-effect.h65
-rw-r--r--examples/particle-system/effects/sparkles-effect-modifier.cpp89
-rw-r--r--examples/particle-system/effects/sparkles-effect-modifier.h54
-rw-r--r--examples/particle-system/effects/sparkles-effect-source.cpp91
-rw-r--r--examples/particle-system/effects/sparkles-effect-source.h56
-rw-r--r--examples/particle-system/particle-system-example.cpp217
-rw-r--r--resources/images/blue-part2.pngbin0 -> 28050 bytes
-rw-r--r--resources/images/particle-image-source.jpgbin0 -> 18414 bytes
-rw-r--r--resources/images/sparkle-part1.pngbin0 -> 7763 bytes
-rwxr-xr-xresources/po/en_GB.po3
-rwxr-xr-xresources/po/en_US.po3
-rw-r--r--shared/dali-demo-strings.h4
24 files changed, 1335 insertions, 4 deletions
diff --git a/build/tizen/examples/CMakeLists.txt b/build/tizen/examples/CMakeLists.txt
index ad3d815e..05ebbdff 100644
--- a/build/tizen/examples/CMakeLists.txt
+++ b/build/tizen/examples/CMakeLists.txt
@@ -27,7 +27,7 @@ ENDIF()
FUNCTION(INSTALL_EXAMPLES EXAMPLE)
SET(PARENT_CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../")
- FILE(GLOB SRCS "${EXAMPLES_SRC_DIR}/${EXAMPLE}/*.cpp")
+ FILE(GLOB_RECURSE SRCS "${EXAMPLES_SRC_DIR}/${EXAMPLE}/*.cpp")
SET(SRCS ${SRCS} "${ROOT_SRC_DIR}/shared/resources-location.cpp")
IF(SHARED)
ADD_LIBRARY(${EXAMPLE}.example SHARED ${SRCS})
diff --git a/demo/dali-demo.cpp b/demo/dali-demo.cpp
index 60f9653a..9baad32b 100644
--- a/demo/dali-demo.cpp
+++ b/demo/dali-demo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,6 +53,7 @@ int DALI_EXPORT_API main(int argc, char** argv)
demo.AddExample(Example("motion-blur.example", DALI_DEMO_STR_TITLE_MOTION_BLUR));
demo.AddExample(Example("page-turn-view.example", DALI_DEMO_STR_TITLE_PAGE_TURN));
demo.AddExample(Example("particles.example", DALI_DEMO_STR_TITLE_PARTICLES));
+ demo.AddExample(Example("particle-system.example", DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM));
demo.AddExample(Example("reflection-demo.example", DALI_DEMO_STR_TITLE_REFLECTION));
demo.AddExample(Example("refraction-effect.example", DALI_DEMO_STR_TITLE_REFRACTION));
demo.AddExample(Example("renderer-stencil.example", DALI_DEMO_STR_TITLE_RENDERER_STENCIL));
diff --git a/examples-reel/dali-examples-reel.cpp b/examples-reel/dali-examples-reel.cpp
index e86f4594..90ac6db4 100644
--- a/examples-reel/dali-examples-reel.cpp
+++ b/examples-reel/dali-examples-reel.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,6 +78,7 @@ int DALI_EXPORT_API main(int argc, char** argv)
demo.AddExample(Example("mesh-morph.example", DALI_DEMO_STR_TITLE_MESH_MORPH));
demo.AddExample(Example("motion-stretch.example", DALI_DEMO_STR_TITLE_MOTION_STRETCH));
demo.AddExample(Example("native-image-source.example", DALI_DEMO_STR_TITLE_NATIVE_IMAGE_SOURCE));
+ demo.AddExample(Example("particle-system.example", DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM));
demo.AddExample(Example("popup.example", DALI_DEMO_STR_TITLE_POPUP));
demo.AddExample(Example("pivot.example", DALI_DEMO_STR_TITLE_PIVOT));
demo.AddExample(Example("primitive-shapes.example", DALI_DEMO_STR_TITLE_PRIMITIVE_SHAPES));
diff --git a/examples/particle-system/effects/fire-ring-effect-modifier.cpp b/examples/particle-system/effects/fire-ring-effect-modifier.cpp
new file mode 100644
index 00000000..56f7e5b2
--- /dev/null
+++ b/examples/particle-system/effects/fire-ring-effect-modifier.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "fire-ring-effect-modifier.h"
+#include "fire-ring-effect-source.h"
+
+namespace Dali::ParticleEffect
+{
+FireModifier::FireModifier(ParticleEmitter& emitter)
+: mEmitter(emitter)
+{
+ // initialize gradient with flame colors
+ mFireGradient.PushColor(Vector4(1.0f, 1.0f, 1.0f, 1.0f), 1.0f - 1.0f);
+ mFireGradient.PushColor(Vector4(0.975, 0.955, 0.476, 1.0f), 1.0f - 0.947f);
+ mFireGradient.PushColor(Vector4(0.999, 0.550, 0.194, 1.0f), 1.0f - 0.800f);
+ mFireGradient.PushColor(Vector4(0.861, 0.277, 0.094, 1.0f), 1.0f - 0.670f);
+ mFireGradient.PushColor(Vector4(0.367, 0.0, 0.0, 1.0f), 1.0f - 0.456f);
+ mFireGradient.PushColor(Vector4(0.3, 0.3, 0.3, 1.0f), 1.0f - 0.400f);
+ mFireGradient.PushColor(Vector4(0.3, 0.2, 0.2, 1.0f), 1.0f - 0.200f);
+ mFireGradient.PushColor(Vector4(0.2, 0.1, 0.1, 1.0f), 1.0f - 0.150f);
+ mFireGradient.PushColor(Vector4(0.1, 0.0, 0.0, 1.0f), 1.0f- 0.100f);
+ mFireGradient.PushColor(Vector4(0.0, 0.0, 0.0, 0.5f), 1.0f-0.050f);
+ mFireGradient.PushColor(Vector4(0.0, 0.0, 0.0, 0.2f), 1.0f);
+}
+
+bool FireModifier::IsMultiThreaded()
+{
+ return false;
+}
+
+void FireModifier::Update(ParticleList& particleList, uint32_t first, uint32_t count)
+{
+ // If no acive particles return
+ if(!particleList.GetActiveParticleCount())
+ {
+ return;
+ }
+
+ mAngle = ((mAngle + 2) % 360);
+
+ // Retrieve the Source and get the stream
+ if(!mStreamBasePos)
+ {
+ mStreamBasePos = static_cast<FireSource*>(&mEmitter.GetSource().GetSourceCallback())->mStreamBasePos;
+ }
+
+ // Missing stream, return!
+ if(!mStreamBasePos)
+ {
+ return;
+ }
+
+ auto& activeParticles = particleList.GetActiveParticles();
+
+ auto it = activeParticles.begin();
+ std::advance(it, first);
+
+ int i = 0;
+ for(; count; ++it, count--)
+ {
+ i += 1;
+
+ // Acquire stream data
+ auto& particle = *it;
+ auto& position = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
+ auto& velocity = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
+ auto& color = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
+ auto& baseLifetime = particle.Get<float>(ParticleStream::LIFETIME_BASE_STREAM_BIT);
+ auto& scale = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
+
+ // Get base positions
+ auto& basePos = particle.GetByIndex<Vector3>(mStreamBasePos);
+
+ float lifetime = particle.Get<float>(ParticleStream::LIFETIME_STREAM_BIT);
+ position.y += -fabs(velocity.y);
+ position.x = basePos.x + 5.0f * sin((((mAngle + i)%360)*M_PI)/180.f );
+
+ velocity *= 0.990f;
+ auto newColor = mFireGradient.GetColorAt((baseLifetime - lifetime) / baseLifetime);
+ float normalizedTime = (lifetime / baseLifetime);
+ newColor.a = normalizedTime * normalizedTime;
+
+ scale = Vector3(64.0f*(normalizedTime * normalizedTime * normalizedTime * normalizedTime), 64.0f*(normalizedTime * normalizedTime * normalizedTime * normalizedTime), 1.0);
+
+ color = newColor;
+ }
+}
+} \ No newline at end of file
diff --git a/examples/particle-system/effects/fire-ring-effect-modifier.h b/examples/particle-system/effects/fire-ring-effect-modifier.h
new file mode 100644
index 00000000..3f9f6ea4
--- /dev/null
+++ b/examples/particle-system/effects/fire-ring-effect-modifier.h
@@ -0,0 +1,88 @@
+#ifndef DALI_PROJECT_FIRE_RING_EFFECT_MODIFIER_H
+#define DALI_PROJECT_FIRE_RING_EFFECT_MODIFIER_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <ctime>
+
+namespace Dali::ParticleEffect
+{
+using namespace Dali::Toolkit::ParticleSystem;
+
+class FireModifier : public ParticleModifierInterface
+{
+public:
+
+ struct ColorGradient
+ {
+ std::vector<Vector4> colors;
+ std::vector<float> position;
+
+ void PushColor(const Vector4& color, float pos)
+ {
+ colors.emplace_back(color);
+ position.emplace_back(pos);
+ }
+
+ Vector4 GetColorAt(float pos)
+ {
+ if(pos >= 1.0f)
+ {
+ return colors.back();
+ }
+ else if(pos <= 0.0f)
+ {
+ return colors[0];
+ }
+ for(auto i = 0u; i < position.size() - 1; ++i)
+ {
+ if(pos >= position[i] && pos < position[i + 1])
+ {
+ auto colorDiff = colors[i + 1] - colors[i];
+ return colors[i] + (colorDiff * ((pos - position[i]) / (position[i + 1] - position[i])));
+ }
+ }
+ return colors[0];
+ }
+ };
+
+
+ explicit FireModifier(ParticleEmitter& emitter);
+
+ bool IsMultiThreaded() override;
+
+ void Update(ParticleList& particleList, uint32_t first, uint32_t count) override;
+
+ ColorGradient mFireGradient;
+ ParticleEmitter mEmitter;
+ uint32_t mStreamBasePos{0u};
+ uint32_t mAngle{0u};
+};
+
+
+
+}
+
+#endif // DALI_PROJECT_FIRE_RING_EFFECT_MODIFIER_H
diff --git a/examples/particle-system/effects/fire-ring-effect-source.cpp b/examples/particle-system/effects/fire-ring-effect-source.cpp
new file mode 100644
index 00000000..0ff0652a
--- /dev/null
+++ b/examples/particle-system/effects/fire-ring-effect-source.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "fire-ring-effect-source.h"
+#include <random>
+
+namespace Dali::ParticleEffect
+{
+static float LIFETIME = 5.0f;
+FireSource::FireSource(ParticleEmitter& emitter)
+: mEmitter(emitter)
+{
+ std::time_t result = std::time(nullptr);
+ srand(result);
+ mRadius = Vector2::ONE;
+}
+
+FireSource::FireSource(ParticleEmitter& emitter, Dali::Vector2 ringRadius) :
+mEmitter(emitter)
+{
+ std::time_t result = std::time(nullptr);
+ srand(result);
+ mRadius = ringRadius;
+
+}
+
+void FireSource::Init()
+{
+ mStreamBasePos = mEmitter.GetParticleList().AddLocalStream<Vector3>(Vector3::ZERO);
+}
+
+uint32_t FireSource::Update(ParticleList& particleList, uint32_t count)
+{
+ while(count--)
+ {
+ auto particle = particleList.NewParticle(LIFETIME * (float(std::rand() % 1000)/1000.0f) + 1.0f );
+ if(!particle)
+ {
+ return 0u;
+ }
+
+ auto& basePosition = particle.GetByIndex<Vector3>(mStreamBasePos);
+
+ auto& position = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
+ auto& color = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
+ auto& velocity = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
+ auto& scale = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
+ UpdateParticle(position, basePosition, color, velocity, scale);
+ }
+
+ return 0;
+}
+
+void FireSource::UpdateParticle(Vector3& position, Vector3& basePosition, Vector4& color, Vector3& velocity, Vector3& scale)
+{
+ float posRadians = ((rand() % 360) * M_PI) / 180.0f;
+
+ basePosition.x = position.x = mRadius.x * sin(posRadians);
+ basePosition.y = position.y = mRadius.y * cos(posRadians);
+ color = Dali::Color::WHITE; // white color when emitted
+
+ // angle of motion
+ float radians = ((rand() % 360) * M_PI) / 180.0f;
+ float speed = ((rand() % 5) + 5);
+ velocity.x = sin(radians) * speed;
+ velocity.y = cos(radians) * speed;
+
+ // Random initial scale
+ float currentScale = float(rand() % 32) + 32;
+ scale = Vector3(currentScale, currentScale, 1);
+}
+
+} // namespace Dali::ParticleEffect \ No newline at end of file
diff --git a/examples/particle-system/effects/fire-ring-effect-source.h b/examples/particle-system/effects/fire-ring-effect-source.h
new file mode 100644
index 00000000..28f78efa
--- /dev/null
+++ b/examples/particle-system/effects/fire-ring-effect-source.h
@@ -0,0 +1,55 @@
+#ifndef DALI_FIRE_RING_EFFECT_SOURCE_H
+#define DALI_FIRE_RING_EFFECT_SOURCE_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle.h>
+#include <ctime>
+
+namespace Dali::ParticleEffect
+{
+using namespace Dali::Toolkit::ParticleSystem;
+
+class FireSource : public Toolkit::ParticleSystem::ParticleSourceInterface
+{
+public:
+
+ explicit FireSource(ParticleEmitter& emitter);
+
+ explicit FireSource(ParticleEmitter& emitter, Dali::Vector2 ringRadius);
+
+ uint32_t Update(ParticleList& particleList, uint32_t count) override;
+
+ void Init() override;
+
+ void UpdateParticle(Vector3& position, Vector3& basePosition, Vector4& color, Vector3& velocity, Vector3& scale);
+
+ ParticleEmitter mEmitter;
+
+ Dali::Vector2 mRadius;
+
+ uint32_t mStreamBasePos{0u};
+
+};
+
+}
+#endif // DALI_FIRE_RING_EFFECT_SOURCE_H
diff --git a/examples/particle-system/effects/image-effect-modifier.cpp b/examples/particle-system/effects/image-effect-modifier.cpp
new file mode 100644
index 00000000..395040c7
--- /dev/null
+++ b/examples/particle-system/effects/image-effect-modifier.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "image-effect-modifier.h"
+#include "image-effect-source.h"
+namespace Dali::ParticleEffect
+{
+
+#define RAD(x) (float(x)*M_PI/180.0f)
+
+ImageExplodeEffectModifier::ImageExplodeEffectModifier(ParticleEmitter& emitter)
+: mEmitter(emitter)
+{
+
+}
+
+bool ImageExplodeEffectModifier::IsMultiThreaded()
+{
+ return false;
+}
+
+void ImageExplodeEffectModifier::Update(ParticleList& particleList, uint32_t first, uint32_t count)
+{
+ // If no acive particles return
+ if(!particleList.GetActiveParticleCount())
+ {
+ return;
+ }
+
+ // Retrieve the Source and get the stream
+ if(!mStreamBasePos)
+ {
+ mStreamBasePos = static_cast<ImageExplodeEffectSource*>(&mEmitter.GetSource().GetSourceCallback())->mStreamBasePos;
+ }
+
+ // Missing stream, return!
+ if(!mStreamBasePos)
+ {
+ return;
+ }
+
+ auto& activeParticles = particleList.GetActiveParticles();
+
+ auto it = activeParticles.begin();
+ std::advance(it, first);
+
+ mAngle += 5.0f;
+
+ for(; count; ++it, count--)
+ {
+ // Acquire stream data
+ auto& particle = *it;
+ auto& position = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
+ auto& color = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
+
+ // Get base positions
+ auto& basePos = particle.GetByIndex<Vector3>(mStreamBasePos);
+ position.z = 200.f * sin(RAD(mAngle+basePos.x));
+ color.a = position.z < 0.0f ? 1.0f : 1.0f - position.z/500.0f;
+ position.z = 500 + position.z;
+ }
+}
+} \ No newline at end of file
diff --git a/examples/particle-system/effects/image-effect-modifier.h b/examples/particle-system/effects/image-effect-modifier.h
new file mode 100644
index 00000000..8a0781e4
--- /dev/null
+++ b/examples/particle-system/effects/image-effect-modifier.h
@@ -0,0 +1,53 @@
+#ifndef DALI_IMAGE_EFFECT_MODIFIER_H
+#define DALI_IMAGE_EFFECT_MODIFIER_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle.h>
+#include <ctime>
+
+namespace Dali::ParticleEffect
+{
+using namespace Dali::Toolkit::ParticleSystem;
+
+class ImageExplodeEffectModifier : public ParticleModifierInterface
+{
+public:
+
+ explicit ImageExplodeEffectModifier(ParticleEmitter& emitter);
+
+ bool IsMultiThreaded() override;
+
+ void Update(ParticleList& particleList, uint32_t first, uint32_t count) override;
+
+ ParticleEmitter mEmitter;
+ uint32_t mStreamBasePos{0u};
+ float mAngle{0.0f};
+
+};
+
+
+
+}
+
+#endif // DALI_IMAGE_EFFECT_MODIFIER_H
diff --git a/examples/particle-system/effects/image-effect-source.cpp b/examples/particle-system/effects/image-effect-source.cpp
new file mode 100644
index 00000000..2e52a1e2
--- /dev/null
+++ b/examples/particle-system/effects/image-effect-source.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "image-effect-source.h"
+#include <dali/devel-api/rendering/texture-devel.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <random>
+
+namespace Dali::ParticleEffect
+{
+namespace
+{
+Vector4 GetColorAt(uint32_t x, uint32_t y, Devel::PixelBuffer& buffer)
+{
+ if(buffer.GetPixelFormat() == Pixel::Format::RGBA8888)
+ {
+ const auto ptr = reinterpret_cast<uint32_t*>(buffer.GetBuffer());
+ auto value = *(ptr + x + (y * buffer.GetHeight()));
+ auto rgba = reinterpret_cast<uint8_t*>(&value);
+ return Vector4(float(rgba[0]) / 255.0f, float(rgba[1]) / 255.0f, float(rgba[2]) / 255.0f, 1.0f);
+ }
+ else
+ {
+ auto rgba = reinterpret_cast<uint8_t*>(buffer.GetBuffer() + (y*buffer.GetWidth()*3) + (x*3));
+ return Vector4(float(rgba[0]) / 255.0f, float(rgba[1]) / 255.0f, float(rgba[2]) / 255.0f, 1.0f);
+ }
+}
+}
+
+static float LIFETIME = 50000.0f; // we need infinite lifetime?
+ImageExplodeEffectSource::ImageExplodeEffectSource(ParticleEmitter& emitter)
+: mEmitter(emitter)
+{
+}
+
+ImageExplodeEffectSource::ImageExplodeEffectSource(ParticleEmitter& emitter, const std::string& imageFileName, uint32_t width, uint32_t height) :
+mEmitter(emitter)
+{
+
+ // Create texture
+ std::string filePath(DEMO_IMAGE_DIR);
+ filePath += imageFileName;
+ ImageDimensions dimensions(width, height);
+ // Pixel buffer will be used as a source of pixels (populating colors of particles based on image pixels)
+ Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile(filePath, dimensions, FittingMode::SHRINK_TO_FIT, SamplingMode::DEFAULT, false);
+ mImageWidth = pixelBuffer.GetWidth();
+ mImageHeight = pixelBuffer.GetHeight();
+ mPixelBuffer = pixelBuffer;
+}
+
+void ImageExplodeEffectSource::Init()
+{
+ mStreamBasePos = mEmitter.GetParticleList().AddLocalStream<Vector3>(Vector3::ZERO);
+}
+
+uint32_t ImageExplodeEffectSource::Update(ParticleList& particleList, uint32_t count)
+{
+ if(!mShouldEmit)
+ {
+ return 0;
+ }
+
+ if(mPixelBuffer.GetPixelFormat() != Dali::Pixel::RGBA8888 &&
+ mPixelBuffer.GetPixelFormat() != Dali::Pixel::RGB888)
+ {
+ return 0;
+ }
+
+ auto i = 0u;
+ float particleScale = 4.0f;
+ float pixelSize = 2.0f;
+
+ uint32_t halfWidth = (mImageWidth/2) * particleScale;
+ uint32_t halfHeight = (mImageHeight/2) * particleScale;
+
+ for(auto y = 0u ; y < mImageHeight; ++y)
+ {
+ for(auto x = 0u; x < mImageWidth; ++x)
+ {
+ if(i < particleList.GetCapacity())
+ {
+ // Ignore count, populating all pixels instantly (emitter must account for all the points)
+ auto particle = particleList.NewParticle(LIFETIME);
+
+ auto& basePosition = particle.GetByIndex<Vector3>(mStreamBasePos);
+ auto& position = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
+ auto& color = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
+ auto& velocity = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
+ auto& scale = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
+ color = GetColorAt(x, y, mPixelBuffer);
+ // Set basePosition
+ position = basePosition = Vector3(x* particleScale -halfWidth, y* particleScale -halfHeight, 0);
+ scale = Vector3(pixelSize, pixelSize, 1);
+ velocity = Vector3::ZERO;
+ }
+ ++i;
+ }
+ }
+
+ mShouldEmit = false;
+ return mImageWidth * mImageHeight;
+}
+
+
+} // namespace Dali::ParticleEffect \ No newline at end of file
diff --git a/examples/particle-system/effects/image-effect-source.h b/examples/particle-system/effects/image-effect-source.h
new file mode 100644
index 00000000..49d84c91
--- /dev/null
+++ b/examples/particle-system/effects/image-effect-source.h
@@ -0,0 +1,62 @@
+#ifndef DALI_IMAGE_EFFECT_SOURCE_H
+#define DALI_IMAGE_EFFECT_SOURCE_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <ctime>
+
+namespace Dali::ParticleEffect
+{
+using namespace Dali::Toolkit::ParticleSystem;
+
+/**
+ * Image source will use 2D image to populate points for the emitter
+ * This particular implementation populates points only once.
+ */
+class ImageExplodeEffectSource : public Toolkit::ParticleSystem::ParticleSourceInterface
+{
+public:
+
+ explicit ImageExplodeEffectSource(ParticleEmitter& emitter);
+
+ explicit ImageExplodeEffectSource(ParticleEmitter& emitter, const std::string& imageFileName, uint32_t width, uint32_t height);
+
+ uint32_t Update(ParticleList& particleList, uint32_t count) override;
+
+ void Init() override;
+
+ ParticleEmitter mEmitter;
+
+ uint32_t mImageWidth{0u};
+ uint32_t mImageHeight{0u};
+
+ uint32_t mStreamBasePos{0u};
+
+ Devel::PixelBuffer mPixelBuffer;
+
+ bool mShouldEmit {true};
+};
+
+}
+#endif // DALI_IMAGE_EFFECT_SOURCE_H
diff --git a/examples/particle-system/effects/particle-effect.cpp b/examples/particle-system/effects/particle-effect.cpp
new file mode 100644
index 00000000..e4f2c302
--- /dev/null
+++ b/examples/particle-system/effects/particle-effect.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "particle-effect.h"
+#include "fire-ring-effect-source.h"
+#include "sparkles-effect-source.h"
+#include "image-effect-source.h"
+#include "fire-ring-effect-modifier.h"
+#include "sparkles-effect-modifier.h"
+#include "image-effect-modifier.h"
+
+#include <dali-toolkit/public-api/particle-system/particle-domain.h>
+#include <dali-toolkit/public-api/particle-system/particle-renderer.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <functional>
+
+#ifndef DEMO_IMAGE_DIR
+#define DEMO_IMAGE_DIR ""
+#endif
+
+namespace Dali::ParticleEffect
+{
+using ParticleEmitter = Dali::Toolkit::ParticleSystem::ParticleEmitter;
+using ParticleSource = Dali::Toolkit::ParticleSystem::ParticleSource;
+using ParticleModifier = Dali::Toolkit::ParticleSystem::ParticleModifier;
+
+struct FunctorReturn
+{
+ ParticleEmitter emitter;
+ ParticleSource source;
+ ParticleModifier modifier;
+};
+
+static std::vector<FunctorReturn(*)(const ParticleEffectParams&)> gEffectInitializers =
+{
+ [](const ParticleEffectParams& params){
+ ParticleEmitter emitter = ParticleEmitter::New();
+ return FunctorReturn{emitter, ParticleSource::New<FireSource>(emitter, params.sourceSize), ParticleModifier::New<FireModifier>(emitter) };
+ },
+ [](const ParticleEffectParams& params){
+ ParticleEmitter emitter = ParticleEmitter::New();
+ return FunctorReturn{emitter, ParticleSource::New<SparklesSource>(emitter), ParticleModifier::New<SparklesModifier>(emitter) };
+ },
+ [](const ParticleEffectParams& params){
+ ParticleEmitter emitter = ParticleEmitter::New();
+ return FunctorReturn{emitter, ParticleSource::New<ImageExplodeEffectSource>(emitter,
+ params.strImageSourceName,
+ uint32_t(params.sourceSize.width),
+ uint32_t(params.sourceSize.height)
+ ), ParticleModifier::New<ImageExplodeEffectModifier>(emitter) };
+ },
+};
+
+ParticleEffect::ParticleEffect() = default;
+
+ParticleEffect::~ParticleEffect() = default;
+
+Dali::Toolkit::ParticleSystem::ParticleEmitter ParticleEffect::CreateEffectEmitter( EffectType effectType, Actor parentActor, const ParticleEffectParams& params )
+{
+ auto retval = gEffectInitializers[int(effectType)](params);
+ auto emitter = retval.emitter;
+
+ ParticleRenderer renderer = ParticleRenderer::New();
+
+ if(!params.strTexture.empty())
+ {
+ // Create texture
+ std::string filename(DEMO_IMAGE_DIR);
+ filename += params.strTexture;
+ Dali::PixelData pixelData = Dali::Toolkit::SyncImageLoader::Load(filename);
+ auto texture = Texture::New(Dali::TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+ texture.Upload(pixelData);
+ renderer.SetTexture(texture);
+ }
+
+ emitter.AttachTo(std::move(parentActor));
+ emitter.SetEmissionRate( params.emissionRate ); // 20 particles emitted per second
+ emitter.SetParticleCount( params.particleCount );
+ emitter.SetSource( retval.source );
+ emitter.SetDomain( ParticleDomain::New() );
+ emitter.AddModifier(retval.modifier);
+ emitter.SetRenderer( renderer );
+ renderer.SetBlendingMode(Dali::Toolkit::ParticleSystem::BlendingMode::SCREEN);
+ emitter.SetInitialParticleCount( params.initialParticleCount );
+
+ return emitter;
+}
+
+
+}
+
diff --git a/examples/particle-system/effects/particle-effect.h b/examples/particle-system/effects/particle-effect.h
new file mode 100644
index 00000000..a1277ef2
--- /dev/null
+++ b/examples/particle-system/effects/particle-effect.h
@@ -0,0 +1,65 @@
+#ifndef DALI_PARTICLE_EFFECT_H
+#define DALI_PARTICLE_EFFECT_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <memory>
+
+namespace Dali::ParticleEffect
+{
+
+using EffectIndex = uint32_t;
+
+enum class EffectType
+{
+ FIRE_RING,
+ SPARKLES,
+ IMAGE_EXPLOSION
+};
+
+struct ParticleEffectParams
+{
+ uint32_t emissionRate;
+ uint32_t particleCount;
+ uint32_t initialParticleCount;
+ Vector2 sourceSize;
+ std::string strTexture;
+ std::string strImageSourceName;
+};
+
+/**
+ * Simple manager to spawn and control partcile emitters
+ */
+class ParticleEffect
+{
+public:
+
+ ParticleEffect();
+
+ ~ParticleEffect();
+
+ Dali::Toolkit::ParticleSystem::ParticleEmitter CreateEffectEmitter( EffectType effectType, Actor parentActor, const ParticleEffectParams& params );
+
+private:
+
+
+};
+}
+
+#endif // DALI_PARTICLE_MANAGER_H \ No newline at end of file
diff --git a/examples/particle-system/effects/sparkles-effect-modifier.cpp b/examples/particle-system/effects/sparkles-effect-modifier.cpp
new file mode 100644
index 00000000..dda93da9
--- /dev/null
+++ b/examples/particle-system/effects/sparkles-effect-modifier.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "sparkles-effect-modifier.h"
+#include "sparkles-effect-source.h"
+
+namespace Dali::ParticleEffect
+{
+static float LIFETIME = 3.0f;
+SparklesModifier::SparklesModifier(ParticleEmitter& emitter)
+: mEmitter(emitter)
+{
+}
+
+bool SparklesModifier::IsMultiThreaded()
+{
+ return true;
+}
+
+void SparklesModifier::Update(ParticleList& particleList, uint32_t first, uint32_t count)
+{
+ // If no acive particles return
+ if(!particleList.GetActiveParticleCount())
+ {
+ return;
+ }
+
+ mAngle = ((mAngle + 2) % 360);
+
+ // Retrieve the Source and get the stream
+ if(!mStreamBasePos)
+ {
+ mStreamBasePos = static_cast<SparklesSource*>(&mEmitter.GetSource().GetSourceCallback())->mStreamBasePos;
+ }
+ if(!mStreamBaseAngle)
+ {
+ mStreamBaseAngle = static_cast<SparklesSource*>(&mEmitter.GetSource().GetSourceCallback())->mStreamBaseAngle;
+ }
+
+ // Missing stream, return!
+ if(!mStreamBasePos)
+ {
+ return;
+ }
+
+ auto& activeParticles = particleList.GetActiveParticles();
+
+ auto it = activeParticles.begin();
+ std::advance(it, first);
+
+ for(; count; ++it, count--)
+ {
+ // Acquire stream data
+ auto& particle = *it;
+ auto& position = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
+ auto& velocity = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
+ auto& color = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
+ auto& scale = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
+
+ // Get base positions
+ [[maybe_unused]] auto& basePos = particle.GetByIndex<Vector3>(mStreamBasePos);
+
+ auto angle = particle.GetByIndex<float>(mStreamBaseAngle);
+ auto radians = ((angle * M_PI)/180.f);
+ float lifetime = particle.Get<float>(ParticleStream::LIFETIME_STREAM_BIT);
+ position.y += velocity.y *sin(radians);
+ position.x += velocity.x * cos(radians);
+
+ velocity *= 0.990f;
+ float normalizedTime = (lifetime / LIFETIME);
+ color.a = normalizedTime;
+ scale = Vector3(64.0f*(normalizedTime * normalizedTime * normalizedTime * normalizedTime), 64.0f*(normalizedTime * normalizedTime * normalizedTime * normalizedTime), 1.0);
+ }
+}
+} \ No newline at end of file
diff --git a/examples/particle-system/effects/sparkles-effect-modifier.h b/examples/particle-system/effects/sparkles-effect-modifier.h
new file mode 100644
index 00000000..1c64bd63
--- /dev/null
+++ b/examples/particle-system/effects/sparkles-effect-modifier.h
@@ -0,0 +1,54 @@
+#ifndef DALI_PARTICLES_SPARKLES_EFFECT_MODIFIER_H
+#define DALI_PARTICLES_SPARKLES_EFFECT_MODIFIER_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <ctime>
+
+namespace Dali::ParticleEffect
+{
+using namespace Dali::Toolkit::ParticleSystem;
+
+class SparklesModifier : public ParticleModifierInterface
+{
+public:
+
+ explicit SparklesModifier(ParticleEmitter& emitter);
+
+ bool IsMultiThreaded() override;
+
+ void Update(ParticleList& particleList, uint32_t first, uint32_t count) override;
+
+ ParticleEmitter mEmitter;
+ uint32_t mStreamBasePos{0u};
+ uint32_t mStreamBaseAngle{0u};
+ uint32_t mAngle{0u};
+};
+
+
+
+}
+
+#endif // DALI_PARTICLES_SPARKLES_EFFECT_MODIFIER_H
diff --git a/examples/particle-system/effects/sparkles-effect-source.cpp b/examples/particle-system/effects/sparkles-effect-source.cpp
new file mode 100644
index 00000000..56eb2987
--- /dev/null
+++ b/examples/particle-system/effects/sparkles-effect-source.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "sparkles-effect-source.h"
+
+namespace Dali::ParticleEffect
+{
+static float LIFETIME = 3.0f;
+SparklesSource::SparklesSource(ParticleEmitter& emitter)
+: mEmitter(emitter)
+{
+ std::time_t result = std::time(nullptr);
+ srand(result);
+ mRadius = Vector2::ONE;
+}
+
+SparklesSource::SparklesSource(ParticleEmitter& emitter, Dali::Vector2 ringRadius) :
+mEmitter(emitter)
+{
+ std::time_t result = std::time(nullptr);
+ srand(result);
+ mRadius = ringRadius;
+
+}
+
+void SparklesSource::Init()
+{
+ mStreamBasePos = mEmitter.GetParticleList().AddLocalStream<Vector3>(Vector3::ZERO);
+ mStreamBaseAngle = mEmitter.GetParticleList().AddLocalStream<float>(0.0f);
+}
+
+uint32_t SparklesSource::Update(ParticleList& particleList, uint32_t count)
+{
+ while(count--)
+ {
+ auto particle = particleList.NewParticle(LIFETIME);
+ if(!particle)
+ {
+ return 0u;
+ }
+
+ auto& basePosition = particle.GetByIndex<Vector3>(mStreamBasePos);
+ auto& angle = particle.GetByIndex<float>(mStreamBaseAngle);
+ auto& position = particle.Get<Vector3>(ParticleStream::POSITION_STREAM_BIT);
+ auto& color = particle.Get<Vector4>(ParticleStream::COLOR_STREAM_BIT);
+ auto& velocity = particle.Get<Vector3>(ParticleStream::VELOCITY_STREAM_BIT);
+ auto& scale = particle.Get<Vector3>(ParticleStream::SCALE_STREAM_BIT);
+
+
+ UpdateParticle(position, basePosition, color, velocity, scale, angle);
+ }
+
+ return 0;
+}
+
+void SparklesSource::UpdateParticle(Vector3& position, Vector3& basePosition, Vector4& color, Vector3& velocity, Vector3& scale, float& angle)
+{
+ static uint32_t a = 0.0f;
+ float posRadians = ((rand() % 360) * M_PI) / 180.0f;
+
+ basePosition.x = position.x = mRadius.x * sin(posRadians);
+ basePosition.y = position.y = mRadius.y * cos(posRadians);
+ color = Dali::Color::WHITE;
+
+ angle = float(a);
+ a = ((a+5)%360);
+ float rad = ((rand() % 360) * M_PI) / 180.0f;
+ float speed = ((rand() % 5) + 5);
+ velocity.x = sin(rad) * speed;
+ velocity.y = cos(rad) * speed;
+
+ // Random initial scale
+ float initialScale = float(rand() % 32) + 32;
+ scale = Vector3(initialScale, initialScale, 1);
+}
+
+} // namespace Dali::ParticleEffect \ No newline at end of file
diff --git a/examples/particle-system/effects/sparkles-effect-source.h b/examples/particle-system/effects/sparkles-effect-source.h
new file mode 100644
index 00000000..466c49b9
--- /dev/null
+++ b/examples/particle-system/effects/sparkles-effect-source.h
@@ -0,0 +1,56 @@
+#ifndef DALI_PARTICLES_SPARKLES_EFFECT_SOURCE_H
+#define DALI_PARTICLES_SPARKLES_EFFECT_SOURCE_H
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle.h>
+#include <ctime>
+
+namespace Dali::ParticleEffect
+{
+using namespace Dali::Toolkit::ParticleSystem;
+
+class SparklesSource : public Toolkit::ParticleSystem::ParticleSourceInterface
+{
+public:
+
+ explicit SparklesSource(ParticleEmitter& emitter);
+
+ explicit SparklesSource(ParticleEmitter& emitter, Dali::Vector2 ringRadius);
+
+ uint32_t Update(ParticleList& particleList, uint32_t count) override;
+
+ void Init() override;
+
+ void UpdateParticle(Vector3& position, Vector3& basePosition, Vector4& color, Vector3& velocity, Vector3& scale, float& angle);
+
+ ParticleEmitter mEmitter;
+
+ Dali::Vector2 mRadius;
+
+ uint32_t mStreamBasePos{0u};
+ uint32_t mStreamBaseAngle{0u};
+
+};
+
+}
+#endif // DALI_PARTICLES_SPARKLES_EFFECT_SOURCE_H
diff --git a/examples/particle-system/particle-system-example.cpp b/examples/particle-system/particle-system-example.cpp
new file mode 100644
index 00000000..7d6a8898
--- /dev/null
+++ b/examples/particle-system/particle-system-example.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit/dali-toolkit.h>
+
+#include <dali-toolkit/public-api/particle-system/particle-emitter.h>
+#include <dali-toolkit/public-api/particle-system/particle-source.h>
+#include <dali-toolkit/public-api/particle-system/particle-domain.h>
+#include <dali-toolkit/public-api/particle-system/particle-list.h>
+#include <dali-toolkit/public-api/particle-system/particle-renderer.h>
+#include <dali-toolkit/public-api/particle-system/particle-types.h>
+
+#include <utility>
+#include <ctime>
+#include <dali-toolkit/public-api/particle-system/particle-modifier.h>
+#include <unistd.h>
+#include <map>
+
+#include "effects/particle-effect.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit::ParticleSystem;
+using namespace Dali::Toolkit;
+using Dali::Toolkit::TextLabel;
+
+using namespace Dali::ParticleEffect;
+
+/**
+ * This example shows Particle System feature
+ */
+class ParticleEffectController : public ConnectionTracker
+{
+public:
+
+ ParticleEffectController(Application& application)
+ : mApplication(application)
+ {
+ // Connect to the Application's Init signal
+ mApplication.InitSignal().Connect(this, &ParticleEffectController::Create);
+ }
+
+ ~ParticleEffectController() = default; // Nothing to do in destructor
+
+ template<class ButtonType>
+ ButtonType MakeButton( std::string title,
+ Vector2 position,
+ Vector2 size,
+ bool toggleable,
+ std::function<bool(Button)> onClick )
+ {
+ ButtonType button = ButtonType::New();
+ button.SetProperty( Button::Property::LABEL, title);
+ button.SetProperty( Actor::Property::POSITION, position);
+ button.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ button.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ button.SetProperty(Button::Property::TOGGLABLE, toggleable);
+ static std::map<RefObject*, std::function<bool(Button)>> callbackMap;
+ struct OnClick
+ {
+ static bool Slot(Button btn)
+ {
+ auto ptr = btn.GetObjectPtr();
+ return callbackMap[ptr](btn);
+ }
+ };
+
+ mUILastControlPosition = position;
+ mUILastControlSize = (size == Vector2::ZERO ? Vector2(button.GetNaturalSize()) : size);
+
+ callbackMap[button.GetObjectPtr()] = onClick;
+ button.ClickedSignal().Connect(OnClick::Slot);
+ return button;
+ }
+
+ // The Init signal is received once (only) during the Application lifetime
+ void Create(Application& application)
+ {
+ using namespace Dali::ParticleEffect;
+
+ // Get a handle to the window
+ Window window = application.GetWindow();
+ window.SetBackgroundColor(Color::BLACK);
+ {
+ Actor emitterActor = Actor::New();
+ emitterActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ emitterActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ emitterActor.SetProperty(Actor::Property::POSITION, Vector2(0.0, 0.0f));
+ emitterActor.SetProperty(Actor::Property::SIZE, Vector2(1.0, 1.0f));
+ window.Add(emitterActor);
+
+ mEmitterActor = emitterActor;
+ PushButton lastButton;
+ window.Add(
+ MakeButton<PushButton>("Fire Effect", Vector2::ZERO, {}, true, [&](Button button){
+
+ if(mCurrentEmitter)
+ {
+ mCurrentEmitter.Stop();
+ mCurrentEmitter.Reset();
+ }
+
+ ParticleEffectParams params{};
+ params.particleCount = 5000;
+ params.emissionRate = 1000;
+ params.initialParticleCount = 0;
+ params.sourceSize = Vector2(200, 10);
+ params.strTexture = "sparkle-part1.png";
+
+ mCurrentEmitter = mParticleSystem->CreateEffectEmitter( EffectType::FIRE_RING, mEmitterActor, params );
+ mCurrentEmitter.Start();
+ return true;
+ })
+ );
+
+ window.Add(
+ MakeButton<PushButton>("Sparkle Effect", Vector2(0.0f, mUILastControlSize.height), {}, true, [&](Button button){
+ if(mCurrentEmitter)
+ {
+ mCurrentEmitter.Stop();
+ mCurrentEmitter.Reset();
+ }
+
+ ParticleEffectParams params{};
+ params.particleCount = 10000;
+ params.emissionRate = 500;
+ params.initialParticleCount = 0;
+ params.sourceSize = Vector2(10, 10);
+ params.strTexture = "blue-part2.png";
+
+ mCurrentEmitter = mParticleSystem->CreateEffectEmitter( EffectType::SPARKLES, mEmitterActor, params );
+ mCurrentEmitter.Start();
+ return true;
+ })
+ );
+
+ window.Add(
+ MakeButton<PushButton>("Image Source Effect", Vector2(0.0f, mUILastControlPosition.y + mUILastControlSize.height), {}, true, [&](Button button){
+ if(mCurrentEmitter)
+ {
+ mCurrentEmitter.Stop();
+ mCurrentEmitter.Reset();
+ }
+
+ ParticleEffectParams params{};
+ params.particleCount = 20000;
+ params.emissionRate = 0;
+ params.initialParticleCount = 10;
+ params.sourceSize = Vector2(64, 64);
+ params.strImageSourceName = "particle-image-source.jpg";
+
+ mCurrentEmitter = mParticleSystem->CreateEffectEmitter( EffectType::IMAGE_EXPLOSION, mEmitterActor, params );
+ mCurrentEmitter.Start();
+ return true;
+ })
+ );
+ window.Add(
+ MakeButton<PushButton>("Quit", Vector2(0.0f, mUILastControlPosition.y + mUILastControlSize.height * 2), {}, true, [&](Button button){
+ if(mCurrentEmitter)
+ {
+ mCurrentEmitter.Stop();
+ mCurrentEmitter.Reset();
+ }
+ mApplication.Quit();
+ return true;
+ })
+ );
+ }
+
+ // Respond to key events
+ window.KeyEventSignal().Connect(this, &ParticleEffectController::OnKeyEvent);
+ }
+
+ void OnKeyEvent(const KeyEvent& event)
+ {
+ if(event.GetState() == KeyEvent::DOWN)
+ {
+ if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
+ {
+ mApplication.Quit();
+ }
+ }
+ }
+
+private:
+
+ Application& mApplication;
+ std::unique_ptr<Dali::ParticleEffect::ParticleEffect> mParticleSystem;
+ ParticleEmitter mCurrentEmitter;
+ Actor mEmitterActor;
+
+ // Needed for buttons
+ Vector2 mUILastControlPosition;
+ Vector2 mUILastControlSize;
+
+};
+
+int DALI_EXPORT_API main(int argc, char** argv)
+{
+ Application application = Application::New(&argc, &argv);
+ ParticleEffectController test(application);
+ application.MainLoop();
+ return 0;
+}
diff --git a/resources/images/blue-part2.png b/resources/images/blue-part2.png
new file mode 100644
index 00000000..3f41b437
--- /dev/null
+++ b/resources/images/blue-part2.png
Binary files differ
diff --git a/resources/images/particle-image-source.jpg b/resources/images/particle-image-source.jpg
new file mode 100644
index 00000000..05e41f84
--- /dev/null
+++ b/resources/images/particle-image-source.jpg
Binary files differ
diff --git a/resources/images/sparkle-part1.png b/resources/images/sparkle-part1.png
new file mode 100644
index 00000000..d6c1764d
--- /dev/null
+++ b/resources/images/sparkle-part1.png
Binary files differ
diff --git a/resources/po/en_GB.po b/resources/po/en_GB.po
index 3211603d..35c782c5 100755
--- a/resources/po/en_GB.po
+++ b/resources/po/en_GB.po
@@ -178,6 +178,9 @@ msgstr "Creation View Performance"
msgid "DALI_DEMO_STR_TITLE_POINT_MESH"
msgstr "Point Mesh"
+msgid "DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM"
+msgstr "Particle System"
+
msgid "DALI_DEMO_STR_TITLE_POPUP"
msgstr "Popup"
diff --git a/resources/po/en_US.po b/resources/po/en_US.po
index a4603666..6d1a91fb 100755
--- a/resources/po/en_US.po
+++ b/resources/po/en_US.po
@@ -178,6 +178,9 @@ msgstr "Page Turn"
msgid "DALI_DEMO_STR_TITLE_PARTICLES"
msgstr "Particles"
+msgid "DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM"
+msgstr "Particle System"
+
msgid "DALI_DEMO_STR_TITLE_PERF_SCROLL"
msgstr "Scrolling Performance"
diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h
index da603525..1d6377f4 100644
--- a/shared/dali-demo-strings.h
+++ b/shared/dali-demo-strings.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -97,6 +97,7 @@ extern "C"
#define DALI_DEMO_STR_TITLE_NEGOTIATE_SIZE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_NEGOTIATE_SIZE")
#define DALI_DEMO_STR_TITLE_PAGE_TURN dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PAGE_TURN")
#define DALI_DEMO_STR_TITLE_PARTICLES dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PARTICLES")
+#define DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM")
#define DALI_DEMO_STR_TITLE_PBR dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PBR")
#define DALI_DEMO_STR_TITLE_PERF_SCROLL dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PERF_SCROLL")
#define DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION")
@@ -211,6 +212,7 @@ extern "C"
#define DALI_DEMO_STR_TITLE_NEGOTIATE_SIZE "Negotiate Size"
#define DALI_DEMO_STR_TITLE_PAGE_TURN "Page Turn"
#define DALI_DEMO_STR_TITLE_PARTICLES "Particles"
+#define DALI_DEMO_STR_TITLE_PARTICLE_SYSTEM "Particle System"
#define DALI_DEMO_STR_TITLE_PBR "PBR"
#define DALI_DEMO_STR_TITLE_PERF_SCROLL "Scrolling Performance"
#define DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION "Creation View Performance"