2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include "bubble-emitter-impl.h"
24 #include <dali-toolkit/public-api/shader-effects/bubble-effect/color-adjuster.h>
35 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
37 unsigned int maximumNumberOfBubble,
38 const Vector2& bubbleSizeRange )
39 : ControlImpl( true ),
40 mMovementArea( movementArea ),
41 mShapeImage( shapeImage ),
42 mTotalNumOfBubble( maximumNumberOfBubble ),
43 mBubbleSizeRange( bubbleSizeRange ),
49 BubbleEmitter::~BubbleEmitter()
53 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
55 unsigned int maximumNumberOfBubble,
56 const Vector2& bubbleSizeRange )
58 // Create the implementation
59 IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
60 maximumNumberOfBubble,bubbleSizeRange ) );
62 // Pass ownership to Toolkit::BubbleEmitter handle
63 Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
65 //Second phase of implementeation : Initialization
66 internalBubbleEmitter->OnInitialize();
71 void BubbleEmitter::OnInitialize()
73 // Create the root actor, all the meshActor should be its children
74 mBubbleRoot = Actor::New();
75 mBubbleRoot.SetSize(mMovementArea);
77 // Prepare the frame buffer to store the color adjusted background image
78 mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::Unused );
80 // Generate the material object, which is used by all meshActors
83 // Calculate how many BubbleEffect shaders are required
84 if( mTotalNumOfBubble>100 )
86 mNumBubblePerShader = 100;
87 mNumShader = mTotalNumOfBubble / 100;
91 mNumBubblePerShader = mTotalNumOfBubble;
95 mMesh.resize( mNumShader );
96 mMeshActor.resize( mNumShader );
97 mEffect.resize( mNumShader );
99 // Create the meshActor group and bubbleEffect group to emit bubbles following the given track, such as finger touch track.
101 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
102 for(unsigned int i=0; i < mNumShader; i++ )
104 mMesh[i] = Mesh::New( meshData );
105 mMeshActor[i] = MeshActor::New( mMesh[i] );
106 mMeshActor[i].SetAffectedByLighting( false );
107 mMeshActor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
108 mEffect[i] = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
109 mEffect[i].SetEffectImage( mEffectImage );
110 mEffect[i].SetMovementArea( mMovementArea );
111 mMeshActor[i].SetShaderEffect( mEffect[i] );
112 mBubbleRoot.Add( mMeshActor[i] );
115 // Create the extra meshActor and bubbleEffect to emit bubbles in totally random angle.
116 MeshData meshDataForNoise;
117 ConstructBubbleMesh( meshDataForNoise, mNumBubblePerShader);
118 mMeshActorForNoise = MeshActor::New( Mesh::New(meshDataForNoise) );
119 mMeshActorForNoise.SetAffectedByLighting( false );
120 mMeshActorForNoise.SetParentOrigin(ParentOrigin::TOP_LEFT);
121 mEffectForNoise = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
122 mEffectForNoise.SetMovementArea( mMovementArea );
123 mEffectForNoise.SetEffectImage( mEffectImage );
124 mMeshActorForNoise.SetShaderEffect( mEffectForNoise );
125 mBubbleRoot.Add( mMeshActorForNoise );
127 // Create a cameraActor for the off screen render task.
128 mCameraActor = CameraActor::New(mMovementArea);
129 mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
130 Stage::GetCurrent().Add(mCameraActor);
133 Actor BubbleEmitter::GetRootActor()
138 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
140 ImageActor sourceActor = ImageActor::New( bgImage );
141 sourceActor.SetSize( mMovementArea );
142 sourceActor.SetParentOrigin(ParentOrigin::CENTER);
143 Stage::GetCurrent().Add( sourceActor );
145 ColorAdjuster colorAdjuster = ColorAdjuster::New( hsvDelta, true /*ignore alpha to make bubble color always*/ );
146 sourceActor.SetShaderEffect( colorAdjuster );
148 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
149 RenderTask task = taskList.CreateTask();
150 task.SetRefreshRate( RenderTask::REFRESH_ONCE );
151 task.SetSourceActor( sourceActor );
152 task.SetExclusive(true);
153 task.SetCameraActor(mCameraActor);
154 task.GetCameraActor().SetInvertYAxis(true);
155 task.SetTargetFrameBuffer( mEffectImage );
156 task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
159 void BubbleEmitter::SetShapeImage( Image shapeImage )
161 mCustomMaterial.SetDiffuseTexture( shapeImage );
163 //Get pixel width of the shape
164 float width = Image::GetImageSize(shapeImage.GetFilename()).width;
166 for(unsigned int i=0; i < mNumShader; i++ )
168 mEffect[i].SetShapeImageWidth(width);
170 mEffectForNoise.SetShapeImageWidth(width);
173 void BubbleEmitter::SetBubbleScale( float scale )
175 for(unsigned int i=0; i < mNumShader; i++ )
177 mEffect[i].SetDynamicScale( scale );
179 mEffectForNoise.SetDynamicScale( scale );
182 void BubbleEmitter::SetBubbleDensity( unsigned int density )
184 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
186 if( density == mDensity )
194 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
195 for(unsigned int i=0; i < mNumShader; i++ )
197 mMesh[i].UpdateMeshData(meshData);
202 // clear the resources created for the off screen rendering
203 void BubbleEmitter::OnRenderFinished(RenderTask& source)
205 Actor sourceActor = source.GetSourceActor();
206 sourceActor.RemoveShaderEffect();
207 Stage::GetCurrent().Remove(sourceActor);
209 Stage::GetCurrent().GetRenderTaskList().RemoveTask(source);
212 void BubbleEmitter::SetBlendMode( bool enable )
216 for(unsigned int i=0; i < mNumShader; i++ )
219 // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
220 mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
221 BlendingFactor::ZERO, BlendingFactor::ONE);
223 mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
224 BlendingFactor::ZERO, BlendingFactor::ONE);
228 for(unsigned int i=0; i < mNumShader; i++ )
230 // using default blend func
231 mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
232 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
234 mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
235 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
239 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
241 unsigned int curUniform = mCurrentUniform % mNumBubblePerShader;
242 unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
243 SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
244 animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
245 1.f, AlphaFunctions::Linear );
247 if( mCurrentUniform % mNumShader == 0 )
249 unsigned int uniform = mCurrentUniform / mNumShader;
250 SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
251 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
252 1.f, AlphaFunctions::Linear );
255 mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
258 void BubbleEmitter::StartExplosion( float duration, float multiple )
260 Animation animation = Animation::New( duration );
261 for(unsigned int i=0; i < mNumShader; i++ )
263 animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
264 multiple, AlphaFunctions::EaseOut);
266 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
267 multiple, AlphaFunctions::EaseOut);
270 animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
273 void BubbleEmitter::Restore()
275 for(unsigned int i=0; i < mNumShader; i++ )
277 mEffect[i].ResetParameters();
279 mEffectForNoise.ResetParameters();
282 void BubbleEmitter::GenMaterial()
284 mCustomMaterial = Material::New("CustomMaterial");
285 mCustomMaterial.SetOpacity(1.0f);
286 mCustomMaterial.SetDiffuseColor(Color::WHITE);
287 mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
288 mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
289 mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
290 mCustomMaterial.SetDiffuseTexture( mShapeImage );
293 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
295 MeshData::Vertex meshVertex;
296 meshVertex.x = XYZ.x;
297 meshVertex.y = XYZ.y;
298 meshVertex.z = XYZ.z;
301 vertices.push_back(meshVertex);
304 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
305 size_t v0, size_t v1, size_t v2)
312 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
314 MeshData::VertexContainer vertices;
315 MeshData::FaceIndices faces;
316 BoneContainer bones(0);
318 for(unsigned int index = 0; index < numOfBubble; index ++)
320 float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
325 float depth = static_cast<float>( index );
326 AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
327 AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
328 AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
329 AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
331 unsigned int idx = index * 4;
332 AddTriangle( faces, idx, idx+1, idx+2);
333 AddTriangle( faces, idx, idx+2, idx+3);
336 meshData.SetData(vertices, faces, bones, mCustomMaterial);
337 meshData.SetHasColor(false);
338 meshData.SetHasTextureCoords(true);
341 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
342 const Vector2& emitPosition, const Vector2& displacement )
344 int halfRange = displacement.x / 2;
345 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
346 if(randomVec.y > 0.0f)
348 randomVec.y *= 0.33f;
351 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
352 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
354 effect.SetPercentage( curUniform, 0.f);
357 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
358 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
360 Vector2 dir(direction);
362 int halfRange = displacement.x / 2;
363 // for the y coordinate, always negative, so bubbles always go upwards
364 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
366 randomVec.x -= dir.x*halfRange;
367 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
369 if(randomVec.y > 0.0f)
371 randomVec.y *= 0.33f;
373 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
374 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
376 effect.SetPercentage( curUniform, 0.f);
379 void BubbleEmitter::OnExplosionFinished( Animation& source )
384 float BubbleEmitter::RandomRange(float f0, float f1)
386 return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
389 } // namespace Internal
391 } // namespace Toolkit