2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "bubble-emitter-impl.h"
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>
27 #include <dali/public-api/math/random.h>
30 #include <dali-toolkit/internal/controls/bubble-effect/bubble-effect.h>
31 #include <dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h>
38 : index( 0.0f ), position(), textureCoord()
42 Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
43 : index( index ), position( position ), textureCoord( textureCoord )
48 Dali::Vector2 position;
49 Dali::Vector2 textureCoord;
52 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
53 attribute mediump vec2 aPosition;\n
54 attribute mediump vec2 aTexCoord;\n
55 uniform mediump vec3 uSize;\n
56 uniform mediump mat4 uMvpMatrix;\n
57 varying mediump vec2 vTexCoord;\n
62 gl_Position = uMvpMatrix * vec4(aPosition*uSize.xy,0.0,1.0);
63 vTexCoord = aTexCoord;\n
67 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
68 precision highp float;\n
69 uniform vec3 uHSVDelta;\n
70 varying mediump vec2 vTexCoord;\n
71 uniform sampler2D sTexture;\n
72 float rand(vec2 co) \n
74 return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n}
76 vec3 rgb2hsv(vec3 c)\n
78 vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n
79 vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n
80 vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n
82 float d = q.x - min(q.w, q.y);\n
84 return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n
86 vec3 hsv2rgb(vec3 c)\n
88 vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n
89 vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n
90 return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n
93 vec4 color = texture2D(sTexture, vTexCoord); \n
94 vec3 hsvColor = rgb2hsv( color.rgb );\n
95 // modify the hsv Value
96 hsvColor += uHSVDelta * rand(vTexCoord); \n
97 // if the new vale exceeds one, then decrease it
98 hsvColor -= max(hsvColor*2.0 - vec3(2.0), 0.0);\n
99 // if the new vale drops below zero, then increase it
100 hsvColor -= min(hsvColor*2.0, 0.0);\n
101 color = vec4( hsv2rgb( hsvColor ), 1.0 ); \n
102 gl_FragColor = color; \n
106 Dali::Geometry CreateTexturedQuad()
110 Dali::Vector2 position;
111 Dali::Vector2 texCoord;
114 static const Vertex data[] = {{ Dali::Vector2( -0.5f, -0.5f ), Dali::Vector2( 0.0f, 0.0f ) },
115 { Dali::Vector2( 0.5f, -0.5f ), Dali::Vector2( 1.0f, 0.0f ) },
116 { Dali::Vector2( -0.5f, 0.5f ), Dali::Vector2( 0.0f, 1.0f ) },
117 { Dali::Vector2( 0.5f, 0.5f ), Dali::Vector2( 1.0f, 1.0f ) }};
119 //Create a vertex buffer for vertex positions and texture coordinates
120 Dali::PropertyBuffer vertexBuffer = Dali::PropertyBuffer::New( Dali::Property::Map()
121 .Add( "aPosition", Dali::Property::VECTOR2 )
122 .Add( "aTexCoord", Dali::Property::VECTOR2 ) );
123 vertexBuffer.SetData( data, 4u );
125 //Create the geometry
126 Dali::Geometry geometry = Dali::Geometry::New();
127 geometry.AddVertexBuffer( vertexBuffer );
128 geometry.SetType(Dali::Geometry::TRIANGLE_STRIP );
143 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
144 Texture shapeTexture,
145 unsigned int maximumNumberOfBubble,
146 const Vector2& bubbleSizeRange )
147 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
148 mShapeTexture( shapeTexture ),
149 mMovementArea( movementArea ),
150 mBubbleSizeRange( bubbleSizeRange ),
152 mTotalNumOfBubble( maximumNumberOfBubble ),
154 mRenderTaskRunning(false)
156 // Calculate how many shaders are required
157 if( mTotalNumOfBubble>100 )
159 mNumBubblePerRenderer = 100;
160 mNumRenderer = mTotalNumOfBubble / 100;
161 if( mNumRenderer*mNumBubblePerRenderer < mTotalNumOfBubble )
164 mNumBubblePerRenderer = mTotalNumOfBubble / mNumRenderer+1;
165 mTotalNumOfBubble = mNumRenderer * mNumBubblePerRenderer;
170 mNumBubblePerRenderer = mTotalNumOfBubble;
175 BubbleEmitter::~BubbleEmitter()
179 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
180 Texture shapeTexture,
181 unsigned int maximumNumberOfBubble,
182 const Vector2& bubbleSizeRange )
184 // Create the implementation
185 IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeTexture,
186 maximumNumberOfBubble,bubbleSizeRange ) );
188 // Pass ownership to Toolkit::BubbleEmitter handle
189 Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
191 //Second phase of implementeation : Initialization
192 internalBubbleEmitter->OnInitialize();
194 return bubbleEmitter;
197 void BubbleEmitter::OnInitialize()
199 // Create the root actor, all the meshActor should be its children
200 mBubbleRoot = Actor::New();
201 mBubbleRoot.SetSize(mMovementArea);
203 // Prepare the frame buffer to store the color adjusted background texture
204 Vector2 imageSize = Vector2( mMovementArea.width/4.f, mMovementArea.height/4.f );
205 mFrameBuffer = FrameBuffer::New( imageSize.x, imageSize.y, 0 );
206 mEffectTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, imageSize.x, imageSize.y );
207 mFrameBuffer.AttachColorTexture( mEffectTexture );
209 // Generate the geometry, which is used by all bubbleActors
210 mMeshGeometry = CreateGeometry( mNumBubblePerRenderer*mDensity );
212 Shader bubbleShader = CreateBubbleShader( mNumBubblePerRenderer );
214 mTextureSet = TextureSet::New();
215 mTextureSet.SetTexture( 0u, mEffectTexture );
216 mTextureSet.SetTexture( 1u, mShapeTexture );
218 // Create the renderers to render the bubbles
219 mBubbleRenderers.resize( mNumRenderer );
220 for(unsigned int i=0; i < mNumRenderer; i++ )
222 mBubbleRenderers[i].Initialize( mNumBubblePerRenderer, mMovementArea, mMeshGeometry, mTextureSet, bubbleShader );
223 mBubbleRoot.AddRenderer( mBubbleRenderers[i].GetRenderer() );
226 // Create a cameraActor for the off screen render task.
227 mCameraActor = CameraActor::New(mMovementArea);
228 mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
230 Stage stage = Stage::GetCurrent();
232 stage.Add(mCameraActor);
233 stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
236 Actor BubbleEmitter::GetRootActor()
241 void BubbleEmitter::SetBackground( Texture bgTexture, const Vector3& hsvDelta )
243 mBackgroundTexture = bgTexture;
244 mHSVDelta = hsvDelta;
246 //Create RenderTask source actor
247 Actor sourceActor = Actor::New();
248 sourceActor.SetSize( mMovementArea );
249 sourceActor.SetParentOrigin(ParentOrigin::CENTER);
250 sourceActor.RegisterProperty( "uHSVDelta", hsvDelta );
251 Stage::GetCurrent().Add( sourceActor );
254 Dali::Geometry geometry = CreateTexturedQuad();
255 Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
256 Renderer renderer = Renderer::New( geometry, shader );
257 TextureSet textureSet = TextureSet::New();
258 textureSet.SetTexture(0u, bgTexture );
259 renderer.SetTextures( textureSet );
260 sourceActor.AddRenderer( renderer );
262 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
263 RenderTask task = taskList.CreateTask();
264 task.SetRefreshRate( RenderTask::REFRESH_ONCE );
265 task.SetSourceActor( sourceActor );
266 task.SetExclusive(true);
267 task.SetCameraActor(mCameraActor);
268 task.GetCameraActor().SetInvertYAxis(true);
269 task.SetFrameBuffer( mFrameBuffer );
270 task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
271 mRenderTaskRunning = true;
274 void BubbleEmitter::SetBubbleShape( Texture shapeTexture )
276 mTextureSet.SetTexture( 1, shapeTexture );
279 void BubbleEmitter::SetBubbleScale( float scale )
281 for(unsigned int i=0; i < mNumRenderer; i++ )
283 mBubbleRenderers[i].SetDynamicScale( scale );
287 void BubbleEmitter::SetBubbleDensity( unsigned int density )
289 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
291 if( density == mDensity )
298 mMeshGeometry = CreateGeometry( mNumBubblePerRenderer*mDensity );
299 for(unsigned int i=0; i < mNumRenderer; i++ )
301 mBubbleRenderers[i].SetGeometry( mMeshGeometry );
306 // clear the resources created for the off screen rendering
307 void BubbleEmitter::OnRenderFinished(RenderTask& source)
309 mRenderTaskRunning = false;
310 Actor sourceActor = source.GetSourceActor();
311 Stage stage = Stage::GetCurrent();
312 stage.Remove(sourceActor);
313 stage.GetRenderTaskList().RemoveTask(source);
316 void BubbleEmitter::OnContextRegained()
318 // Context was lost, so the framebuffer has been destroyed. Re-create render task
319 // and trigger re-draw if not already running
320 if( ! mRenderTaskRunning )
322 SetBackground( mBackgroundTexture, mHSVDelta );
326 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
328 unsigned int curUniform = mCurrentBubble % mNumBubblePerRenderer;
329 unsigned int groupIdx = mCurrentBubble / mNumBubblePerRenderer;
330 SetBubbleParameter( mBubbleRenderers[groupIdx], curUniform, emitPosition - Vector2(mMovementArea.x*0.5f,mMovementArea.y*0.5f), direction, displacement);
331 animation.AnimateTo( mBubbleRenderers[groupIdx].GetPercentageProperty(curUniform),
332 1.f, AlphaFunction::LINEAR );
334 mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
337 void BubbleEmitter::Restore()
339 for(unsigned int i=0; i < mNumRenderer; i++ )
341 mBubbleRenderers[i].ResetProperties();
345 Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
347 unsigned int numVertex = numOfPatch*4u;
348 Vector<Vertex> vertexData;
349 vertexData.Reserve( numVertex );
351 unsigned int numIndex = numOfPatch*6u;
352 Vector<unsigned short> indexData;
353 indexData.Reserve( numIndex );
355 for(unsigned int i = 0; i < numOfPatch; i++)
357 float halfSize = Random::Range( mBubbleSizeRange.x, mBubbleSizeRange.y ) * 0.5f;
359 float index = static_cast<float>( i );
360 vertexData.PushBack( Vertex( index, Vector2(-halfSize,-halfSize),Vector2(0.f,0.f) ) );
361 vertexData.PushBack( Vertex( index, Vector2(-halfSize, halfSize), Vector2(0.f,1.f) ) );
362 vertexData.PushBack( Vertex( index, Vector2( halfSize, halfSize), Vector2(1.f,1.f) ) );
363 vertexData.PushBack( Vertex( index, Vector2( halfSize,-halfSize), Vector2(1.f,0.f) ) );
365 unsigned short idx = index * 4;
366 indexData.PushBack( idx );
367 indexData.PushBack( idx+1 );
368 indexData.PushBack( idx+2 );
369 indexData.PushBack( idx );
370 indexData.PushBack( idx+2 );
371 indexData.PushBack( idx+3 );
374 Property::Map vertexFormat;
375 vertexFormat["aIndex"] = Property::FLOAT;
376 vertexFormat["aPosition"] = Property::VECTOR2;
377 vertexFormat["aTexCoord"] = Property::VECTOR2;
378 PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
379 vertices.SetData( &vertexData[0], numVertex );
381 Geometry geometry = Geometry::New();
382 geometry.AddVertexBuffer( vertices );
383 geometry.SetIndexBuffer( &indexData[0], numIndex );
388 void BubbleEmitter::SetBubbleParameter( BubbleRenderer& bubbleRenderer, unsigned int curUniform,
389 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
391 Vector2 dir(direction);
393 int halfRange = displacement.x / 2;
394 // for the y coordinate, always negative, so bubbles always go upwards
395 Vector2 randomVec( rand() % static_cast<int>( displacement.x ) - halfRange, -rand() % static_cast<int>( displacement.y ) );
397 randomVec.x -= dir.x*halfRange;
398 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
400 if(randomVec.y > 0.0f)
402 randomVec.y *= 0.33f;
404 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
405 bubbleRenderer.SetStartAndEndPosition( curUniform, startAndEndPos );
407 bubbleRenderer.SetPercentage( curUniform, 0.f);
410 } // namespace Internal
412 } // namespace Toolkit