Merge "Fix overshoot issue - not to make an overshoot actor twice" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / bubble-effect / bubble-emitter-impl.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 // CLASS HEADER
19 #include "bubble-emitter-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/animation.h>
23 #include <dali/public-api/render-tasks/render-task-list.h>
24 #include <dali/public-api/images/resource-image.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/controls/bubble-effect/bubble-actor.h>
28 #include <dali-toolkit/internal/controls/bubble-effect/color-adjuster.h>
29 #include <dali-toolkit/internal/controls/bubble-effect/bubble-effect.h>
30
31 namespace
32 {
33 struct Vertex
34 {
35   Vertex()
36   : index( 0.0f ), position(), textureCoord()
37   {
38   }
39
40   Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
41   : index( index ), position( position ), textureCoord( textureCoord )
42   {
43   }
44
45   float index;
46   Dali::Vector2 position;
47   Dali::Vector2 textureCoord;
48 };
49
50 /**
51  * Return a random value between the given interval.
52  * @param[in] f0 The low bound
53  * @param[in] f1 The up bound
54  * @param[in] seed The seed to genergate random number
55  * @return A random value between the given interval
56  */
57 float RandomRange(float f0, float f1, unsigned int& seed)
58 {
59   return f0 + (rand_r( &seed ) & 0xfff) * (f1-f0) * (1.0f/4095.0f);
60 }
61
62 }
63
64 namespace Dali
65 {
66
67 namespace Toolkit
68 {
69
70 namespace Internal
71 {
72 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
73                               Image shapeImage,
74                               unsigned int maximumNumberOfBubble,
75                               const Vector2& bubbleSizeRange )
76 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS ) ),
77   mShapeImage( shapeImage ),
78   mMovementArea( movementArea ),
79   mBubbleSizeRange( bubbleSizeRange ),
80   mDensity( 5 ),
81   mTotalNumOfBubble( maximumNumberOfBubble ),
82   mCurrentBubble( 0 ),
83   mRandomSeed( 0 ),
84   mRenderTaskRunning(false)
85 {
86   // Calculate how many shaders are required
87   if( mTotalNumOfBubble>100 )
88   {
89     mNumBubblePerActor = 100;
90     mNumActor = mTotalNumOfBubble / 100;
91     if( mNumActor*mNumBubblePerActor < mTotalNumOfBubble )
92     {
93       mNumActor++;
94       mNumBubblePerActor =  mTotalNumOfBubble / mNumActor+1;
95       mTotalNumOfBubble = mNumActor * mNumBubblePerActor;
96     }
97   }
98   else
99   {
100     mNumBubblePerActor = mTotalNumOfBubble;
101     mNumActor = 1;
102   }
103
104   mRandomSeed = time( NULL );
105 }
106
107 BubbleEmitter::~BubbleEmitter()
108 {
109 }
110
111 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
112                                            Image shapeImage,
113                                            unsigned int maximumNumberOfBubble,
114                                            const Vector2& bubbleSizeRange )
115 {
116   // Create the implementation
117    IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
118                                                             maximumNumberOfBubble,bubbleSizeRange ) );
119
120   // Pass ownership to Toolkit::BubbleEmitter handle
121   Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
122
123   //Second phase of implementeation : Initialization
124   internalBubbleEmitter->OnInitialize();
125
126   return bubbleEmitter;
127 }
128
129 void BubbleEmitter::OnInitialize()
130 {
131   // Create the root actor, all the meshActor should be its children
132   mBubbleRoot = Actor::New();
133   mBubbleRoot.SetSize(mMovementArea);
134
135   // Prepare the frame buffer to store the color adjusted background image
136   mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::UNUSED );
137
138   // Generate the geometry, which is used by all bubbleActors
139   mMeshGeometry =  CreateGeometry( mNumBubblePerActor*mDensity );
140
141   Shader bubbleShader = CreateBubbleShader (mNumBubblePerActor );
142
143   mMaterial = Material::New( bubbleShader );
144   mMaterial.AddTexture( mEffectImage, "sBackground" );
145   mMaterial.AddTexture( mShapeImage,  "sBubbleShape" );
146
147   mBubbleActors.resize( mNumActor );
148
149   // Create the meshActor group and bubbleEffect group to emit bubbles following the given track, such as finger touch track.
150   for(unsigned int i=0; i < mNumActor; i++ )
151   {
152     mBubbleActors[i] = new BubbleActor( mNumBubblePerActor, mMovementArea );
153     (mBubbleActors[i])->MakeRenderable( mMeshGeometry, mMaterial );
154     mBubbleRoot.Add( (mBubbleActors[i])->GetMeshActor() );
155   }
156
157   // Create a cameraActor for the off screen render task.
158   mCameraActor = CameraActor::New(mMovementArea);
159   mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
160
161   Stage stage = Stage::GetCurrent();
162
163   stage.Add(mCameraActor);
164   stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
165 }
166
167 Actor BubbleEmitter::GetRootActor()
168 {
169   return mBubbleRoot;
170 }
171
172 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
173 {
174   mBackgroundImage = bgImage;
175   mHSVDelta = hsvDelta;
176
177   ImageActor sourceActor = ImageActor::New( bgImage );
178   sourceActor.SetSize( mMovementArea );
179   sourceActor.SetParentOrigin(ParentOrigin::CENTER);
180   Stage::GetCurrent().Add( sourceActor );
181
182   ShaderEffect colorAdjuster = CreateColorAdjuster( hsvDelta, true /*ignore alpha to make bubble color always*/ );
183   sourceActor.SetShaderEffect( colorAdjuster );
184
185   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
186   RenderTask task = taskList.CreateTask();
187   task.SetRefreshRate( RenderTask::REFRESH_ONCE );
188   task.SetSourceActor( sourceActor );
189   task.SetExclusive(true);
190   task.SetCameraActor(mCameraActor);
191   task.GetCameraActor().SetInvertYAxis(true);
192   task.SetTargetFrameBuffer( mEffectImage );
193   task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
194   mRenderTaskRunning = true;
195 }
196
197 void BubbleEmitter::SetShapeImage( Image shapeImage )
198 {
199   mMaterial.SetTextureImage( 1, shapeImage );
200 }
201
202 void BubbleEmitter::SetBubbleScale( float scale )
203 {
204   for(unsigned int i=0; i < mNumActor; i++ )
205   {
206     (mBubbleActors[i])->SetDynamicScale( scale );
207   }
208 }
209
210 void BubbleEmitter::SetBubbleDensity( unsigned int density )
211 {
212   DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
213
214   if( density == mDensity )
215   {
216     return;
217   }
218   else
219   {
220     mDensity = density;
221     mMeshGeometry =  CreateGeometry( mNumBubblePerActor*mDensity );
222     for(unsigned int i=0; i < mNumActor; i++ )
223     {
224       (mBubbleActors[i])->SetGeometry( mMeshGeometry );
225     }
226   }
227 }
228
229 void BubbleEmitter::SetBlendMode( bool enable )
230 {
231   if(enable)
232   {
233     // linear overlay
234     mMaterial.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
235                            BlendingFactor::ZERO, BlendingFactor::ONE);
236   }
237   else
238   {
239     // using default blend func
240     mMaterial.SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
241                             BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
242   }
243 }
244
245 // clear the resources created for the off screen rendering
246 void BubbleEmitter::OnRenderFinished(RenderTask& source)
247 {
248   mRenderTaskRunning = false;
249   Actor sourceActor = source.GetSourceActor();
250   if( sourceActor )
251   {
252     ImageActor renderable = ImageActor::DownCast( sourceActor );
253     if( renderable )
254     {
255       renderable.RemoveShaderEffect();
256     }
257   }
258
259   Stage stage = Stage::GetCurrent();
260   stage.Remove(sourceActor);
261   stage.GetRenderTaskList().RemoveTask(source);
262 }
263
264 void BubbleEmitter::OnContextRegained()
265 {
266   // Context was lost, so the framebuffer has been destroyed. Re-create render task
267   // and trigger re-draw if not already running
268   if( ! mRenderTaskRunning )
269   {
270     SetBackground( mBackgroundImage, mHSVDelta );
271   }
272 }
273
274 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
275 {
276   unsigned int curUniform = mCurrentBubble  % mNumBubblePerActor;
277   unsigned int groupIdx = mCurrentBubble / mNumBubblePerActor;
278   SetBubbleParameter( mBubbleActors[groupIdx], curUniform, emitPosition, direction, displacement);
279   animation.AnimateTo( (mBubbleActors[groupIdx])->GetPercentageProperty(curUniform),
280                        1.f, AlphaFunction::LINEAR );
281
282   mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
283 }
284
285 void BubbleEmitter::Restore()
286 {
287   for(unsigned int i=0; i < mNumActor; i++ )
288   {
289     (mBubbleActors[i])->ResetProperties();
290   }
291 }
292
293 Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
294 {
295   unsigned int numVertex = numOfPatch*4u;
296   std::vector<Vertex> vertexData;
297   vertexData.reserve( numVertex );
298
299   unsigned int numIndex = numOfPatch*6u;
300   Vector<unsigned int> indexData;
301   indexData.Reserve( numIndex );
302
303   for(unsigned int i = 0; i < numOfPatch; i++)
304   {
305     float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y, mRandomSeed);
306
307     float index = static_cast<float>( i );
308     vertexData.push_back( Vertex( index, Vector2(0.f,0.f),         Vector2(0.f,0.f) ) );
309     vertexData.push_back( Vertex( index, Vector2(0.f,curSize),     Vector2(0.f,1.f)  ) );
310     vertexData.push_back( Vertex( index, Vector2(curSize,curSize), Vector2(1.f,1.f)  ) );
311     vertexData.push_back( Vertex( index, Vector2(curSize,0.f),     Vector2(1.f,0.f)  ) );
312
313     unsigned int idx = index * 4;
314     indexData.PushBack( idx );
315     indexData.PushBack( idx+1 );
316     indexData.PushBack( idx+2 );
317     indexData.PushBack( idx );
318     indexData.PushBack( idx+2 );
319     indexData.PushBack( idx+3 );
320   }
321
322   Property::Map vertexFormat;
323   vertexFormat["aIndex"] = Property::FLOAT;
324   vertexFormat["aPosition"] = Property::VECTOR2;
325   vertexFormat["aTexCoord"] = Property::VECTOR2;
326   PropertyBuffer vertices = PropertyBuffer::New( vertexFormat, numVertex  );
327   vertices.SetData( &vertexData[0] );
328
329   Property::Map indexFormat;
330   indexFormat["indices"] = Property::INTEGER;
331   PropertyBuffer indices = PropertyBuffer::New( indexFormat, numIndex  );
332   indices.SetData( &indexData[0] );
333
334   Geometry geometry = Geometry::New();
335   geometry.AddVertexBuffer( vertices );
336   geometry.SetIndexBuffer( indices );
337
338   return geometry;
339 }
340
341 void BubbleEmitter::SetBubbleParameter( BubbleActorPtr bubbleActor, unsigned int curUniform,
342                                         const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
343 {
344   Vector2 dir(direction);
345
346   int halfRange = displacement.x / 2;
347   // for the y coordinate, always negative, so bubbles always go upwards
348   Vector2 randomVec( rand_r( &mRandomSeed ) % static_cast<int>(displacement.x) - halfRange, -rand_r( &mRandomSeed ) % static_cast<int>(displacement.y) );
349   dir.Normalize();
350   randomVec.x -= dir.x*halfRange;
351   randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
352
353   if(randomVec.y > 0.0f)
354   {
355     randomVec.y *= 0.33f;
356   }
357   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
358   bubbleActor->SetStartAndEndPosition( curUniform, startAndEndPos );
359
360   bubbleActor->SetPercentage( curUniform, 0.f);
361 }
362
363 } // namespace Internal
364
365 } // namespace Toolkit
366
367 } // namespace Dali