2 * Copyright (c) 2020 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>
28 #include <dali-toolkit/internal/controls/bubble-effect/bubble-effect.h>
29 #include <dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h>
30 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
37 : index( 0.0f ), position(), textureCoord()
41 Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
42 : index( index ), position( position ), textureCoord( textureCoord )
47 Dali::Vector2 position;
48 Dali::Vector2 textureCoord;
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
58 float RandomRange(float f0, float f1, unsigned int& seed)
60 return f0 + (rand_r( &seed ) & 0xfff) * (f1-f0) * (1.0f/4095.0f);
63 Dali::Geometry CreateTexturedQuad()
67 Dali::Vector2 position;
68 Dali::Vector2 texCoord;
71 static const Vertex data[] = {{ Dali::Vector2( -0.5f, -0.5f ), Dali::Vector2( 0.0f, 0.0f ) },
72 { Dali::Vector2( 0.5f, -0.5f ), Dali::Vector2( 1.0f, 0.0f ) },
73 { Dali::Vector2( -0.5f, 0.5f ), Dali::Vector2( 0.0f, 1.0f ) },
74 { Dali::Vector2( 0.5f, 0.5f ), Dali::Vector2( 1.0f, 1.0f ) }};
76 // Create a vertex buffer for vertex positions and texture coordinates
77 Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New( Dali::Property::Map()
78 .Add( "aPosition", Dali::Property::VECTOR2 )
79 .Add( "aTexCoord", Dali::Property::VECTOR2 ) );
80 vertexBuffer.SetData( data, 4u );
83 Dali::Geometry geometry = Dali::Geometry::New();
84 geometry.AddVertexBuffer( vertexBuffer );
85 geometry.SetType(Dali::Geometry::TRIANGLE_STRIP );
100 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
101 Texture shapeTexture,
102 unsigned int maximumNumberOfBubble,
103 const Vector2& bubbleSizeRange )
104 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
105 mShapeTexture( shapeTexture ),
106 mMovementArea( movementArea ),
107 mBubbleSizeRange( bubbleSizeRange ),
109 mTotalNumOfBubble( maximumNumberOfBubble ),
112 mRenderTaskRunning(false)
114 // Calculate how many shaders are required
115 if( mTotalNumOfBubble>100 )
117 mNumBubblePerRenderer = 100;
118 mNumRenderer = mTotalNumOfBubble / 100;
119 if( mNumRenderer*mNumBubblePerRenderer < mTotalNumOfBubble )
122 mNumBubblePerRenderer = mTotalNumOfBubble / mNumRenderer+1;
123 mTotalNumOfBubble = mNumRenderer * mNumBubblePerRenderer;
128 mNumBubblePerRenderer = mTotalNumOfBubble;
132 mRandomSeed = time( NULL );
135 BubbleEmitter::~BubbleEmitter()
139 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
140 Texture shapeTexture,
141 unsigned int maximumNumberOfBubble,
142 const Vector2& bubbleSizeRange )
144 // Create the implementation
145 IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeTexture,
146 maximumNumberOfBubble,bubbleSizeRange ) );
148 // Pass ownership to Toolkit::BubbleEmitter handle
149 Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
151 //Second phase of implementeation : Initialization
152 internalBubbleEmitter->OnInitialize();
154 return bubbleEmitter;
157 void BubbleEmitter::OnInitialize()
159 // Create the root actor, all the meshActor should be its children
160 mBubbleRoot = Actor::New();
161 mBubbleRoot.SetProperty( Actor::Property::SIZE, mMovementArea );
163 // Prepare the frame buffer to store the color adjusted background texture
164 Vector2 imageSize = Vector2( mMovementArea.width/4.f, mMovementArea.height/4.f );
165 mFrameBuffer = FrameBuffer::New( imageSize.x, imageSize.y, FrameBuffer::Attachment::NONE );
166 mEffectTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, imageSize.x, imageSize.y );
167 mFrameBuffer.AttachColorTexture( mEffectTexture );
169 // Generate the geometry, which is used by all bubbleActors
170 mMeshGeometry = CreateGeometry( mNumBubblePerRenderer*mDensity );
172 Shader bubbleShader = CreateBubbleShader( mNumBubblePerRenderer );
174 mTextureSet = TextureSet::New();
175 mTextureSet.SetTexture( 0u, mEffectTexture );
176 mTextureSet.SetTexture( 1u, mShapeTexture );
178 // Create the renderers to render the bubbles
179 mBubbleRenderers.resize( mNumRenderer );
180 for(unsigned int i=0; i < mNumRenderer; i++ )
182 mBubbleRenderers[i].Initialize( mNumBubblePerRenderer, mMovementArea, mMeshGeometry, mTextureSet, bubbleShader );
183 mBubbleRoot.AddRenderer( mBubbleRenderers[i].GetRenderer() );
186 // Create a cameraActor for the off screen render task.
187 mCameraActor = CameraActor::New(mMovementArea);
188 mCameraActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
190 Stage stage = Stage::GetCurrent();
192 stage.Add(mCameraActor);
193 stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
196 Actor BubbleEmitter::GetRootActor()
201 void BubbleEmitter::SetBackground( Texture bgTexture, const Vector3& hsvDelta )
203 mBackgroundTexture = bgTexture;
204 mHSVDelta = hsvDelta;
206 //Create RenderTask source actor
207 Actor sourceActor = Actor::New();
208 sourceActor.SetProperty( Actor::Property::SIZE, mMovementArea );
209 sourceActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
210 sourceActor.RegisterProperty( "uHSVDelta", hsvDelta );
211 Stage::GetCurrent().Add( sourceActor );
214 Dali::Geometry geometry = CreateTexturedQuad();
215 Shader shader = Shader::New( SHADER_BUBBLE_EMITTER_VERT, SHADER_BUBBLE_EMITTER_FRAG );
216 Renderer renderer = Renderer::New( geometry, shader );
217 TextureSet textureSet = TextureSet::New();
218 textureSet.SetTexture(0u, bgTexture );
219 renderer.SetTextures( textureSet );
220 sourceActor.AddRenderer( renderer );
222 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
223 RenderTask task = taskList.CreateTask();
224 task.SetRefreshRate( RenderTask::REFRESH_ONCE );
225 task.SetSourceActor( sourceActor );
226 task.SetExclusive(true);
227 task.SetCameraActor(mCameraActor);
228 task.GetCameraActor().SetInvertYAxis(true);
229 task.SetFrameBuffer( mFrameBuffer );
230 task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
231 mRenderTaskRunning = true;
234 void BubbleEmitter::SetBubbleShape( Texture shapeTexture )
236 mTextureSet.SetTexture( 1, shapeTexture );
239 void BubbleEmitter::SetBubbleScale( float scale )
241 for(unsigned int i=0; i < mNumRenderer; i++ )
243 mBubbleRenderers[i].SetDynamicScale( scale );
247 void BubbleEmitter::SetBubbleDensity( unsigned int density )
249 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
251 if( density == mDensity )
258 mMeshGeometry = CreateGeometry( mNumBubblePerRenderer*mDensity );
259 for(unsigned int i=0; i < mNumRenderer; i++ )
261 mBubbleRenderers[i].SetGeometry( mMeshGeometry );
266 // clear the resources created for the off screen rendering
267 void BubbleEmitter::OnRenderFinished(RenderTask& source)
269 mRenderTaskRunning = false;
270 Actor sourceActor = source.GetSourceActor();
271 Stage stage = Stage::GetCurrent();
272 stage.Remove(sourceActor);
273 stage.GetRenderTaskList().RemoveTask(source);
276 void BubbleEmitter::OnContextRegained()
278 // Context was lost, so the framebuffer has been destroyed. Re-create render task
279 // and trigger re-draw if not already running
280 if( ! mRenderTaskRunning )
282 SetBackground( mBackgroundTexture, mHSVDelta );
286 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
288 unsigned int curUniform = mCurrentBubble % mNumBubblePerRenderer;
289 unsigned int groupIdx = mCurrentBubble / mNumBubblePerRenderer;
290 SetBubbleParameter( mBubbleRenderers[groupIdx], curUniform, emitPosition - Vector2(mMovementArea.x*0.5f,mMovementArea.y*0.5f), direction, displacement);
291 animation.AnimateTo( mBubbleRenderers[groupIdx].GetPercentageProperty(curUniform),
292 1.f, AlphaFunction::LINEAR );
294 mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
297 void BubbleEmitter::Restore()
299 for(unsigned int i=0; i < mNumRenderer; i++ )
301 mBubbleRenderers[i].ResetProperties();
305 Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
307 unsigned int numVertex = numOfPatch*4u;
308 Vector<Vertex> vertexData;
309 vertexData.Reserve( numVertex );
311 unsigned int numIndex = numOfPatch*6u;
312 Vector<unsigned short> indexData;
313 indexData.Reserve( numIndex );
315 for(unsigned int i = 0; i < numOfPatch; i++)
317 float halfSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y, mRandomSeed) * 0.5f;
319 float index = static_cast<float>( i );
320 vertexData.PushBack( Vertex( index, Vector2(-halfSize,-halfSize),Vector2(0.f,0.f) ) );
321 vertexData.PushBack( Vertex( index, Vector2(-halfSize, halfSize), Vector2(0.f,1.f) ) );
322 vertexData.PushBack( Vertex( index, Vector2( halfSize, halfSize), Vector2(1.f,1.f) ) );
323 vertexData.PushBack( Vertex( index, Vector2( halfSize,-halfSize), Vector2(1.f,0.f) ) );
325 unsigned short idx = index * 4;
326 indexData.PushBack( idx );
327 indexData.PushBack( idx+1 );
328 indexData.PushBack( idx+2 );
329 indexData.PushBack( idx );
330 indexData.PushBack( idx+2 );
331 indexData.PushBack( idx+3 );
334 Property::Map vertexFormat;
335 vertexFormat["aIndex"] = Property::FLOAT;
336 vertexFormat["aPosition"] = Property::VECTOR2;
337 vertexFormat["aTexCoord"] = Property::VECTOR2;
338 VertexBuffer vertices = VertexBuffer::New( vertexFormat );
339 vertices.SetData( &vertexData[0], numVertex );
341 Geometry geometry = Geometry::New();
342 geometry.AddVertexBuffer( vertices );
343 geometry.SetIndexBuffer( &indexData[0], numIndex );
348 void BubbleEmitter::SetBubbleParameter( BubbleRenderer& bubbleRenderer, unsigned int curUniform,
349 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
351 Vector2 dir(direction);
353 int halfRange = displacement.x / 2;
354 // for the y coordinate, always negative, so bubbles always go upwards
355 Vector2 randomVec( rand_r( &mRandomSeed ) % static_cast<int>(displacement.x) - halfRange, -rand_r( &mRandomSeed ) % static_cast<int>(displacement.y) );
357 randomVec.x -= dir.x*halfRange;
358 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
360 if(randomVec.y > 0.0f)
362 randomVec.y *= 0.33f;
364 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
365 bubbleRenderer.SetStartAndEndPosition( curUniform, startAndEndPos );
367 bubbleRenderer.SetPercentage( curUniform, 0.f);
370 } // namespace Internal
372 } // namespace Toolkit