2 * Copyright (c) 2014 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"
23 #include <dali/public-api/animation/animation.h>
24 #include <dali/public-api/render-tasks/render-task-list.h>
27 #include <dali-toolkit/public-api/shader-effects/bubble-effect/color-adjuster.h>
37 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
39 unsigned int maximumNumberOfBubble,
40 const Vector2& bubbleSizeRange )
41 : Control( REQUIRES_TOUCH_EVENTS ),
42 mMovementArea( movementArea ),
43 mShapeImage( shapeImage ),
44 mTotalNumOfBubble( maximumNumberOfBubble ),
45 mRenderTaskRunning(false),
46 mBubbleSizeRange( bubbleSizeRange ),
50 // Calculate how many BubbleEffect shaders are required
51 if( mTotalNumOfBubble>100 )
53 mNumBubblePerShader = 100;
54 mNumShader = mTotalNumOfBubble / 100;
58 mNumBubblePerShader = mTotalNumOfBubble;
63 BubbleEmitter::~BubbleEmitter()
67 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
69 unsigned int maximumNumberOfBubble,
70 const Vector2& bubbleSizeRange )
72 // Create the implementation
73 IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
74 maximumNumberOfBubble,bubbleSizeRange ) );
76 // Pass ownership to Toolkit::BubbleEmitter handle
77 Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
79 //Second phase of implementeation : Initialization
80 internalBubbleEmitter->OnInitialize();
85 void BubbleEmitter::OnInitialize()
87 // Create the root actor, all the meshActor should be its children
88 mBubbleRoot = Actor::New();
89 mBubbleRoot.SetSize(mMovementArea);
91 // Prepare the frame buffer to store the color adjusted background image
92 mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::Unused );
94 // Generate the material object, which is used by all meshActors
97 mMesh.resize( mNumShader );
98 mMeshActor.resize( mNumShader );
99 mEffect.resize( mNumShader );
101 // Create the meshActor group and bubbleEffect group to emit bubbles following the given track, such as finger touch track.
103 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
104 for(unsigned int i=0; i < mNumShader; i++ )
106 mMesh[i] = Mesh::New( meshData );
107 mMeshActor[i] = MeshActor::New( mMesh[i] );
108 mMeshActor[i].SetAffectedByLighting( false );
109 mMeshActor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
110 mEffect[i] = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
111 mEffect[i].SetEffectImage( mEffectImage );
112 mEffect[i].SetMovementArea( mMovementArea );
113 mMeshActor[i].SetShaderEffect( mEffect[i] );
114 mBubbleRoot.Add( mMeshActor[i] );
117 // Create the extra meshActor and bubbleEffect to emit bubbles in totally random angle.
118 MeshData meshDataForNoise;
119 ConstructBubbleMesh( meshDataForNoise, mNumBubblePerShader);
120 mMeshActorForNoise = MeshActor::New( Mesh::New(meshDataForNoise) );
121 mMeshActorForNoise.SetAffectedByLighting( false );
122 mMeshActorForNoise.SetParentOrigin(ParentOrigin::TOP_LEFT);
123 mEffectForNoise = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
124 mEffectForNoise.SetMovementArea( mMovementArea );
125 mEffectForNoise.SetEffectImage( mEffectImage );
126 mMeshActorForNoise.SetShaderEffect( mEffectForNoise );
127 mBubbleRoot.Add( mMeshActorForNoise );
129 // Create a cameraActor for the off screen render task.
130 mCameraActor = CameraActor::New(mMovementArea);
131 mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
133 Stage stage = Stage::GetCurrent();
135 stage.Add(mCameraActor);
136 stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
139 Actor BubbleEmitter::GetRootActor()
144 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
146 mBackgroundImage = bgImage;
147 mHSVDelta = hsvDelta;
149 ImageActor sourceActor = ImageActor::New( bgImage );
150 sourceActor.SetSize( mMovementArea );
151 sourceActor.SetParentOrigin(ParentOrigin::CENTER);
152 Stage::GetCurrent().Add( sourceActor );
154 ColorAdjuster colorAdjuster = ColorAdjuster::New( hsvDelta, true /*ignore alpha to make bubble color always*/ );
155 sourceActor.SetShaderEffect( colorAdjuster );
157 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
158 RenderTask task = taskList.CreateTask();
159 task.SetRefreshRate( RenderTask::REFRESH_ONCE );
160 task.SetSourceActor( sourceActor );
161 task.SetExclusive(true);
162 task.SetCameraActor(mCameraActor);
163 task.GetCameraActor().SetInvertYAxis(true);
164 task.SetTargetFrameBuffer( mEffectImage );
165 task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
166 mRenderTaskRunning = true;
169 void BubbleEmitter::SetShapeImage( Image shapeImage )
171 mCustomMaterial.SetDiffuseTexture( shapeImage );
173 //Get pixel width of the shape
174 float width = Image::GetImageSize(shapeImage.GetFilename()).width;
176 for(unsigned int i=0; i < mNumShader; i++ )
178 mEffect[i].SetShapeImageWidth(width);
180 mEffectForNoise.SetShapeImageWidth(width);
183 void BubbleEmitter::SetBubbleScale( float scale )
185 for(unsigned int i=0; i < mNumShader; i++ )
187 mEffect[i].SetDynamicScale( scale );
189 mEffectForNoise.SetDynamicScale( scale );
192 void BubbleEmitter::SetBubbleDensity( unsigned int density )
194 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
196 if( density == mDensity )
204 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
205 for(unsigned int i=0; i < mNumShader; i++ )
207 mMesh[i].UpdateMeshData(meshData);
212 // clear the resources created for the off screen rendering
213 void BubbleEmitter::OnRenderFinished(RenderTask& source)
215 mRenderTaskRunning = false;
216 Actor sourceActor = source.GetSourceActor();
219 RenderableActor renderable = RenderableActor::DownCast( sourceActor );
222 renderable.RemoveShaderEffect();
226 Stage stage = Stage::GetCurrent();
227 stage.Remove(sourceActor);
228 stage.GetRenderTaskList().RemoveTask(source);
231 void BubbleEmitter::OnContextRegained()
233 // Context was lost, so the framebuffer has been destroyed. Re-create render task
234 // and trigger re-draw if not already running
235 if( ! mRenderTaskRunning )
237 SetBackground( mBackgroundImage, mHSVDelta );
241 void BubbleEmitter::SetBlendMode( bool enable )
245 for(unsigned int i=0; i < mNumShader; i++ )
248 // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
249 mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
250 BlendingFactor::ZERO, BlendingFactor::ONE);
252 mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
253 BlendingFactor::ZERO, BlendingFactor::ONE);
257 for(unsigned int i=0; i < mNumShader; i++ )
259 // using default blend func
260 mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
261 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
263 mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
264 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
268 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
270 unsigned int curUniform = mCurrentUniform % mNumBubblePerShader;
271 unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
272 SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
273 animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
274 1.f, AlphaFunctions::Linear );
276 if( mCurrentUniform % mNumShader == 0 )
278 unsigned int uniform = mCurrentUniform / mNumShader;
279 SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
280 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
281 1.f, AlphaFunctions::Linear );
284 mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
287 void BubbleEmitter::StartExplosion( float duration, float multiple )
289 Animation animation = Animation::New( duration );
290 for(unsigned int i=0; i < mNumShader; i++ )
292 animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
293 multiple, AlphaFunctions::EaseOut);
295 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
296 multiple, AlphaFunctions::EaseOut);
299 animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
302 void BubbleEmitter::Restore()
304 for(unsigned int i=0; i < mNumShader; i++ )
306 mEffect[i].ResetParameters();
308 mEffectForNoise.ResetParameters();
311 void BubbleEmitter::GenMaterial()
313 mCustomMaterial = Material::New("CustomMaterial");
314 mCustomMaterial.SetOpacity(1.0f);
315 mCustomMaterial.SetDiffuseColor(Color::WHITE);
316 mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
317 mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
318 mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
319 mCustomMaterial.SetDiffuseTexture( mShapeImage );
322 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
324 MeshData::Vertex meshVertex;
325 meshVertex.x = XYZ.x;
326 meshVertex.y = XYZ.y;
327 meshVertex.z = XYZ.z;
330 vertices.push_back(meshVertex);
333 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
334 size_t v0, size_t v1, size_t v2)
341 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
343 MeshData::VertexContainer vertices;
344 MeshData::FaceIndices faces;
345 BoneContainer bones(0);
347 for(unsigned int index = 0; index < numOfBubble; index ++)
349 float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
354 float depth = static_cast<float>( index );
355 AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
356 AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
357 AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
358 AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
360 unsigned int idx = index * 4;
361 AddTriangle( faces, idx, idx+1, idx+2);
362 AddTriangle( faces, idx, idx+2, idx+3);
365 meshData.SetData(vertices, faces, bones, mCustomMaterial);
366 meshData.SetHasColor(false);
367 meshData.SetHasTextureCoords(true);
370 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
371 const Vector2& emitPosition, const Vector2& displacement )
373 int halfRange = displacement.x / 2;
374 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
375 if(randomVec.y > 0.0f)
377 randomVec.y *= 0.33f;
380 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
381 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
383 effect.SetPercentage( curUniform, 0.f);
386 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
387 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
389 Vector2 dir(direction);
391 int halfRange = displacement.x / 2;
392 // for the y coordinate, always negative, so bubbles always go upwards
393 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
395 randomVec.x -= dir.x*halfRange;
396 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
398 if(randomVec.y > 0.0f)
400 randomVec.y *= 0.33f;
402 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
403 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
405 effect.SetPercentage( curUniform, 0.f);
408 void BubbleEmitter::OnExplosionFinished( Animation& source )
413 float BubbleEmitter::RandomRange(float f0, float f1)
415 return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
418 } // namespace Internal
420 } // namespace Toolkit