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