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