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.SetTargetFrameBuffer( mEffectImage );
155 task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
158 void BubbleEmitter::SetShapeImage( Image shapeImage )
160 mCustomMaterial.SetDiffuseTexture( shapeImage );
162 //Get pixel width of the shape
163 float width = Image::GetImageSize(shapeImage.GetFilename()).width;
165 for(unsigned int i=0; i < mNumShader; i++ )
167 mEffect[i].SetShapeImageWidth(width);
169 mEffectForNoise.SetShapeImageWidth(width);
172 void BubbleEmitter::SetBubbleScale( float scale )
174 for(unsigned int i=0; i < mNumShader; i++ )
176 mEffect[i].SetDynamicScale( scale );
178 mEffectForNoise.SetDynamicScale( scale );
181 void BubbleEmitter::SetBubbleDensity( unsigned int density )
183 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
185 if( density == mDensity )
193 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
194 for(unsigned int i=0; i < mNumShader; i++ )
196 mMesh[i].UpdateMeshData(meshData);
201 // clear the resources created for the off screen rendering
202 void BubbleEmitter::OnRenderFinished(RenderTask& source)
204 Actor sourceActor = source.GetSourceActor();
205 sourceActor.RemoveShaderEffect();
206 Stage::GetCurrent().Remove(sourceActor);
208 Stage::GetCurrent().GetRenderTaskList().RemoveTask(source);
211 void BubbleEmitter::SetBlendMode( bool enable )
215 for(unsigned int i=0; i < mNumShader; i++ )
218 // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
219 mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
220 BlendingFactor::ZERO, BlendingFactor::ONE);
222 mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
223 BlendingFactor::ZERO, BlendingFactor::ONE);
227 for(unsigned int i=0; i < mNumShader; i++ )
229 // using default blend func
230 mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
231 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
233 mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
234 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
238 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
240 unsigned int curUniform = mCurrentUniform % mNumBubblePerShader;
241 unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
242 SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
243 animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
244 1.f, AlphaFunctions::Linear );
246 if( mCurrentUniform % mNumShader == 0 )
248 unsigned int uniform = mCurrentUniform / mNumShader;
249 SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
250 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
251 1.f, AlphaFunctions::Linear );
254 mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
257 void BubbleEmitter::StartExplosion( float duration, float multiple )
259 Animation animation = Animation::New( duration );
260 for(unsigned int i=0; i < mNumShader; i++ )
262 animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
263 multiple, AlphaFunctions::EaseOut);
265 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
266 multiple, AlphaFunctions::EaseOut);
269 animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
272 void BubbleEmitter::Restore()
274 for(unsigned int i=0; i < mNumShader; i++ )
276 mEffect[i].ResetParameters();
278 mEffectForNoise.ResetParameters();
281 void BubbleEmitter::GenMaterial()
283 mCustomMaterial = Material::New("CustomMaterial");
284 mCustomMaterial.SetOpacity(1.0f);
285 mCustomMaterial.SetDiffuseColor(Color::WHITE);
286 mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
287 mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
288 mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
289 mCustomMaterial.SetDiffuseTexture( mShapeImage );
292 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
294 MeshData::Vertex meshVertex;
295 meshVertex.x = XYZ.x;
296 meshVertex.y = XYZ.y;
297 meshVertex.z = XYZ.z;
300 vertices.push_back(meshVertex);
303 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
304 size_t v0, size_t v1, size_t v2)
311 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
313 MeshData::VertexContainer vertices;
314 MeshData::FaceIndices faces;
315 BoneContainer bones(0);
317 for(unsigned int index = 0; index < numOfBubble; index ++)
319 float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
324 float depth = static_cast<float>( index );
325 AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
326 AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
327 AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
328 AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
330 unsigned int idx = index * 4;
331 AddTriangle( faces, idx, idx+1, idx+2);
332 AddTriangle( faces, idx, idx+2, idx+3);
335 meshData.SetData(vertices, faces, bones, mCustomMaterial);
336 meshData.SetHasColor(false);
337 meshData.SetHasTextureCoords(true);
340 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
341 const Vector2& emitPosition, const Vector2& displacement )
343 int halfRange = displacement.x / 2;
344 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
345 if(randomVec.y > 0.0f)
347 randomVec.y *= 0.33f;
350 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
351 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
353 effect.SetPercentage( curUniform, 0.f);
356 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
357 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
359 Vector2 dir(direction);
361 int halfRange = displacement.x / 2;
362 // for the y coordinate, always negative, so bubbles always go upwards
363 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
365 randomVec.x -= dir.x*halfRange;
366 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
368 if(randomVec.y > 0.0f)
370 randomVec.y *= 0.33f;
372 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
373 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
375 effect.SetPercentage( curUniform, 0.f);
378 void BubbleEmitter::OnExplosionFinished( Animation& source )
383 float BubbleEmitter::RandomRange(float f0, float f1)
385 return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
388 } // namespace Internal
390 } // namespace Toolkit