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