Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-demo.git] / examples / bubble-effect / bubble-effect-example.cpp
1 /*
2  * Copyright (c) 2014 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 "shared/view.h"
21
22 using namespace Dali;
23
24 namespace
25 {
26 const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
27 const char * const APPLICATION_TITLE( "Bubble Effect" );
28 const char * const CHANGE_BACKGROUND_ICON( DALI_IMAGE_DIR "icon-change.png" );
29 const char * const CHANGE_BUBBLE_SHAPE_ICON( DALI_IMAGE_DIR "icon-replace.png" );
30
31 const char* BACKGROUND_IMAGES[]=
32 {
33   DALI_IMAGE_DIR "background-1.jpg",
34   DALI_IMAGE_DIR "background-2.jpg",
35   DALI_IMAGE_DIR "background-3.jpg",
36   DALI_IMAGE_DIR "background-4.jpg",
37   DALI_IMAGE_DIR "background-5.jpg",
38 };
39 const unsigned int NUM_BACKGROUND_IMAGES( sizeof( BACKGROUND_IMAGES ) / sizeof( BACKGROUND_IMAGES[0] ) );
40
41 const char* BUBBLE_SHAPE_IMAGES[] =
42 {
43   DALI_IMAGE_DIR "bubble-ball.png",
44   DALI_IMAGE_DIR "icon-item-view-layout-spiral.png",
45   DALI_IMAGE_DIR "icon-replace.png",
46   DALI_IMAGE_DIR "icon-effect-cross.png"
47 };
48 const unsigned int NUM_BUBBLE_SHAPE_IMAGES( sizeof( BUBBLE_SHAPE_IMAGES ) / sizeof( BUBBLE_SHAPE_IMAGES[0] ) );
49
50 const Vector2 DEFAULT_BUBBLE_SIZE( 10.f, 30.f );
51 const unsigned int DEFAULT_NUMBER_OF_BUBBLES( 1000 );
52
53 /**
54  * @brief Load an image, scaled-down to no more than the stage dimensions.
55  *
56  * Uses image scaling mode ImageAttributes::ScaleToFill to resize the image at
57  * load time to cover the entire stage with pixels with no borders,
58  * and filter mode ImageAttributes::BoxThenLinear to sample the image with
59  * maximum quality.
60  */
61 ResourceImage LoadStageFillingImage( const char * const imagePath )
62 {
63   Size stageSize = Stage::GetCurrent().GetSize();
64   ImageAttributes attributes;
65   attributes.SetSize( stageSize.x, stageSize.y );
66   attributes.SetFilterMode( ImageAttributes::BoxThenLinear );
67   attributes.SetScalingMode( ImageAttributes::ScaleToFill );
68   return ResourceImage::New( imagePath, attributes );
69 }
70
71 }// end LOCAL_STUFF
72
73 // This example shows the usage of BubbleEmitter which displays lots of moving bubbles on the stage.
74 class BubbleEffectExample : public ConnectionTracker
75 {
76 public:
77   BubbleEffectExample(Application &app)
78   : mApp(app),
79     mHSVDelta( Vector3( 0.f, 0.f, 0.5f ) ),
80     mNeedNewAnimation( true ),
81     mTimerInterval( 16 ),
82     mCurrentBackgroundImageId( 0 ),
83     mCurrentBubbleShapeImageId( 0 )
84   {
85     // Connect to the Application's Init signal
86     app.InitSignal().Connect(this, &BubbleEffectExample::Create);
87   }
88
89   ~BubbleEffectExample()
90   {
91   }
92
93 private:
94
95   // The Init signal is received once (only) during the Application lifetime
96   void Create(Application& app)
97   {
98     DemoHelper::RequestThemeChange();
99
100     Stage stage = Stage::GetCurrent();
101     Vector2 stageSize = stage.GetSize();
102
103     stage.KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent);
104
105     // Creates a default view with a default tool bar.
106     // The view is added to the stage.
107     Toolkit::ToolBar toolBar;
108     Toolkit::View    view;
109     Layer content = DemoHelper::CreateView( app,
110                                             view,
111                                             toolBar,
112                                             "",
113                                             TOOLBAR_IMAGE,
114                                             APPLICATION_TITLE );
115
116     // Add a button to change background. (right of toolbar)
117     mChangeBackgroundButton = Toolkit::PushButton::New();
118     mChangeBackgroundButton.SetBackgroundImage( ResourceImage::New( CHANGE_BACKGROUND_ICON ) );
119     mChangeBackgroundButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked );
120     toolBar.AddControl( mChangeBackgroundButton,
121                         DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
122                         Toolkit::Alignment::HorizontalRight,
123                         DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
124     // Add a button to change bubble shape. ( left of bar )
125     mChangeBubbleShapeButton = Toolkit::PushButton::New();
126     mChangeBubbleShapeButton.SetBackgroundImage( ResourceImage::New( CHANGE_BUBBLE_SHAPE_ICON ) );
127     mChangeBubbleShapeButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked );
128     toolBar.AddControl( mChangeBubbleShapeButton,
129                         DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
130                         Toolkit::Alignment::HorizontalLeft,
131                         DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
132
133     // Create and initialize the BubbleEmitter object
134     mBubbleEmitter = Toolkit::BubbleEmitter::New( stageSize,
135                                                   ResourceImage::New( BUBBLE_SHAPE_IMAGES[mCurrentBubbleShapeImageId] ),
136                                                   DEFAULT_NUMBER_OF_BUBBLES,
137                                                   DEFAULT_BUBBLE_SIZE);
138     mBackgroundImage = LoadStageFillingImage( BACKGROUND_IMAGES[mCurrentBackgroundImageId] );
139     mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta );
140
141     // Get the root actor of all bubbles, and add it to stage.
142     Actor bubbleRoot = mBubbleEmitter.GetRootActor();
143     bubbleRoot.SetParentOrigin(ParentOrigin::CENTER);
144     bubbleRoot.SetZ(0.1f); // Make sure the bubbles displayed on top og the background.
145     content.Add( bubbleRoot );
146
147     // Add the background image actor to stage
148     mBackgroundActor = ImageActor::New( mBackgroundImage );
149     view.SetBackground( mBackgroundActor );
150
151     // Set up the timer to emit bubble regularly when the finger is touched down but not moved
152     mTimerForBubbleEmission = Timer::New( mTimerInterval );
153     mTimerForBubbleEmission.TickSignal().Connect(this, &BubbleEffectExample::OnTimerTick);
154
155     // Connect the callback to the touch signal on the background
156     mBackgroundActor.TouchedSignal().Connect( this, &BubbleEffectExample::OnTouch );
157   }
158
159
160 /***********
161  * Emit bubbles
162  *****************/
163
164   // Set up the animation of emitting bubbles, to be efficient, every animation controls multiple bubbles ( 4 here )
165   void SetUpAnimation( Vector2 emitPosition, Vector2 direction )
166   {
167     if( mNeedNewAnimation )
168     {
169       float duration = Random::Range(1.f, 1.5f);
170       mEmitAnimation = Animation::New( duration );
171       mNeedNewAnimation = false;
172       mAnimateComponentCount = 0;
173     }
174
175     mBubbleEmitter.EmitBubble( mEmitAnimation, emitPosition, direction + Vector2(0.f, 30.f) /* upwards */, Vector2(300, 600) );
176
177     mAnimateComponentCount++;
178
179     if( mAnimateComponentCount % 4 ==0 )
180     {
181       mEmitAnimation.Play();
182       mNeedNewAnimation = true;
183     }
184   }
185
186   // Emit bubbles when the finger touches down but keep stationary.
187   // And stops emitting new bubble after being stationary for 2 seconds
188   bool OnTimerTick()
189   {
190     if(mEmitPosition == mCurrentTouchPosition) // finger is not moving
191     {
192       mNonMovementCount++;
193       if(mNonMovementCount < (1000 / mTimerInterval)) // 1 seconds
194       {
195         for(int i = 0; i < 4; i++) // emit 4 bubbles every timer tick
196         {
197           SetUpAnimation( mCurrentTouchPosition+Vector2(rand()%5, rand()%5), Vector2(rand()%60-30, rand()%100-50) );
198         }
199       }
200     }
201     else
202     {
203       mNonMovementCount = 0;
204       mEmitPosition = mCurrentTouchPosition;
205     }
206
207     return true;
208   }
209
210   // Callback function of the touch signal on the background
211   bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event)
212   {
213     const TouchPoint &point = event.GetPoint(0);
214     switch(point.state)
215     {
216       case TouchPoint::Down:
217       {
218         mCurrentTouchPosition = point.screen;
219         mEmitPosition = point.screen;
220         mTimerForBubbleEmission.Start();
221         mNonMovementCount = 0;
222
223         break;
224       }
225       case TouchPoint::Motion:
226       {
227         Vector2 displacement = point.screen - mCurrentTouchPosition;
228         mCurrentTouchPosition = point.screen;
229         //emit multiple bubbles along the moving direction when the finger moves quickly
230         float step = std::min(5.f, displacement.Length());
231         for( float i=0.25f; i<step; i=i+1.f)
232         {
233           SetUpAnimation( mCurrentTouchPosition+displacement*(i/step), displacement );
234         }
235         break;
236       }
237       case TouchPoint::Up:
238       case TouchPoint::Leave:
239       case TouchPoint::Interrupted:
240       {
241         mTimerForBubbleEmission.Stop();
242         break;
243       }
244       case TouchPoint::Stationary:
245       case TouchPoint::Last:
246       default:
247       {
248         break;
249       }
250
251     }
252     return true;
253   }
254
255   bool OnChangeIconClicked( Toolkit::Button button )
256   {
257     if(button == mChangeBackgroundButton)
258     {
259       mBackgroundImage = LoadStageFillingImage( BACKGROUND_IMAGES[ ++mCurrentBackgroundImageId % NUM_BACKGROUND_IMAGES  ] );
260
261       mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta );
262
263       mBackgroundActor.SetImage( mBackgroundImage );
264     }
265     else if( button == mChangeBubbleShapeButton )
266     {
267       mBubbleEmitter.SetShapeImage( ResourceImage::New( 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   Image                      mBackgroundImage;
290   ImageActor                 mBackgroundActor;
291
292   Toolkit::BubbleEmitter     mBubbleEmitter;
293   Vector3                    mHSVDelta;
294
295   Animation                  mEmitAnimation;
296   unsigned int               mAnimateComponentCount;
297   bool                       mNeedNewAnimation;
298
299   Timer                      mTimerForBubbleEmission;
300   unsigned int               mNonMovementCount;
301   unsigned int               mTimerInterval;
302
303   Vector2                    mCurrentTouchPosition;
304   Vector2                    mEmitPosition;
305
306   Toolkit::PushButton        mChangeBackgroundButton;
307   Toolkit::PushButton        mChangeBubbleShapeButton;
308   unsigned int               mCurrentBackgroundImageId;
309   unsigned int               mCurrentBubbleShapeImageId;
310 };
311
312 /*****************************************************************************/
313
314 static void
315 RunTest(Application& app)
316 {
317   BubbleEffectExample theApp(app);
318   app.MainLoop();
319 }
320
321 /*****************************************************************************/
322
323 int
324 main(int argc, char **argv)
325 {
326   Application app = Application::New(&argc, &argv);
327
328   RunTest(app);
329
330   return 0;
331 }
332
333
334