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