Merge "Text - Stop destroying the text renderer when text decoration is updated....
[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 <dali/public-api/animation/animation.h>
23 #include <dali/public-api/render-tasks/render-task-list.h>
24 #include <dali/public-api/images/resource-image.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/controls/bubble-effect/bubble-actor.h>
28 #include <dali-toolkit/internal/controls/bubble-effect/color-adjuster.h>
29 #include <dali-toolkit/internal/controls/bubble-effect/bubble-effect.h>
30 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
31
32
33 namespace
34 {
35 struct Vertex
36 {
37   Vertex()
38   : index( 0.0f ), position(), textureCoord()
39   {
40   }
41
42   Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
43   : index( index ), position( position ), textureCoord( textureCoord )
44   {
45   }
46
47   float index;
48   Dali::Vector2 position;
49   Dali::Vector2 textureCoord;
50 };
51
52 /**
53  * Return a random value between the given interval.
54  * @param[in] f0 The low bound
55  * @param[in] f1 The up bound
56  * @param[in] seed The seed to genergate random number
57  * @return A random value between the given interval
58  */
59 float RandomRange(float f0, float f1, unsigned int& seed)
60 {
61   return f0 + (rand_r( &seed ) & 0xfff) * (f1-f0) * (1.0f/4095.0f);
62 }
63
64 }
65
66 namespace Dali
67 {
68
69 namespace Toolkit
70 {
71
72 namespace Internal
73 {
74 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
75                               Image shapeImage,
76                               unsigned int maximumNumberOfBubble,
77                               const Vector2& bubbleSizeRange )
78 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
79   mShapeImage( shapeImage ),
80   mMovementArea( movementArea ),
81   mBubbleSizeRange( bubbleSizeRange ),
82   mDensity( 5 ),
83   mTotalNumOfBubble( maximumNumberOfBubble ),
84   mCurrentBubble( 0 ),
85   mRandomSeed( 0 ),
86   mRenderTaskRunning(false)
87 {
88   // Calculate how many shaders are required
89   if( mTotalNumOfBubble>100 )
90   {
91     mNumBubblePerActor = 100;
92     mNumActor = mTotalNumOfBubble / 100;
93     if( mNumActor*mNumBubblePerActor < mTotalNumOfBubble )
94     {
95       mNumActor++;
96       mNumBubblePerActor =  mTotalNumOfBubble / mNumActor+1;
97       mTotalNumOfBubble = mNumActor * mNumBubblePerActor;
98     }
99   }
100   else
101   {
102     mNumBubblePerActor = mTotalNumOfBubble;
103     mNumActor = 1;
104   }
105
106   mRandomSeed = time( NULL );
107 }
108
109 BubbleEmitter::~BubbleEmitter()
110 {
111 }
112
113 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
114                                            Image shapeImage,
115                                            unsigned int maximumNumberOfBubble,
116                                            const Vector2& bubbleSizeRange )
117 {
118   // Create the implementation
119    IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
120                                                             maximumNumberOfBubble,bubbleSizeRange ) );
121
122   // Pass ownership to Toolkit::BubbleEmitter handle
123   Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
124
125   //Second phase of implementeation : Initialization
126   internalBubbleEmitter->OnInitialize();
127
128   return bubbleEmitter;
129 }
130
131 void BubbleEmitter::OnInitialize()
132 {
133   // Create the root actor, all the meshActor should be its children
134   mBubbleRoot = Actor::New();
135   mBubbleRoot.SetSize(mMovementArea);
136
137   // Prepare the frame buffer to store the color adjusted background image
138   mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::UNUSED );
139
140   // Generate the geometry, which is used by all bubbleActors
141   mMeshGeometry =  CreateGeometry( mNumBubblePerActor*mDensity );
142
143   Shader bubbleShader = CreateBubbleShader (mNumBubblePerActor );
144
145   mTextureSet = TextureSet::New();
146   mTextureSet.SetImage( 0u, mEffectImage );
147   mTextureSet.SetImage( 1u, mShapeImage );
148
149   mBubbleActors.resize( mNumActor );
150
151   // Create the meshActor group and bubbleEffect group to emit bubbles following the given track, such as finger touch track.
152   for(unsigned int i=0; i < mNumActor; i++ )
153   {
154     mBubbleActors[i] = new BubbleActor( mNumBubblePerActor, mMovementArea );
155     (mBubbleActors[i])->MakeRenderable( mMeshGeometry, mTextureSet, bubbleShader );
156     mBubbleRoot.Add( (mBubbleActors[i])->GetMeshActor() );
157   }
158
159   // Create a cameraActor for the off screen render task.
160   mCameraActor = CameraActor::New(mMovementArea);
161   mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
162
163   Stage stage = Stage::GetCurrent();
164
165   stage.Add(mCameraActor);
166   stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
167 }
168
169 Actor BubbleEmitter::GetRootActor()
170 {
171   return mBubbleRoot;
172 }
173
174 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
175 {
176   mBackgroundImage = bgImage;
177   mHSVDelta = hsvDelta;
178
179   Toolkit::ImageView sourceActor = Toolkit::ImageView::New(bgImage);
180   sourceActor.SetSize( mMovementArea );
181   sourceActor.SetParentOrigin(ParentOrigin::CENTER);
182
183   Property::Map colorAdjuster = CreateColorAdjuster();
184   sourceActor.SetProperty( Toolkit::ImageView::Property::IMAGE, colorAdjuster);
185   SetColorAdjusterProperties( sourceActor, hsvDelta, true /*ignore alpha to make bubble color always*/ );
186
187   Stage::GetCurrent().Add( sourceActor );
188
189   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
190   RenderTask task = taskList.CreateTask();
191   task.SetRefreshRate( RenderTask::REFRESH_ONCE );
192   task.SetSourceActor( sourceActor );
193   task.SetExclusive(true);
194   task.SetCameraActor(mCameraActor);
195   task.GetCameraActor().SetInvertYAxis(true);
196   task.SetTargetFrameBuffer( mEffectImage );
197   task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
198   mRenderTaskRunning = true;
199 }
200
201 void BubbleEmitter::SetShapeImage( Image shapeImage )
202 {
203   mTextureSet.SetImage( 1, shapeImage );
204 }
205
206 void BubbleEmitter::SetBubbleScale( float scale )
207 {
208   for(unsigned int i=0; i < mNumActor; i++ )
209   {
210     (mBubbleActors[i])->SetDynamicScale( scale );
211   }
212 }
213
214 void BubbleEmitter::SetBubbleDensity( unsigned int density )
215 {
216   DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
217
218   if( density == mDensity )
219   {
220     return;
221   }
222   else
223   {
224     mDensity = density;
225     mMeshGeometry =  CreateGeometry( mNumBubblePerActor*mDensity );
226     for(unsigned int i=0; i < mNumActor; i++ )
227     {
228       (mBubbleActors[i])->SetGeometry( mMeshGeometry );
229     }
230   }
231 }
232
233 // clear the resources created for the off screen rendering
234 void BubbleEmitter::OnRenderFinished(RenderTask& source)
235 {
236   mRenderTaskRunning = false;
237   Actor sourceActor = source.GetSourceActor();
238   Stage stage = Stage::GetCurrent();
239   stage.Remove(sourceActor);
240   stage.GetRenderTaskList().RemoveTask(source);
241 }
242
243 void BubbleEmitter::OnContextRegained()
244 {
245   // Context was lost, so the framebuffer has been destroyed. Re-create render task
246   // and trigger re-draw if not already running
247   if( ! mRenderTaskRunning )
248   {
249     SetBackground( mBackgroundImage, mHSVDelta );
250   }
251 }
252
253 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
254 {
255   unsigned int curUniform = mCurrentBubble  % mNumBubblePerActor;
256   unsigned int groupIdx = mCurrentBubble / mNumBubblePerActor;
257   SetBubbleParameter( mBubbleActors[groupIdx], curUniform, emitPosition, direction, displacement);
258   animation.AnimateTo( (mBubbleActors[groupIdx])->GetPercentageProperty(curUniform),
259                        1.f, AlphaFunction::LINEAR );
260
261   mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
262 }
263
264 void BubbleEmitter::Restore()
265 {
266   for(unsigned int i=0; i < mNumActor; i++ )
267   {
268     (mBubbleActors[i])->ResetProperties();
269   }
270 }
271
272 Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
273 {
274   unsigned int numVertex = numOfPatch*4u;
275   std::vector<Vertex> vertexData;
276   vertexData.reserve( numVertex );
277
278   unsigned int numIndex = numOfPatch*6u;
279   Vector<unsigned short> indexData;
280   indexData.Reserve( numIndex );
281
282   for(unsigned int i = 0; i < numOfPatch; i++)
283   {
284     float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y, mRandomSeed);
285
286     float index = static_cast<float>( i );
287     vertexData.push_back( Vertex( index, Vector2(0.f,0.f),         Vector2(0.f,0.f) ) );
288     vertexData.push_back( Vertex( index, Vector2(0.f,curSize),     Vector2(0.f,1.f)  ) );
289     vertexData.push_back( Vertex( index, Vector2(curSize,curSize), Vector2(1.f,1.f)  ) );
290     vertexData.push_back( Vertex( index, Vector2(curSize,0.f),     Vector2(1.f,0.f)  ) );
291
292     unsigned short idx = index * 4;
293     indexData.PushBack( idx );
294     indexData.PushBack( idx+1 );
295     indexData.PushBack( idx+2 );
296     indexData.PushBack( idx );
297     indexData.PushBack( idx+2 );
298     indexData.PushBack( idx+3 );
299   }
300
301   Property::Map vertexFormat;
302   vertexFormat["aIndex"] = Property::FLOAT;
303   vertexFormat["aPosition"] = Property::VECTOR2;
304   vertexFormat["aTexCoord"] = Property::VECTOR2;
305   PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
306   vertices.SetData( &vertexData[0], numVertex );
307
308   Geometry geometry = Geometry::New();
309   geometry.AddVertexBuffer( vertices );
310   geometry.SetIndexBuffer( &indexData[0], numIndex );
311
312   return geometry;
313 }
314
315 void BubbleEmitter::SetBubbleParameter( BubbleActorPtr bubbleActor, unsigned int curUniform,
316                                         const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
317 {
318   Vector2 dir(direction);
319
320   int halfRange = displacement.x / 2;
321   // for the y coordinate, always negative, so bubbles always go upwards
322   Vector2 randomVec( rand_r( &mRandomSeed ) % static_cast<int>(displacement.x) - halfRange, -rand_r( &mRandomSeed ) % static_cast<int>(displacement.y) );
323   dir.Normalize();
324   randomVec.x -= dir.x*halfRange;
325   randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
326
327   if(randomVec.y > 0.0f)
328   {
329     randomVec.y *= 0.33f;
330   }
331   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
332   bubbleActor->SetStartAndEndPosition( curUniform, startAndEndPos );
333
334   bubbleActor->SetPercentage( curUniform, 0.f);
335 }
336
337 } // namespace Internal
338
339 } // namespace Toolkit
340
341 } // namespace Dali