Changes following "Changed bubble effect to use new texture API"
[platform/core/uifw/dali-demo.git] / examples / bubble-effect / bubble-effect-example.cpp
1 /*
2  * Copyright (c) 2016 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/dali.h>
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h>
21 #include "shared/view.h"
22 #include "shared/utility.h"
23
24 using namespace Dali;
25
26 namespace
27 {
28 const char * const TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
29 const char * const APPLICATION_TITLE( "Bubble Effect" );
30 const char * const CHANGE_BACKGROUND_ICON( DEMO_IMAGE_DIR "icon-change.png" );
31 const char * const CHANGE_BACKGROUND_ICON_SELECTED( DEMO_IMAGE_DIR "icon-change-selected.png" );
32 const char * const CHANGE_BUBBLE_SHAPE_ICON( DEMO_IMAGE_DIR "icon-replace.png" );
33 const char * const CHANGE_BUBBLE_SHAPE_ICON_SELECTED( DEMO_IMAGE_DIR "icon-replace-selected.png" );
34
35 const char* BACKGROUND_IMAGES[]=
36 {
37   DEMO_IMAGE_DIR "background-1.jpg",
38   DEMO_IMAGE_DIR "background-2.jpg",
39   DEMO_IMAGE_DIR "background-3.jpg",
40   DEMO_IMAGE_DIR "background-4.jpg",
41   DEMO_IMAGE_DIR "background-5.jpg",
42 };
43 const unsigned int NUM_BACKGROUND_IMAGES( sizeof( BACKGROUND_IMAGES ) / sizeof( BACKGROUND_IMAGES[0] ) );
44
45 const char* BUBBLE_SHAPE_IMAGES[] =
46 {
47   DEMO_IMAGE_DIR "bubble-ball.png",
48   DEMO_IMAGE_DIR "icon-effect-cross.png",
49   DEMO_IMAGE_DIR "icon-item-view-layout-spiral.png",
50   DEMO_IMAGE_DIR "icon-replace.png"
51 };
52 const unsigned int NUM_BUBBLE_SHAPE_IMAGES( sizeof( BUBBLE_SHAPE_IMAGES ) / sizeof( BUBBLE_SHAPE_IMAGES[0] ) );
53
54 const Vector2 DEFAULT_BUBBLE_SIZE( 10.f, 30.f );
55 const unsigned int DEFAULT_NUMBER_OF_BUBBLES( 1000 );
56
57 }// end LOCAL_STUFF
58
59 // This example shows the usage of BubbleEmitter which displays lots of moving bubbles on the stage.
60 class BubbleEffectExample : public ConnectionTracker
61 {
62 public:
63   BubbleEffectExample(Application &app)
64   : mApp(app),
65     mBackground(),
66     mBubbleEmitter(),
67     mEmitAnimation(),
68     mChangeBackgroundButton(),
69     mChangeBubbleShapeButton(),
70     mTimerForBubbleEmission(),
71     mHSVDelta( Vector3( 0.f, 0.f, 0.5f ) ),
72     mCurrentTouchPosition(),
73     mEmitPosition(),
74     mAnimateComponentCount( 0 ),
75     mNonMovementCount( 0 ),
76     mTimerInterval( 16 ),
77     mCurrentBackgroundImageId( 0 ),
78     mCurrentBubbleShapeImageId( 0 ),
79     mNeedNewAnimation( true )
80   {
81     // Connect to the Application's Init signal
82     app.InitSignal().Connect(this, &BubbleEffectExample::Create);
83   }
84
85   ~BubbleEffectExample()
86   {
87   }
88
89 private:
90
91   // The Init signal is received once (only) during the Application lifetime
92   void Create(Application& app)
93   {
94     Stage stage = Stage::GetCurrent();
95     Vector2 stageSize = stage.GetSize();
96
97     stage.KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent);
98
99     // Creates a default view with a default tool bar.
100     // The view is added to the stage.
101     Toolkit::ToolBar toolBar;
102     Layer content = DemoHelper::CreateView( app,
103                                             mBackground,
104                                             toolBar,
105                                             "",
106                                             TOOLBAR_IMAGE,
107                                             APPLICATION_TITLE );
108
109     // Add a button to change background. (right of toolbar)
110     mChangeBackgroundButton = Toolkit::PushButton::New();
111     mChangeBackgroundButton.SetUnselectedImage( CHANGE_BACKGROUND_ICON );
112     mChangeBackgroundButton.SetSelectedImage( CHANGE_BACKGROUND_ICON_SELECTED );
113     mChangeBackgroundButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked );
114     toolBar.AddControl( mChangeBackgroundButton,
115                         DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
116                         Toolkit::Alignment::HorizontalRight,
117                         DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
118     // Add a button to change bubble shape. ( left of bar )
119     mChangeBubbleShapeButton = Toolkit::PushButton::New();
120     mChangeBubbleShapeButton.SetUnselectedImage( CHANGE_BUBBLE_SHAPE_ICON );
121     mChangeBubbleShapeButton.SetSelectedImage( CHANGE_BUBBLE_SHAPE_ICON_SELECTED );
122     mChangeBubbleShapeButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked );
123     toolBar.AddControl( mChangeBubbleShapeButton,
124                         DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
125                         Toolkit::Alignment::HorizontalLeft,
126                         DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
127
128     // Create and initialize the BubbleEmitter object
129     mBubbleEmitter = Toolkit::BubbleEmitter::New( stageSize,
130                                                   DemoHelper::LoadTexture( BUBBLE_SHAPE_IMAGES[mCurrentBubbleShapeImageId] ),
131                                                   DEFAULT_NUMBER_OF_BUBBLES,
132                                                   DEFAULT_BUBBLE_SIZE);
133
134     mBubbleEmitter.SetBackground( DemoHelper::LoadStageFillingTexture( BACKGROUND_IMAGES[mCurrentBackgroundImageId] ), mHSVDelta );
135
136     // Get the root actor of all bubbles, and add it to stage.
137     Actor bubbleRoot = mBubbleEmitter.GetRootActor();
138     bubbleRoot.SetParentOrigin(ParentOrigin::CENTER);
139     bubbleRoot.SetZ(0.1f); // Make sure the bubbles displayed on top og the background.
140     content.Add( bubbleRoot );
141
142     // Set the application background
143     mBackground.SetProperty( Toolkit::Control::Property::BACKGROUND, Dali::Property::Map()
144       .Add( Dali::Toolkit::Visual::Property::TYPE, Dali::Toolkit::Visual::IMAGE )
145       .Add( Dali::Toolkit::ImageVisual::Property::URL, BACKGROUND_IMAGES[mCurrentBackgroundImageId] ));
146
147     // Set up the timer to emit bubble regularly when the finger is touched down but not moved
148     mTimerForBubbleEmission = Timer::New( mTimerInterval );
149     mTimerForBubbleEmission.TickSignal().Connect(this, &BubbleEffectExample::OnTimerTick);
150
151     // Connect the callback to the touch signal on the background
152     mBackground.TouchSignal().Connect( this, &BubbleEffectExample::OnTouch );
153   }
154
155
156 /***********
157  * Emit bubbles
158  *****************/
159
160   // Set up the animation of emitting bubbles, to be efficient, every animation controls multiple emission ( 4 here )
161   void SetUpAnimation( Vector2 emitPosition, Vector2 direction )
162   {
163     if( mNeedNewAnimation )
164     {
165       float duration = Random::Range(1.f, 1.5f);
166       mEmitAnimation = Animation::New( duration );
167       mNeedNewAnimation = false;
168       mAnimateComponentCount = 0;
169     }
170
171     mBubbleEmitter.EmitBubble( mEmitAnimation, emitPosition, direction + Vector2(0.f, 30.f) /* upwards */, Vector2(300, 600) );
172
173     mAnimateComponentCount++;
174
175     if( mAnimateComponentCount % 4 ==0 )
176     {
177       mEmitAnimation.Play();
178       mNeedNewAnimation = true;
179     }
180   }
181
182   // Emit bubbles when the finger touches down but keep stationary.
183   // And stops emitting new bubble after being stationary for 2 seconds
184   bool OnTimerTick()
185   {
186     if(mEmitPosition == mCurrentTouchPosition) // finger is not moving
187     {
188       mNonMovementCount++;
189       if(mNonMovementCount < (1000 / mTimerInterval)) // 1 seconds
190       {
191         for(int i = 0; i < 4; i++) // emit 4 bubbles every timer tick
192         {
193           SetUpAnimation( mCurrentTouchPosition+Vector2(rand()%5, rand()%5), Vector2(rand()%60-30, rand()%100-50) );
194         }
195       }
196     }
197     else
198     {
199       mNonMovementCount = 0;
200       mEmitPosition = mCurrentTouchPosition;
201     }
202
203     return true;
204   }
205
206   // Callback function of the touch signal on the background
207   bool OnTouch(Dali::Actor actor, const Dali::TouchData& event)
208   {
209     switch( event.GetState( 0 ) )
210     {
211       case PointState::DOWN:
212       {
213         mCurrentTouchPosition = mEmitPosition = event.GetScreenPosition( 0 );
214         mTimerForBubbleEmission.Start();
215         mNonMovementCount = 0;
216
217         break;
218       }
219       case PointState::MOTION:
220       {
221         Vector2 displacement = event.GetScreenPosition( 0 ) - mCurrentTouchPosition;
222         mCurrentTouchPosition = event.GetScreenPosition( 0 );
223         //emit multiple bubbles along the moving direction when the finger moves quickly
224         float step = std::min(5.f, displacement.Length());
225         for( float i=0.25f; i<step; i=i+1.f)
226         {
227           SetUpAnimation( mCurrentTouchPosition+displacement*(i/step), displacement );
228         }
229         break;
230       }
231       case PointState::UP:
232       case PointState::LEAVE:
233       case PointState::INTERRUPTED:
234       {
235         mTimerForBubbleEmission.Stop();
236         mEmitAnimation.Play();
237         mNeedNewAnimation = true;
238         mAnimateComponentCount = 0;
239         break;
240       }
241       case PointState::STATIONARY:
242       default:
243       {
244         break;
245       }
246
247     }
248     return true;
249   }
250
251   bool OnChangeIconClicked( Toolkit::Button button )
252   {
253     if(button == mChangeBackgroundButton)
254     {
255       mCurrentBackgroundImageId = (mCurrentBackgroundImageId+1) % NUM_BACKGROUND_IMAGES;
256
257       //Update bubble emitter background
258       mBubbleEmitter.SetBackground( DemoHelper::LoadStageFillingTexture( BACKGROUND_IMAGES[ mCurrentBackgroundImageId  ] ), mHSVDelta );
259
260       // Set the application background
261       mBackground.SetProperty( Toolkit::Control::Property::BACKGROUND, Dali::Property::Map()
262       .Add( Dali::Toolkit::Visual::Property::TYPE, Dali::Toolkit::Visual::IMAGE )
263       .Add( Dali::Toolkit::ImageVisual::Property::URL, BACKGROUND_IMAGES[mCurrentBackgroundImageId] ));
264     }
265     else if( button == mChangeBubbleShapeButton )
266     {
267       mBubbleEmitter.SetBubbleShape( DemoHelper::LoadTexture( BUBBLE_SHAPE_IMAGES[ ++mCurrentBubbleShapeImageId % NUM_BUBBLE_SHAPE_IMAGES ] ) );
268     }
269     return true;
270   }
271
272   /**
273    * Main key event handler
274    */
275   void OnKeyEvent(const KeyEvent& event)
276   {
277     if(event.state == KeyEvent::Down)
278     {
279       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
280       {
281         mApp.Quit();
282       }
283     }
284   }
285
286 private:
287
288   Application&               mApp;
289   Dali::Toolkit::Control     mBackground;
290
291   Toolkit::BubbleEmitter     mBubbleEmitter;
292   Animation                  mEmitAnimation;
293   Toolkit::PushButton        mChangeBackgroundButton;
294   Toolkit::PushButton        mChangeBubbleShapeButton;
295   Timer                      mTimerForBubbleEmission;
296
297   Vector3                    mHSVDelta;
298   Vector2                    mCurrentTouchPosition;
299   Vector2                    mEmitPosition;
300
301   unsigned int               mAnimateComponentCount;
302   unsigned int               mNonMovementCount;
303   unsigned int               mTimerInterval;
304   unsigned int               mCurrentBackgroundImageId;
305   unsigned int               mCurrentBubbleShapeImageId;
306
307   bool                       mNeedNewAnimation;
308 };
309
310 /*****************************************************************************/
311
312 static void
313 RunTest(Application& app)
314 {
315   BubbleEffectExample theApp(app);
316   app.MainLoop();
317 }
318
319 /*****************************************************************************/
320
321 int DALI_EXPORT_API main(int argc, char **argv)
322 {
323   Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
324
325   RunTest(app);
326
327   return 0;
328 }