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