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/images/resource-image.h>
25 #include <dali/devel-api/images/texture-set-image.h>
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>
39 : index( 0.0f ), position(), textureCoord()
43 Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
44 : index( index ), position( position ), textureCoord( textureCoord )
49 Dali::Vector2 position;
50 Dali::Vector2 textureCoord;
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
60 float RandomRange(float f0, float f1, unsigned int& seed)
62 return f0 + (rand_r( &seed ) & 0xfff) * (f1-f0) * (1.0f/4095.0f);
75 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
77 unsigned int maximumNumberOfBubble,
78 const Vector2& bubbleSizeRange )
79 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
80 mShapeImage( shapeImage ),
81 mMovementArea( movementArea ),
82 mBubbleSizeRange( bubbleSizeRange ),
84 mTotalNumOfBubble( maximumNumberOfBubble ),
87 mRenderTaskRunning(false)
89 // Calculate how many shaders are required
90 if( mTotalNumOfBubble>100 )
92 mNumBubblePerActor = 100;
93 mNumActor = mTotalNumOfBubble / 100;
94 if( mNumActor*mNumBubblePerActor < mTotalNumOfBubble )
97 mNumBubblePerActor = mTotalNumOfBubble / mNumActor+1;
98 mTotalNumOfBubble = mNumActor * mNumBubblePerActor;
103 mNumBubblePerActor = mTotalNumOfBubble;
107 mRandomSeed = time( NULL );
110 BubbleEmitter::~BubbleEmitter()
114 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
116 unsigned int maximumNumberOfBubble,
117 const Vector2& bubbleSizeRange )
119 // Create the implementation
120 IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
121 maximumNumberOfBubble,bubbleSizeRange ) );
123 // Pass ownership to Toolkit::BubbleEmitter handle
124 Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
126 //Second phase of implementeation : Initialization
127 internalBubbleEmitter->OnInitialize();
129 return bubbleEmitter;
132 void BubbleEmitter::OnInitialize()
134 // Create the root actor, all the meshActor should be its children
135 mBubbleRoot = Actor::New();
136 mBubbleRoot.SetSize(mMovementArea);
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 );
141 // Generate the geometry, which is used by all bubbleActors
142 mMeshGeometry = CreateGeometry( mNumBubblePerActor*mDensity );
144 Shader bubbleShader = CreateBubbleShader (mNumBubblePerActor );
146 mTextureSet = TextureSet::New();
147 TextureSetImage( mTextureSet, 0u, mEffectImage );
148 TextureSetImage( mTextureSet, 1u, mShapeImage );
150 mBubbleActors.resize( mNumActor );
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++ )
155 mBubbleActors[i] = new BubbleActor( mNumBubblePerActor, mMovementArea );
156 (mBubbleActors[i])->MakeRenderable( mMeshGeometry, mTextureSet, bubbleShader );
157 mBubbleRoot.Add( (mBubbleActors[i])->GetMeshActor() );
160 // Create a cameraActor for the off screen render task.
161 mCameraActor = CameraActor::New(mMovementArea);
162 mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
164 Stage stage = Stage::GetCurrent();
166 stage.Add(mCameraActor);
167 stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
170 Actor BubbleEmitter::GetRootActor()
175 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
177 mBackgroundImage = bgImage;
178 mHSVDelta = hsvDelta;
180 Toolkit::ImageView sourceActor = Toolkit::ImageView::New(bgImage);
181 sourceActor.SetSize( mMovementArea );
182 sourceActor.SetParentOrigin(ParentOrigin::CENTER);
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*/ );
188 Stage::GetCurrent().Add( sourceActor );
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;
202 void BubbleEmitter::SetShapeImage( Image shapeImage )
204 TextureSetImage( mTextureSet, 1, shapeImage );
207 void BubbleEmitter::SetBubbleScale( float scale )
209 for(unsigned int i=0; i < mNumActor; i++ )
211 (mBubbleActors[i])->SetDynamicScale( scale );
215 void BubbleEmitter::SetBubbleDensity( unsigned int density )
217 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
219 if( density == mDensity )
226 mMeshGeometry = CreateGeometry( mNumBubblePerActor*mDensity );
227 for(unsigned int i=0; i < mNumActor; i++ )
229 (mBubbleActors[i])->SetGeometry( mMeshGeometry );
234 // clear the resources created for the off screen rendering
235 void BubbleEmitter::OnRenderFinished(RenderTask& source)
237 mRenderTaskRunning = false;
238 Actor sourceActor = source.GetSourceActor();
239 Stage stage = Stage::GetCurrent();
240 stage.Remove(sourceActor);
241 stage.GetRenderTaskList().RemoveTask(source);
244 void BubbleEmitter::OnContextRegained()
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 )
250 SetBackground( mBackgroundImage, mHSVDelta );
254 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
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 );
262 mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
265 void BubbleEmitter::Restore()
267 for(unsigned int i=0; i < mNumActor; i++ )
269 (mBubbleActors[i])->ResetProperties();
273 Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
275 unsigned int numVertex = numOfPatch*4u;
276 std::vector<Vertex> vertexData;
277 vertexData.reserve( numVertex );
279 unsigned int numIndex = numOfPatch*6u;
280 Vector<unsigned short> indexData;
281 indexData.Reserve( numIndex );
283 for(unsigned int i = 0; i < numOfPatch; i++)
285 float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y, mRandomSeed);
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) ) );
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 );
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 );
309 Geometry geometry = Geometry::New();
310 geometry.AddVertexBuffer( vertices );
311 geometry.SetIndexBuffer( &indexData[0], numIndex );
316 void BubbleEmitter::SetBubbleParameter( BubbleActorPtr bubbleActor, unsigned int curUniform,
317 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
319 Vector2 dir(direction);
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) );
325 randomVec.x -= dir.x*halfRange;
326 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
328 if(randomVec.y > 0.0f)
330 randomVec.y *= 0.33f;
332 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
333 bubbleActor->SetStartAndEndPosition( curUniform, startAndEndPos );
335 bubbleActor->SetPercentage( curUniform, 0.f);
338 } // namespace Internal
340 } // namespace Toolkit