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     Stage stage = Stage::GetCurrent();
99     Vector2 stageSize = stage.GetSize();
100
101     stage.KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent);
102
103     // Creates a default view with a default tool bar.
104     // The view is added to the stage.
105     Toolkit::ToolBar toolBar;
106     Toolkit::View    view;
107     Layer content = DemoHelper::CreateView( app,
108                                             view,
109                                             toolBar,
110                                             "",
111                                             TOOLBAR_IMAGE,
112                                             APPLICATION_TITLE );
113
114     // Add a button to change background. (right of toolbar)
115     mChangeBackgroundButton = Toolkit::PushButton::New();
116     mChangeBackgroundButton.SetBackgroundImage( ResourceImage::New( CHANGE_BACKGROUND_ICON ) );
117     mChangeBackgroundButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked );
118     toolBar.AddControl( mChangeBackgroundButton,
119                         DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
120                         Toolkit::Alignment::HorizontalRight,
121                         DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
122     // Add a button to change bubble shape. ( left of bar )
123     mChangeBubbleShapeButton = Toolkit::PushButton::New();
124     mChangeBubbleShapeButton.SetBackgroundImage( ResourceImage::New( CHANGE_BUBBLE_SHAPE_ICON ) );
125     mChangeBubbleShapeButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked );
126     toolBar.AddControl( mChangeBubbleShapeButton,
127                         DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
128                         Toolkit::Alignment::HorizontalLeft,
129                         DemoHelper::DEFAULT_MODE_SWITCH_PADDING  );
130
131     // Create and initialize the BubbleEmitter object
132     mBubbleEmitter = Toolkit::BubbleEmitter::New( stageSize,
133                                                   ResourceImage::New( BUBBLE_SHAPE_IMAGES[mCurrentBubbleShapeImageId] ),
134                                                   DEFAULT_NUMBER_OF_BUBBLES,
135                                                   DEFAULT_BUBBLE_SIZE);
136     mBackgroundImage = LoadStageFillingImage( BACKGROUND_IMAGES[mCurrentBackgroundImageId] );
137     mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta );
138
139     // Get the root actor of all bubbles, and add it to stage.
140     Actor bubbleRoot = mBubbleEmitter.GetRootActor();
141     bubbleRoot.SetParentOrigin(ParentOrigin::CENTER);
142     bubbleRoot.SetZ(0.1f); // Make sure the bubbles displayed on top og the background.
143     content.Add( bubbleRoot );
144
145     // Add the background image actor to stage
146     mBackgroundActor = ImageActor::New( mBackgroundImage );
147     view.SetBackground( mBackgroundActor );
148
149     // Set up the timer to emit bubble regularly when the finger is touched down but not moved
150     mTimerForBubbleEmission = Timer::New( mTimerInterval );
151     mTimerForBubbleEmission.TickSignal().Connect(this, &BubbleEffectExample::OnTimerTick);
152
153     // Connect the callback to the touch signal on the background
154     mBackgroundActor.TouchedSignal().Connect( this, &BubbleEffectExample::OnTouch );
155   }
156
157
158 /***********
159  * Emit bubbles
160  *****************/
161
162   // Set up the animation of emitting bubbles, to be efficient, every animation controls multiple bubbles ( 4 here )
163   void SetUpAnimation( Vector2 emitPosition, Vector2 direction )
164   {
165     if( mNeedNewAnimation )
166     {
167       float duration = Random::Range(1.f, 1.5f);
168       mEmitAnimation = Animation::New( duration );
169       mNeedNewAnimation = false;
170       mAnimateComponentCount = 0;
171     }
172
173     mBubbleEmitter.EmitBubble( mEmitAnimation, emitPosition, direction + Vector2(0.f, 30.f) /* upwards */, Vector2(300, 600) );
174
175     mAnimateComponentCount++;
176
177     if( mAnimateComponentCount % 4 ==0 )
178     {
179       mEmitAnimation.Play();
180       mNeedNewAnimation = true;
181     }
182   }
183
184   // Emit bubbles when the finger touches down but keep stationary.
185   // And stops emitting new bubble after being stationary for 2 seconds
186   bool OnTimerTick()
187   {
188     if(mEmitPosition == mCurrentTouchPosition) // finger is not moving
189     {
190       mNonMovementCount++;
191       if(mNonMovementCount < (1000 / mTimerInterval)) // 1 seconds
192       {
193         for(int i = 0; i < 4; i++) // emit 4 bubbles every timer tick
194         {
195           SetUpAnimation( mCurrentTouchPosition+Vector2(rand()%5, rand()%5), Vector2(rand()%60-30, rand()%100-50) );
196         }
197       }
198     }
199     else
200     {
201       mNonMovementCount = 0;
202       mEmitPosition = mCurrentTouchPosition;
203     }
204
205     return true;
206   }
207
208   // Callback function of the touch signal on the background
209   bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event)
210   {
211     const TouchPoint &point = event.GetPoint(0);
212     switch(point.state)
213     {
214       case TouchPoint::Down:
215       {
216         mCurrentTouchPosition = point.screen;
217         mEmitPosition = point.screen;
218         mTimerForBubbleEmission.Start();
219         mNonMovementCount = 0;
220
221         break;
222       }
223       case TouchPoint::Motion:
224       {
225         Vector2 displacement = point.screen - mCurrentTouchPosition;
226         mCurrentTouchPosition = point.screen;
227         //emit multiple bubbles along the moving direction when the finger moves quickly
228         float step = std::min(5.f, displacement.Length());
229         for( float i=0.25f; i<step; i=i+1.f)
230         {
231           SetUpAnimation( mCurrentTouchPosition+displacement*(i/step), displacement );
232         }
233         break;
234       }
235       case TouchPoint::Up:
236       case TouchPoint::Leave:
237       case TouchPoint::Interrupted:
238       {
239         mTimerForBubbleEmission.Stop();
240         break;
241       }
242       case TouchPoint::Stationary:
243       case TouchPoint::Last:
244       default:
245       {
246         break;
247       }
248
249     }
250     return true;
251   }
252
253   bool OnChangeIconClicked( Toolkit::Button button )
254   {
255     if(button == mChangeBackgroundButton)
256     {
257       mBackgroundImage = LoadStageFillingImage( BACKGROUND_IMAGES[ ++mCurrentBackgroundImageId % NUM_BACKGROUND_IMAGES  ] );
258
259       mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta );
260
261       mBackgroundActor.SetImage( mBackgroundImage );
262     }
263     else if( button == mChangeBubbleShapeButton )
264     {
265       mBubbleEmitter.SetShapeImage( ResourceImage::New( BUBBLE_SHAPE_IMAGES[ ++mCurrentBubbleShapeImageId % NUM_BUBBLE_SHAPE_IMAGES ] ) );
266     }
267     return true;
268   }
269
270   /**
271    * Main key event handler
272    */
273   void OnKeyEvent(const KeyEvent& event)
274   {
275     if(event.state == KeyEvent::Down)
276     {
277       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
278       {
279         mApp.Quit();
280       }
281     }
282   }
283
284 private:
285
286   Application&               mApp;
287   Image                      mBackgroundImage;
288   ImageActor                 mBackgroundActor;
289
290   Toolkit::BubbleEmitter     mBubbleEmitter;
291   Vector3                    mHSVDelta;
292
293   Animation                  mEmitAnimation;
294   unsigned int               mAnimateComponentCount;
295   bool                       mNeedNewAnimation;
296
297   Timer                      mTimerForBubbleEmission;
298   unsigned int               mNonMovementCount;
299   unsigned int               mTimerInterval;
300
301   Vector2                    mCurrentTouchPosition;
302   Vector2                    mEmitPosition;
303
304   Toolkit::PushButton        mChangeBackgroundButton;
305   Toolkit::PushButton        mChangeBubbleShapeButton;
306   unsigned int               mCurrentBackgroundImageId;
307   unsigned int               mCurrentBubbleShapeImageId;
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
322 main(int argc, char **argv)
323 {
324   Application app = Application::New(&argc, &argv);
325
326   RunTest(app);
327
328   return 0;
329 }
330
331
332