Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-demo.git] / examples / particle-system / particle-system-example.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/dali-toolkit.h>
19
20 #include <dali-toolkit/public-api/particle-system/particle-domain.h>
21 #include <dali-toolkit/public-api/particle-system/particle-emitter.h>
22 #include <dali-toolkit/public-api/particle-system/particle-list.h>
23 #include <dali-toolkit/public-api/particle-system/particle-renderer.h>
24 #include <dali-toolkit/public-api/particle-system/particle-source.h>
25 #include <dali-toolkit/public-api/particle-system/particle-types.h>
26
27 #include <dali-toolkit/public-api/particle-system/particle-modifier.h>
28
29 #include "effects/particle-effect.h"
30
31 using namespace Dali;
32 using namespace Dali::Toolkit::ParticleSystem;
33 using namespace Dali::Toolkit;
34 using Dali::Toolkit::TextLabel;
35
36 using namespace Dali::ParticleEffect;
37
38 constexpr uint16_t NUMBER_OF_EFFECTS         = 3;
39 constexpr float    TEXT_LABEL_ANIMATION_TIME = 5.0f;
40 const TimePeriod   TEXT_LABEL_ANIMATION_TIME_PERIOD(3.0, 2.0f);
41
42 /**
43  * This example shows Particle System feature
44  */
45 class ParticleEffectController : public ConnectionTracker
46 {
47 public:
48   ParticleEffectController(Application& application)
49   : mApplication(application)
50   {
51     // Connect to the Application's Init signal
52     mApplication.InitSignal().Connect(this, &ParticleEffectController::Create);
53   }
54
55   ~ParticleEffectController() = default; // Nothing to do in destructor
56
57 private:
58   // The Init signal is received once (only) during the Application lifetime
59   void Create(Application& application)
60   {
61     Window window = application.GetWindow();
62     window.SetBackgroundColor(Color::BLACK);
63     auto windowSize = window.GetSize();
64
65     // Set up emitter actor to be the full size of the window as some particles may be outside a particular size
66     mEmitterActor = Handle::New<Actor>({{Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER},
67                                         {Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER},
68                                         {Actor::Property::POSITION, Vector2::ZERO},
69                                         {Actor::Property::SIZE, Vector2(windowSize.GetWidth(), windowSize.GetHeight())}});
70     window.Add(mEmitterActor);
71
72     // Create a tap gesture detector, attach the actor & connect
73     mTapDetector = TapGestureDetector::New();
74     mTapDetector.Attach(mEmitterActor);
75     mTapDetector.DetectedSignal().Connect(this, [&](Actor actor, const TapGesture& tap) { NextEffect(); });
76
77     // Respond to key events
78     window.KeyEventSignal().Connect(this, &ParticleEffectController::OnKeyEvent);
79
80     // Create a Text Label at the bottom of the screen
81     mTextLabel = Handle::New<TextLabel>({{Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER},
82                                          {Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER},
83                                          {TextLabel::Property::MULTI_LINE, true},
84                                          {TextLabel::Property::HORIZONTAL_ALIGNMENT, HorizontalAlignment::CENTER},
85                                          {TextLabel::Property::TEXT_COLOR, Color::WHITE}});
86     window.Add(mTextLabel);
87
88     // Create a fade out animation for the text label after a few seconds
89     mTextLabelAnimation = Animation::New(TEXT_LABEL_ANIMATION_TIME);
90     mTextLabelAnimation.AnimateTo(Property(mTextLabel, Actor::Property::COLOR_ALPHA), 0.0f, TEXT_LABEL_ANIMATION_TIME_PERIOD);
91     mTextLabelAnimation.Play();
92
93     // Start the default effect
94     StartEffect(EffectType(mCurrentEffectType));
95
96     // Add extra line to text for further instructions only the first time
97     std::string label = mTextLabel[TextLabel::Property::TEXT];
98     label += "\nTap to change particle effect";
99     mTextLabel[TextLabel::Property::TEXT] = label;
100   }
101
102   void StartEffect(EffectType effectType)
103   {
104     if(mCurrentEmitter)
105     {
106       mCurrentEmitter.Stop();
107       mCurrentEmitter.Reset();
108     }
109
110     ParticleEffectParams params{};
111     std::string          effectName;
112
113     switch(effectType)
114     {
115       case EffectType::FIRE_RING:
116         params.particleCount        = 5000;
117         params.emissionRate         = 1000;
118         params.initialParticleCount = 0;
119         params.sourceSize           = Vector2(200, 10);
120         params.strTexture           = "sparkle-part1.png";
121         effectName                  = "Fire Effect";
122         break;
123
124       case EffectType::SPARKLES:
125         params.particleCount        = 10000;
126         params.emissionRate         = 500;
127         params.initialParticleCount = 0;
128         params.sourceSize           = Vector2(10, 10);
129         params.strTexture           = "blue-part2.png";
130         effectName                  = "Sparkle Effect";
131         break;
132
133       case EffectType::IMAGE_EXPLOSION:
134         params.particleCount        = 20000;
135         params.emissionRate         = 0;
136         params.initialParticleCount = 10;
137         params.sourceSize           = Vector2(64, 64);
138         params.strImageSourceName   = "particle-image-source.jpg";
139         effectName                  = "Image Source Effect";
140         break;
141     }
142
143     mCurrentEmitter = mParticleSystem->CreateEffectEmitter(effectType, mEmitterActor, params);
144     mCurrentEmitter.Start();
145
146     // Set text and reset TextLabel properties and animation
147     mTextLabel[Toolkit::TextLabel::Property::TEXT] = effectName;
148     mTextLabel[Actor::Property::COLOR_ALPHA]       = 1.0f;
149     mTextLabelAnimation.SetCurrentProgress(0.0f);
150     mTextLabelAnimation.Play();
151   }
152
153   void NextEffect()
154   {
155     StartEffect(EffectType(++mCurrentEffectType %= NUMBER_OF_EFFECTS));
156   }
157
158   void OnKeyEvent(const KeyEvent& event)
159   {
160     if(event.GetState() == KeyEvent::DOWN)
161     {
162       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
163       {
164         mApplication.Quit();
165       }
166       else
167       {
168         NextEffect();
169       }
170     }
171   }
172
173 private:
174   using ParticleEffectPtr = std::unique_ptr<Dali::ParticleEffect::ParticleEffect>;
175
176   Application&      mApplication;
177   ParticleEffectPtr mParticleSystem;
178   ParticleEmitter   mCurrentEmitter;
179   Actor             mEmitterActor;
180
181   TapGestureDetector mTapDetector;
182
183   uint32_t  mCurrentEffectType{0u};
184   Actor     mTextLabel;
185   Animation mTextLabelAnimation;
186 };
187
188 int DALI_EXPORT_API main(int argc, char** argv)
189 {
190   Application              application = Application::New(&argc, &argv);
191   ParticleEffectController test(application);
192   application.MainLoop();
193   return 0;
194 }