[Tizen] fixed SVACE issue about Windows Backend
[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/rendering/texture.h>
25 #include <dali/public-api/rendering/shader.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/internal/controls/bubble-effect/bubble-effect.h>
29 #include <dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h>
30
31 namespace
32 {
33 struct Vertex
34 {
35   Vertex()
36   : index( 0.0f ), position(), textureCoord()
37   {
38   }
39
40   Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
41   : index( index ), position( position ), textureCoord( textureCoord )
42   {
43   }
44
45   float index;
46   Dali::Vector2 position;
47   Dali::Vector2 textureCoord;
48 };
49
50
51 /**
52 * Return a random value between the given interval.
53 * @param[in] f0 The low bound
54 * @param[in] f1 The up bound
55 * @param[in] seed The seed to genergate random number
56 * @return A random value between the given interval
57 */
58 float RandomRange(float f0, float f1, unsigned int& seed)
59 {
60     return f0 + (rand_r(&seed) & 0xfff) * (f1 - f0) * (1.0f / 4095.0f);
61 }
62
63 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
64   attribute mediump vec2 aPosition;\n
65   attribute mediump vec2 aTexCoord;\n
66   uniform mediump vec3 uSize;\n
67   uniform mediump mat4 uMvpMatrix;\n
68   varying mediump vec2 vTexCoord;\n
69   \n
70
71   void main()\n
72   {\n
73     gl_Position = uMvpMatrix * vec4(aPosition*uSize.xy,0.0,1.0);
74     vTexCoord = aTexCoord;\n
75   }\n
76 );
77
78 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
79     precision highp float;\n
80     uniform vec3 uHSVDelta;\n
81     varying mediump vec2 vTexCoord;\n
82     uniform sampler2D sTexture;\n
83     float rand(vec2 co) \n
84     {\n
85       return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n}
86     \n
87     vec3 rgb2hsv(vec3 c)\n
88     {\n
89       vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n
90       vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n
91       vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n
92       \n
93       float d = q.x - min(q.w, q.y);\n
94       float e = 1.0e-10;\n
95       return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n
96     }\n
97     vec3 hsv2rgb(vec3 c)\n
98     {\n
99       vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n
100       vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n
101       return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n
102     }\n
103     void main() {\n
104       vec4 color = texture2D(sTexture, vTexCoord); \n
105       vec3 hsvColor = rgb2hsv( color.rgb );\n
106       // modify the hsv Value
107       hsvColor += uHSVDelta * rand(vTexCoord); \n
108       // if the new vale exceeds one, then decrease it
109       hsvColor -= max(hsvColor*2.0 - vec3(2.0), 0.0);\n
110       // if the new vale drops below zero, then increase it
111       hsvColor -= min(hsvColor*2.0, 0.0);\n
112       color = vec4( hsv2rgb( hsvColor ), 1.0 ); \n
113       gl_FragColor = color; \n
114     }\n
115   );
116
117 Dali::Geometry CreateTexturedQuad()
118 {
119   struct Vertex
120   {
121     Dali::Vector2 position;
122     Dali::Vector2 texCoord;
123   };
124
125   static const Vertex data[] = {{ Dali::Vector2( -0.5f, -0.5f ), Dali::Vector2( 0.0f, 0.0f ) },
126                                 { Dali::Vector2(  0.5f, -0.5f ), Dali::Vector2( 1.0f, 0.0f ) },
127                                 { Dali::Vector2( -0.5f,  0.5f ), Dali::Vector2( 0.0f, 1.0f ) },
128                                 { Dali::Vector2(  0.5f,  0.5f ), Dali::Vector2( 1.0f, 1.0f ) }};
129
130   //Create a vertex buffer for vertex positions and texture coordinates
131   Dali::PropertyBuffer vertexBuffer = Dali::PropertyBuffer::New( Dali::Property::Map()
132                                               .Add( "aPosition", Dali::Property::VECTOR2 )
133                                               .Add( "aTexCoord", Dali::Property::VECTOR2 ) );
134   vertexBuffer.SetData( data, 4u );
135
136   //Create the geometry
137   Dali::Geometry geometry = Dali::Geometry::New();
138   geometry.AddVertexBuffer( vertexBuffer );
139   geometry.SetType(Dali::Geometry::TRIANGLE_STRIP );
140
141   return geometry;
142 }
143
144 }
145
146 namespace Dali
147 {
148
149 namespace Toolkit
150 {
151
152 namespace Internal
153 {
154 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
155                               Texture shapeTexture,
156                               unsigned int maximumNumberOfBubble,
157                               const Vector2& bubbleSizeRange )
158 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
159   mShapeTexture( shapeTexture ),
160   mMovementArea( movementArea ),
161   mBubbleSizeRange( bubbleSizeRange ),
162   mDensity( 5 ),
163   mTotalNumOfBubble( maximumNumberOfBubble ),
164   mCurrentBubble( 0 ),
165   mRandomSeed( 0 ),
166   mRenderTaskRunning(false)
167 {
168   // Calculate how many shaders are required
169   if( mTotalNumOfBubble>100 )
170   {
171     mNumBubblePerRenderer = 100;
172     mNumRenderer = mTotalNumOfBubble / 100;
173     if( mNumRenderer*mNumBubblePerRenderer < mTotalNumOfBubble )
174     {
175       mNumRenderer++;
176       mNumBubblePerRenderer =  mTotalNumOfBubble / mNumRenderer+1;
177       mTotalNumOfBubble = mNumRenderer * mNumBubblePerRenderer;
178     }
179   }
180   else
181   {
182     mNumBubblePerRenderer = mTotalNumOfBubble;
183     mNumRenderer = 1;
184   }
185
186   mRandomSeed = time(NULL);
187 }
188
189 BubbleEmitter::~BubbleEmitter()
190 {
191 }
192
193 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
194                                            Texture shapeTexture,
195                                            unsigned int maximumNumberOfBubble,
196                                            const Vector2& bubbleSizeRange )
197 {
198   // Create the implementation
199    IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeTexture,
200                                                             maximumNumberOfBubble,bubbleSizeRange ) );
201
202   // Pass ownership to Toolkit::BubbleEmitter handle
203   Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
204
205   //Second phase of implementeation : Initialization
206   internalBubbleEmitter->OnInitialize();
207
208   return bubbleEmitter;
209 }
210
211 void BubbleEmitter::OnInitialize()
212 {
213   // Create the root actor, all the meshActor should be its children
214   mBubbleRoot = Actor::New();
215   mBubbleRoot.SetSize(mMovementArea);
216
217   // Prepare the frame buffer to store the color adjusted background texture
218   Vector2 imageSize = Vector2( mMovementArea.width/4.f, mMovementArea.height/4.f );
219   mFrameBuffer = FrameBuffer::New( imageSize.x, imageSize.y, 0 );
220   mEffectTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, imageSize.x, imageSize.y );
221   mFrameBuffer.AttachColorTexture( mEffectTexture );
222
223   // Generate the geometry, which is used by all bubbleActors
224   mMeshGeometry =  CreateGeometry( mNumBubblePerRenderer*mDensity );
225
226   Shader bubbleShader = CreateBubbleShader( mNumBubblePerRenderer );
227
228   mTextureSet = TextureSet::New();
229   mTextureSet.SetTexture( 0u, mEffectTexture );
230   mTextureSet.SetTexture( 1u, mShapeTexture );
231
232   // Create the renderers to render the bubbles
233   mBubbleRenderers.resize( mNumRenderer );
234   for(unsigned int i=0; i < mNumRenderer; i++ )
235   {
236     mBubbleRenderers[i].Initialize( mNumBubblePerRenderer, mMovementArea, mMeshGeometry, mTextureSet, bubbleShader );
237     mBubbleRoot.AddRenderer( mBubbleRenderers[i].GetRenderer() );
238   }
239
240   // Create a cameraActor for the off screen render task.
241   mCameraActor = CameraActor::New(mMovementArea);
242   mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
243
244   Stage stage = Stage::GetCurrent();
245
246   stage.Add(mCameraActor);
247   stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
248 }
249
250 Actor BubbleEmitter::GetRootActor()
251 {
252   return mBubbleRoot;
253 }
254
255 void BubbleEmitter::SetBackground( Texture bgTexture, const Vector3& hsvDelta )
256 {
257   mBackgroundTexture = bgTexture;
258   mHSVDelta = hsvDelta;
259
260   //Create RenderTask source actor
261   Actor sourceActor = Actor::New();
262   sourceActor.SetSize( mMovementArea );
263   sourceActor.SetParentOrigin(ParentOrigin::CENTER);
264   sourceActor.RegisterProperty( "uHSVDelta", hsvDelta );
265   Stage::GetCurrent().Add( sourceActor );
266
267   //Create renderer
268   Dali::Geometry geometry = CreateTexturedQuad();
269   Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
270   Renderer renderer = Renderer::New( geometry, shader );
271   TextureSet textureSet = TextureSet::New();
272   textureSet.SetTexture(0u, bgTexture );
273   renderer.SetTextures( textureSet );
274   sourceActor.AddRenderer( renderer );
275
276   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
277   RenderTask task = taskList.CreateTask();
278   task.SetRefreshRate( RenderTask::REFRESH_ONCE );
279   task.SetSourceActor( sourceActor );
280   task.SetExclusive(true);
281   task.SetCameraActor(mCameraActor);
282   task.GetCameraActor().SetInvertYAxis(true);
283   task.SetFrameBuffer( mFrameBuffer );
284   task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
285   mRenderTaskRunning = true;
286 }
287
288 void BubbleEmitter::SetBubbleShape( Texture shapeTexture )
289 {
290   mTextureSet.SetTexture( 1, shapeTexture );
291 }
292
293 void BubbleEmitter::SetBubbleScale( float scale )
294 {
295   for(unsigned int i=0; i < mNumRenderer; i++ )
296   {
297     mBubbleRenderers[i].SetDynamicScale( scale );
298   }
299 }
300
301 void BubbleEmitter::SetBubbleDensity( unsigned int density )
302 {
303   DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
304
305   if( density == mDensity )
306   {
307     return;
308   }
309   else
310   {
311     mDensity = density;
312     mMeshGeometry =  CreateGeometry( mNumBubblePerRenderer*mDensity );
313     for(unsigned int i=0; i < mNumRenderer; i++ )
314     {
315       mBubbleRenderers[i].SetGeometry( mMeshGeometry );
316     }
317   }
318 }
319
320 // clear the resources created for the off screen rendering
321 void BubbleEmitter::OnRenderFinished(RenderTask& source)
322 {
323   mRenderTaskRunning = false;
324   Actor sourceActor = source.GetSourceActor();
325   Stage stage = Stage::GetCurrent();
326   stage.Remove(sourceActor);
327   stage.GetRenderTaskList().RemoveTask(source);
328 }
329
330 void BubbleEmitter::OnContextRegained()
331 {
332   // Context was lost, so the framebuffer has been destroyed. Re-create render task
333   // and trigger re-draw if not already running
334   if( ! mRenderTaskRunning )
335   {
336     SetBackground( mBackgroundTexture, mHSVDelta );
337   }
338 }
339
340 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
341 {
342   unsigned int curUniform = mCurrentBubble  % mNumBubblePerRenderer;
343   unsigned int groupIdx = mCurrentBubble / mNumBubblePerRenderer;
344   SetBubbleParameter( mBubbleRenderers[groupIdx], curUniform, emitPosition - Vector2(mMovementArea.x*0.5f,mMovementArea.y*0.5f), direction, displacement);
345   animation.AnimateTo( mBubbleRenderers[groupIdx].GetPercentageProperty(curUniform),
346                        1.f, AlphaFunction::LINEAR );
347
348   mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
349 }
350
351 void BubbleEmitter::Restore()
352 {
353   for(unsigned int i=0; i < mNumRenderer; i++ )
354   {
355     mBubbleRenderers[i].ResetProperties();
356   }
357 }
358
359 Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
360 {
361   unsigned int numVertex = numOfPatch*4u;
362   Vector<Vertex> vertexData;
363   vertexData.Reserve( numVertex );
364
365   unsigned int numIndex = numOfPatch*6u;
366   Vector<unsigned short> indexData;
367   indexData.Reserve( numIndex );
368
369   for(unsigned int i = 0; i < numOfPatch; i++)
370   {
371     float halfSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y, mRandomSeed) * 0.5f;
372
373     float index = static_cast<float>( i );
374     vertexData.PushBack( Vertex( index, Vector2(-halfSize,-halfSize),Vector2(0.f,0.f) ) );
375     vertexData.PushBack( Vertex( index, Vector2(-halfSize, halfSize), Vector2(0.f,1.f) ) );
376     vertexData.PushBack( Vertex( index, Vector2( halfSize, halfSize),  Vector2(1.f,1.f) ) );
377     vertexData.PushBack( Vertex( index, Vector2( halfSize,-halfSize), Vector2(1.f,0.f) ) );
378
379     unsigned short idx = index * 4;
380     indexData.PushBack( idx );
381     indexData.PushBack( idx+1 );
382     indexData.PushBack( idx+2 );
383     indexData.PushBack( idx );
384     indexData.PushBack( idx+2 );
385     indexData.PushBack( idx+3 );
386   }
387
388   Property::Map vertexFormat;
389   vertexFormat["aIndex"] = Property::FLOAT;
390   vertexFormat["aPosition"] = Property::VECTOR2;
391   vertexFormat["aTexCoord"] = Property::VECTOR2;
392   PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
393   vertices.SetData( &vertexData[0], numVertex );
394
395   Geometry geometry = Geometry::New();
396   geometry.AddVertexBuffer( vertices );
397   geometry.SetIndexBuffer( &indexData[0], numIndex );
398
399   return geometry;
400 }
401
402 void BubbleEmitter::SetBubbleParameter( BubbleRenderer& bubbleRenderer, unsigned int curUniform,
403                                         const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
404 {
405   Vector2 dir(direction);
406
407   int halfRange = displacement.x / 2;
408   // for the y coordinate, always negative, so bubbles always go upwards
409   Vector2 randomVec(rand_r(&mRandomSeed) % static_cast<int>(displacement.x) - halfRange, -rand_r(&mRandomSeed) % static_cast<int>(displacement.y));
410   dir.Normalize();
411   randomVec.x -= dir.x*halfRange;
412   randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
413
414   if(randomVec.y > 0.0f)
415   {
416     randomVec.y *= 0.33f;
417   }
418   Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
419   bubbleRenderer.SetStartAndEndPosition( curUniform, startAndEndPos );
420
421   bubbleRenderer.SetPercentage( curUniform, 0.f);
422 }
423
424 } // namespace Internal
425
426 } // namespace Toolkit
427
428 } // namespace Dali