ItemView API to set the alpha function
[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 Flora License, Version 1.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://floralicense.org/license/
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 //CLASS HEADER
18 #include "bubble-emitter-impl.h"
19
20 //EXTERNAL INCLUDES
21 #include <cmath>
22
23 //INTERNAL INCLUDES
24 #include <dali-toolkit/public-api/shader-effects/bubble-effect/color-adjuster.h>
25
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
36                               Image shapeImage,
37                               unsigned int maximumNumberOfBubble,
38                               const Vector2& bubbleSizeRange )
39 : ControlImpl( true ),
40   mMovementArea( movementArea ),
41   mShapeImage( shapeImage ),
42   mTotalNumOfBubble( maximumNumberOfBubble ),
43   mBubbleSizeRange( bubbleSizeRange ),
44   mCurrentUniform( 0 ),
45   mDensity( 5 )
46 {
47 }
48
49 BubbleEmitter::~BubbleEmitter()
50 {
51 }
52
53 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
54                                            Image shapeImage,
55                                            unsigned int maximumNumberOfBubble,
56                                            const Vector2& bubbleSizeRange )
57 {
58   // Create the implementation
59    IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
60                                                             maximumNumberOfBubble,bubbleSizeRange ) );
61
62   // Pass ownership to Toolkit::BubbleEmitter handle
63   Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
64
65   //Second phase of implementeation : Initialization
66   internalBubbleEmitter->OnInitialize();
67
68   return bubbleEmitter;
69 }
70
71 void BubbleEmitter::OnInitialize()
72 {
73   // Create the root actor, all the meshActor should be its children
74   mBubbleRoot = Actor::New();
75   mBubbleRoot.SetSize(mMovementArea);
76
77   // Prepare the frame buffer to store the color adjusted background image
78   mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::Unused );
79
80   // Generate the material object, which is used by all meshActors
81   GenMaterial();
82
83   // Calculate how many BubbleEffect shaders are required
84   if( mTotalNumOfBubble>100 )
85   {
86     mNumBubblePerShader = 100;
87     mNumShader = mTotalNumOfBubble / 100;
88   }
89   else
90   {
91     mNumBubblePerShader = mTotalNumOfBubble;
92     mNumShader = 1;
93   }
94
95   mMesh.resize( mNumShader );
96   mMeshActor.resize( mNumShader );
97   mEffect.resize( mNumShader );
98
99   // Create the meshActor group and bubbleEffect group to emit bubbles following the given track, such as finger touch track.
100   MeshData meshData;
101   ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
102   for(unsigned int i=0; i < mNumShader; i++ )
103   {
104     mMesh[i] = Mesh::New( meshData );
105     mMeshActor[i] = MeshActor::New( mMesh[i] );
106     mMeshActor[i].SetAffectedByLighting( false );
107     mMeshActor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
108     mEffect[i] = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
109     mEffect[i].SetEffectImage( mEffectImage );
110     mEffect[i].SetMovementArea( mMovementArea );
111     mMeshActor[i].SetShaderEffect( mEffect[i] );
112     mBubbleRoot.Add( mMeshActor[i] );
113   }
114
115   // Create the extra meshActor and bubbleEffect to emit bubbles in totally random angle.
116   MeshData meshDataForNoise;
117   ConstructBubbleMesh( meshDataForNoise, mNumBubblePerShader);
118   mMeshActorForNoise = MeshActor::New( Mesh::New(meshDataForNoise) );
119   mMeshActorForNoise.SetAffectedByLighting( false );
120   mMeshActorForNoise.SetParentOrigin(ParentOrigin::TOP_LEFT);
121   mEffectForNoise = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
122   mEffectForNoise.SetMovementArea( mMovementArea );
123   mEffectForNoise.SetEffectImage( mEffectImage );
124   mMeshActorForNoise.SetShaderEffect( mEffectForNoise );
125   mBubbleRoot.Add( mMeshActorForNoise );
126
127   // Create a cameraActor for the off screen render task.
128   mCameraActor = CameraActor::New(mMovementArea);
129   mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
130   Stage::GetCurrent().Add(mCameraActor);
131 }
132
133 Actor BubbleEmitter::GetRootActor()
134 {
135   return mBubbleRoot;
136 }
137
138 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
139 {
140   ImageActor sourceActor = ImageActor::New( bgImage );
141   sourceActor.SetSize( mMovementArea );
142   sourceActor.SetParentOrigin(ParentOrigin::CENTER);
143   Stage::GetCurrent().Add( sourceActor );
144
145   ColorAdjuster colorAdjuster = ColorAdjuster::New( hsvDelta, true /*ignore alpha to make bubble color always*/ );
146   sourceActor.SetShaderEffect( colorAdjuster );
147
148   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
149   RenderTask task = taskList.CreateTask();
150   task.SetRefreshRate( RenderTask::REFRESH_ONCE );
151   task.SetSourceActor( sourceActor );
152   task.SetExclusive(true);
153   task.SetCameraActor(mCameraActor);
154   task.SetTargetFrameBuffer( mEffectImage );
155   task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
156 }
157
158 void BubbleEmitter::SetShapeImage( Image shapeImage )
159 {
160   mCustomMaterial.SetDiffuseTexture( shapeImage );
161
162   //Get pixel width of the shape
163   float width = Image::GetImageSize(shapeImage.GetFilename()).width;
164
165   for(unsigned int i=0; i < mNumShader; i++ )
166   {
167     mEffect[i].SetShapeImageWidth(width);
168   }
169   mEffectForNoise.SetShapeImageWidth(width);
170 }
171
172 void BubbleEmitter::SetBubbleScale( float scale )
173 {
174   for(unsigned int i=0; i < mNumShader; i++ )
175   {
176     mEffect[i].SetDynamicScale( scale );
177   }
178   mEffectForNoise.SetDynamicScale( scale );
179 }
180
181 void BubbleEmitter::SetBubbleDensity( unsigned int density )
182 {
183   DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
184
185   if( density == mDensity )
186   {
187     return;
188   }
189   else
190   {
191     mDensity = density;
192     MeshData meshData;
193     ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
194     for(unsigned int i=0; i < mNumShader; i++ )
195     {
196       mMesh[i].UpdateMeshData(meshData);
197     }
198   }
199 }
200
201 // clear the resources created for the off screen rendering
202 void BubbleEmitter::OnRenderFinished(RenderTask& source)
203 {
204   Actor sourceActor =  source.GetSourceActor();
205   sourceActor.RemoveShaderEffect();
206   Stage::GetCurrent().Remove(sourceActor);
207   sourceActor.Reset();
208   Stage::GetCurrent().GetRenderTaskList().RemoveTask(source);
209 }
210
211 void BubbleEmitter::SetBlendMode( bool enable )
212 {
213   if(enable)
214   {
215     for(unsigned int i=0; i < mNumShader; i++ )
216     {
217       // linear overlay
218       // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
219       mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
220                                  BlendingFactor::ZERO, BlendingFactor::ONE);
221     }
222     mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
223                                     BlendingFactor::ZERO, BlendingFactor::ONE);
224   }
225   else
226   {
227     for(unsigned int i=0; i < mNumShader; i++ )
228     {
229       // using default blend func
230       mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
231                                   BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
232     }
233     mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
234                                      BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
235   }
236 }
237
238 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
239 {
240   unsigned int curUniform = mCurrentUniform  % mNumBubblePerShader;
241   unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
242   SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
243   animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
244                        1.f, AlphaFunctions::Linear );
245
246   if( mCurrentUniform % mNumShader == 0 )
247   {
248     unsigned int uniform = mCurrentUniform / mNumShader;
249     SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
250     animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
251                          1.f, AlphaFunctions::Linear );
252   }
253
254   mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
255 }
256
257 void BubbleEmitter::StartExplosion( float duration, float multiple )
258 {
259   Animation animation = Animation::New( duration );
260   for(unsigned int i=0; i < mNumShader; i++ )
261   {
262     animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
263                          multiple, AlphaFunctions::EaseOut);
264   }
265   animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
266                        multiple, AlphaFunctions::EaseOut);
267   animation.Play();
268
269   animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
270 }
271
272 void BubbleEmitter::Restore()
273 {
274   for(unsigned int i=0; i < mNumShader; i++ )
275   {
276     mEffect[i].ResetParameters();
277   }
278   mEffectForNoise.ResetParameters();
279 }
280
281 void BubbleEmitter::GenMaterial()
282 {
283   mCustomMaterial = Material::New("CustomMaterial");
284   mCustomMaterial.SetOpacity(1.0f);
285   mCustomMaterial.SetDiffuseColor(Color::WHITE);
286   mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
287   mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
288   mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
289   mCustomMaterial.SetDiffuseTexture( mShapeImage );
290 }
291
292 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
293 {
294   MeshData::Vertex meshVertex;
295   meshVertex.x = XYZ.x;
296   meshVertex.y = XYZ.y;
297   meshVertex.z = XYZ.z;
298   meshVertex.u = UV.x;
299   meshVertex.v = UV.y;
300   vertices.push_back(meshVertex);
301 }
302
303 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
304 size_t v0, size_t v1, size_t v2)
305 {
306   faces.push_back(v0);
307   faces.push_back(v1);
308   faces.push_back(v2);
309 }
310
311 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
312 {
313   MeshData::VertexContainer    vertices;
314   MeshData::FaceIndices        faces;
315   BoneContainer                bones(0);
316
317   for(unsigned int index = 0; index < numOfBubble; index ++)
318   {
319     float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
320     if(rand()%100 < 1)
321     {
322       curSize *= 2.f;
323     }
324     float depth = static_cast<float>( index );
325     AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
326     AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
327     AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
328     AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
329
330     unsigned int idx = index * 4;
331     AddTriangle( faces, idx, idx+1, idx+2);
332     AddTriangle( faces, idx, idx+2, idx+3);
333   }
334
335   meshData.SetData(vertices, faces, bones, mCustomMaterial);
336   meshData.SetHasColor(false);
337   meshData.SetHasTextureCoords(true);
338 }
339
340 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
341                                         const Vector2& emitPosition, const Vector2& displacement )
342 {
343   int halfRange = displacement.x / 2;
344   Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
345   if(randomVec.y > 0.0f)
346   {
347     randomVec.y *= 0.33f;
348   }
349
350   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
351   effect.SetStartAndEndPosition( curUniform, startAndEndPos );
352
353   effect.SetPercentage( curUniform, 0.f);
354 }
355
356 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
357                                         const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
358 {
359   Vector2 dir(direction);
360
361   int halfRange = displacement.x / 2;
362   // for the y coordinate, always negative, so bubbles always go upwards
363   Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
364   dir.Normalize();
365   randomVec.x -= dir.x*halfRange;
366   randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
367
368   if(randomVec.y > 0.0f)
369   {
370     randomVec.y *= 0.33f;
371   }
372   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
373   effect.SetStartAndEndPosition( curUniform, startAndEndPos );
374
375   effect.SetPercentage( curUniform, 0.f);
376 }
377
378 void BubbleEmitter::OnExplosionFinished( Animation& source )
379 {
380   Restore();
381 }
382
383 float BubbleEmitter::RandomRange(float f0, float f1)
384 {
385   return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
386 }
387
388 } // namespace Internal
389
390 } // namespace Toolkit
391
392 } // namespace Dali