92dca9f40542bb421bd7841a6ed87c056fdcc8d7
[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   sourceActor.RemoveShaderEffect();
208   Stage::GetCurrent().Remove(sourceActor);
209   sourceActor.Reset();
210   Stage::GetCurrent().GetRenderTaskList().RemoveTask(source);
211 }
212
213 void BubbleEmitter::SetBlendMode( bool enable )
214 {
215   if(enable)
216   {
217     for(unsigned int i=0; i < mNumShader; i++ )
218     {
219       // linear overlay
220       // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
221       mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
222                                  BlendingFactor::ZERO, BlendingFactor::ONE);
223     }
224     mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
225                                     BlendingFactor::ZERO, BlendingFactor::ONE);
226   }
227   else
228   {
229     for(unsigned int i=0; i < mNumShader; i++ )
230     {
231       // using default blend func
232       mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
233                                   BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
234     }
235     mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA,   BlendingFactor::ONE_MINUS_SRC_ALPHA,
236                                      BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
237   }
238 }
239
240 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
241 {
242   unsigned int curUniform = mCurrentUniform  % mNumBubblePerShader;
243   unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
244   SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
245   animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
246                        1.f, AlphaFunctions::Linear );
247
248   if( mCurrentUniform % mNumShader == 0 )
249   {
250     unsigned int uniform = mCurrentUniform / mNumShader;
251     SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
252     animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
253                          1.f, AlphaFunctions::Linear );
254   }
255
256   mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
257 }
258
259 void BubbleEmitter::StartExplosion( float duration, float multiple )
260 {
261   Animation animation = Animation::New( duration );
262   for(unsigned int i=0; i < mNumShader; i++ )
263   {
264     animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
265                          multiple, AlphaFunctions::EaseOut);
266   }
267   animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
268                        multiple, AlphaFunctions::EaseOut);
269   animation.Play();
270
271   animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
272 }
273
274 void BubbleEmitter::Restore()
275 {
276   for(unsigned int i=0; i < mNumShader; i++ )
277   {
278     mEffect[i].ResetParameters();
279   }
280   mEffectForNoise.ResetParameters();
281 }
282
283 void BubbleEmitter::GenMaterial()
284 {
285   mCustomMaterial = Material::New("CustomMaterial");
286   mCustomMaterial.SetOpacity(1.0f);
287   mCustomMaterial.SetDiffuseColor(Color::WHITE);
288   mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
289   mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
290   mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
291   mCustomMaterial.SetDiffuseTexture( mShapeImage );
292 }
293
294 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
295 {
296   MeshData::Vertex meshVertex;
297   meshVertex.x = XYZ.x;
298   meshVertex.y = XYZ.y;
299   meshVertex.z = XYZ.z;
300   meshVertex.u = UV.x;
301   meshVertex.v = UV.y;
302   vertices.push_back(meshVertex);
303 }
304
305 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
306 size_t v0, size_t v1, size_t v2)
307 {
308   faces.push_back(v0);
309   faces.push_back(v1);
310   faces.push_back(v2);
311 }
312
313 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
314 {
315   MeshData::VertexContainer    vertices;
316   MeshData::FaceIndices        faces;
317   BoneContainer                bones(0);
318
319   for(unsigned int index = 0; index < numOfBubble; index ++)
320   {
321     float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
322     if(rand()%100 < 1)
323     {
324       curSize *= 2.f;
325     }
326     float depth = static_cast<float>( index );
327     AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
328     AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
329     AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
330     AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
331
332     unsigned int idx = index * 4;
333     AddTriangle( faces, idx, idx+1, idx+2);
334     AddTriangle( faces, idx, idx+2, idx+3);
335   }
336
337   meshData.SetData(vertices, faces, bones, mCustomMaterial);
338   meshData.SetHasColor(false);
339   meshData.SetHasTextureCoords(true);
340 }
341
342 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
343                                         const Vector2& emitPosition, const Vector2& displacement )
344 {
345   int halfRange = displacement.x / 2;
346   Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
347   if(randomVec.y > 0.0f)
348   {
349     randomVec.y *= 0.33f;
350   }
351
352   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
353   effect.SetStartAndEndPosition( curUniform, startAndEndPos );
354
355   effect.SetPercentage( curUniform, 0.f);
356 }
357
358 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
359                                         const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
360 {
361   Vector2 dir(direction);
362
363   int halfRange = displacement.x / 2;
364   // for the y coordinate, always negative, so bubbles always go upwards
365   Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
366   dir.Normalize();
367   randomVec.x -= dir.x*halfRange;
368   randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
369
370   if(randomVec.y > 0.0f)
371   {
372     randomVec.y *= 0.33f;
373   }
374   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
375   effect.SetStartAndEndPosition( curUniform, startAndEndPos );
376
377   effect.SetPercentage( curUniform, 0.f);
378 }
379
380 void BubbleEmitter::OnExplosionFinished( Animation& source )
381 {
382   Restore();
383 }
384
385 float BubbleEmitter::RandomRange(float f0, float f1)
386 {
387   return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
388 }
389
390 } // namespace Internal
391
392 } // namespace Toolkit
393
394 } // namespace Dali