808319124a00db151b256afc5ecfb0968de5bc3d
[platform/core/uifw/dali-toolkit.git] / optional / 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 : Control( 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.GetCameraActor().SetInvertYAxis(true);
155   task.SetTargetFrameBuffer( mEffectImage );
156   task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
157 }
158
159 void BubbleEmitter::SetShapeImage( Image shapeImage )
160 {
161   mCustomMaterial.SetDiffuseTexture( shapeImage );
162
163   //Get pixel width of the shape
164   float width = Image::GetImageSize(shapeImage.GetFilename()).width;
165
166   for(unsigned int i=0; i < mNumShader; i++ )
167   {
168     mEffect[i].SetShapeImageWidth(width);
169   }
170   mEffectForNoise.SetShapeImageWidth(width);
171 }
172
173 void BubbleEmitter::SetBubbleScale( float scale )
174 {
175   for(unsigned int i=0; i < mNumShader; i++ )
176   {
177     mEffect[i].SetDynamicScale( scale );
178   }
179   mEffectForNoise.SetDynamicScale( scale );
180 }
181
182 void BubbleEmitter::SetBubbleDensity( unsigned int density )
183 {
184   DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
185
186   if( density == mDensity )
187   {
188     return;
189   }
190   else
191   {
192     mDensity = density;
193     MeshData meshData;
194     ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
195     for(unsigned int i=0; i < mNumShader; i++ )
196     {
197       mMesh[i].UpdateMeshData(meshData);
198     }
199   }
200 }
201
202 // clear the resources created for the off screen rendering
203 void BubbleEmitter::OnRenderFinished(RenderTask& source)
204 {
205   Actor sourceActor =  source.GetSourceActor();
206   sourceActor.RemoveShaderEffect();
207   Stage::GetCurrent().Remove(sourceActor);
208   sourceActor.Reset();
209   Stage::GetCurrent().GetRenderTaskList().RemoveTask(source);
210 }
211
212 void BubbleEmitter::SetBlendMode( bool enable )
213 {
214   if(enable)
215   {
216     for(unsigned int i=0; i < mNumShader; i++ )
217     {
218       // linear overlay
219       // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
220       mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
221                                  BlendingFactor::ZERO, BlendingFactor::ONE);
222     }
223     mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
224                                     BlendingFactor::ZERO, BlendingFactor::ONE);
225   }
226   else
227   {
228     for(unsigned int i=0; i < mNumShader; i++ )
229     {
230       // using default blend func
231       mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
232                                   BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
233     }
234     mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
235                                      BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
236   }
237 }
238
239 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
240 {
241   unsigned int curUniform = mCurrentUniform  % mNumBubblePerShader;
242   unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
243   SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
244   animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
245                        1.f, AlphaFunctions::Linear );
246
247   if( mCurrentUniform % mNumShader == 0 )
248   {
249     unsigned int uniform = mCurrentUniform / mNumShader;
250     SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
251     animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
252                          1.f, AlphaFunctions::Linear );
253   }
254
255   mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
256 }
257
258 void BubbleEmitter::StartExplosion( float duration, float multiple )
259 {
260   Animation animation = Animation::New( duration );
261   for(unsigned int i=0; i < mNumShader; i++ )
262   {
263     animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
264                          multiple, AlphaFunctions::EaseOut);
265   }
266   animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
267                        multiple, AlphaFunctions::EaseOut);
268   animation.Play();
269
270   animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
271 }
272
273 void BubbleEmitter::Restore()
274 {
275   for(unsigned int i=0; i < mNumShader; i++ )
276   {
277     mEffect[i].ResetParameters();
278   }
279   mEffectForNoise.ResetParameters();
280 }
281
282 void BubbleEmitter::GenMaterial()
283 {
284   mCustomMaterial = Material::New("CustomMaterial");
285   mCustomMaterial.SetOpacity(1.0f);
286   mCustomMaterial.SetDiffuseColor(Color::WHITE);
287   mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
288   mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
289   mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
290   mCustomMaterial.SetDiffuseTexture( mShapeImage );
291 }
292
293 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
294 {
295   MeshData::Vertex meshVertex;
296   meshVertex.x = XYZ.x;
297   meshVertex.y = XYZ.y;
298   meshVertex.z = XYZ.z;
299   meshVertex.u = UV.x;
300   meshVertex.v = UV.y;
301   vertices.push_back(meshVertex);
302 }
303
304 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
305 size_t v0, size_t v1, size_t v2)
306 {
307   faces.push_back(v0);
308   faces.push_back(v1);
309   faces.push_back(v2);
310 }
311
312 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
313 {
314   MeshData::VertexContainer    vertices;
315   MeshData::FaceIndices        faces;
316   BoneContainer                bones(0);
317
318   for(unsigned int index = 0; index < numOfBubble; index ++)
319   {
320     float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
321     if(rand()%100 < 1)
322     {
323       curSize *= 2.f;
324     }
325     float depth = static_cast<float>( index );
326     AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
327     AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
328     AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
329     AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
330
331     unsigned int idx = index * 4;
332     AddTriangle( faces, idx, idx+1, idx+2);
333     AddTriangle( faces, idx, idx+2, idx+3);
334   }
335
336   meshData.SetData(vertices, faces, bones, mCustomMaterial);
337   meshData.SetHasColor(false);
338   meshData.SetHasTextureCoords(true);
339 }
340
341 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
342                                         const Vector2& emitPosition, const Vector2& displacement )
343 {
344   int halfRange = displacement.x / 2;
345   Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
346   if(randomVec.y > 0.0f)
347   {
348     randomVec.y *= 0.33f;
349   }
350
351   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
352   effect.SetStartAndEndPosition( curUniform, startAndEndPos );
353
354   effect.SetPercentage( curUniform, 0.f);
355 }
356
357 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
358                                         const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
359 {
360   Vector2 dir(direction);
361
362   int halfRange = displacement.x / 2;
363   // for the y coordinate, always negative, so bubbles always go upwards
364   Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
365   dir.Normalize();
366   randomVec.x -= dir.x*halfRange;
367   randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
368
369   if(randomVec.y > 0.0f)
370   {
371     randomVec.y *= 0.33f;
372   }
373   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
374   effect.SetStartAndEndPosition( curUniform, startAndEndPos );
375
376   effect.SetPercentage( curUniform, 0.f);
377 }
378
379 void BubbleEmitter::OnExplosionFinished( Animation& source )
380 {
381   Restore();
382 }
383
384 float BubbleEmitter::RandomRange(float f0, float f1)
385 {
386   return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
387 }
388
389 } // namespace Internal
390
391 } // namespace Toolkit
392
393 } // namespace Dali