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