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"
25 #include <dali-toolkit/public-api/shader-effects/bubble-effect/color-adjuster.h>
36 BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
38 unsigned int maximumNumberOfBubble,
39 const Vector2& bubbleSizeRange )
40 : ControlImpl( true ),
41 mMovementArea( movementArea ),
42 mShapeImage( shapeImage ),
43 mTotalNumOfBubble( maximumNumberOfBubble ),
44 mBubbleSizeRange( bubbleSizeRange ),
50 BubbleEmitter::~BubbleEmitter()
54 Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
56 unsigned int maximumNumberOfBubble,
57 const Vector2& bubbleSizeRange )
59 // Create the implementation
60 IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeImage,
61 maximumNumberOfBubble,bubbleSizeRange ) );
63 // Pass ownership to Toolkit::BubbleEmitter handle
64 Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
66 //Second phase of implementeation : Initialization
67 internalBubbleEmitter->OnInitialize();
72 void BubbleEmitter::OnInitialize()
74 // Create the root actor, all the meshActor should be its children
75 mBubbleRoot = Actor::New();
76 mBubbleRoot.SetSize(mMovementArea);
78 // Prepare the frame buffer to store the color adjusted background image
79 mEffectImage = FrameBufferImage::New( mMovementArea.width/4.f, mMovementArea.height/4.f, Pixel::RGBA8888, Dali::Image::Unused );
81 // Generate the material object, which is used by all meshActors
84 // Calculate how many BubbleEffect shaders are required
85 if( mTotalNumOfBubble>100 )
87 mNumBubblePerShader = 100;
88 mNumShader = mTotalNumOfBubble / 100;
92 mNumBubblePerShader = mTotalNumOfBubble;
96 mMesh.resize( mNumShader );
97 mMeshActor.resize( mNumShader );
98 mEffect.resize( mNumShader );
100 // Create the meshActor group and bubbleEffect group to emit bubbles following the given track, such as finger touch track.
102 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
103 for(unsigned int i=0; i < mNumShader; i++ )
105 mMesh[i] = Mesh::New( meshData );
106 mMeshActor[i] = MeshActor::New( mMesh[i] );
107 mMeshActor[i].SetAffectedByLighting( false );
108 mMeshActor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
109 mEffect[i] = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
110 mEffect[i].SetEffectImage( mEffectImage );
111 mEffect[i].SetMovementArea( mMovementArea );
112 mMeshActor[i].SetShaderEffect( mEffect[i] );
113 mBubbleRoot.Add( mMeshActor[i] );
116 // Create the extra meshActor and bubbleEffect to emit bubbles in totally random angle.
117 MeshData meshDataForNoise;
118 ConstructBubbleMesh( meshDataForNoise, mNumBubblePerShader);
119 mMeshActorForNoise = MeshActor::New( Mesh::New(meshDataForNoise) );
120 mMeshActorForNoise.SetAffectedByLighting( false );
121 mMeshActorForNoise.SetParentOrigin(ParentOrigin::TOP_LEFT);
122 mEffectForNoise = BubbleEffect::New( mNumBubblePerShader, mShapeImage.GetFilename() );
123 mEffectForNoise.SetMovementArea( mMovementArea );
124 mEffectForNoise.SetEffectImage( mEffectImage );
125 mMeshActorForNoise.SetShaderEffect( mEffectForNoise );
126 mBubbleRoot.Add( mMeshActorForNoise );
128 // Create a cameraActor for the off screen render task.
129 mCameraActor = CameraActor::New(mMovementArea);
130 mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
131 Stage::GetCurrent().Add(mCameraActor);
134 Actor BubbleEmitter::GetRootActor()
139 void BubbleEmitter::SetBackground( Image bgImage, const Vector3& hsvDelta )
141 ImageActor sourceActor = ImageActor::New( bgImage );
142 sourceActor.SetSize( mMovementArea );
143 sourceActor.SetParentOrigin(ParentOrigin::CENTER);
144 Stage::GetCurrent().Add( sourceActor );
146 ColorAdjuster colorAdjuster = ColorAdjuster::New( hsvDelta, true /*ignore alpha to make bubble color always*/ );
147 sourceActor.SetShaderEffect( colorAdjuster );
149 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
150 RenderTask task = taskList.CreateTask();
151 task.SetRefreshRate( RenderTask::REFRESH_ONCE );
152 task.SetSourceActor( sourceActor );
153 task.SetExclusive(true);
154 task.SetCameraActor(mCameraActor);
155 task.GetCameraActor().SetInvertYAxis(true);
156 task.SetTargetFrameBuffer( mEffectImage );
157 task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
160 void BubbleEmitter::SetShapeImage( Image shapeImage )
162 mCustomMaterial.SetDiffuseTexture( shapeImage );
164 //Get pixel width of the shape
165 float width = Image::GetImageSize(shapeImage.GetFilename()).width;
167 for(unsigned int i=0; i < mNumShader; i++ )
169 mEffect[i].SetShapeImageWidth(width);
171 mEffectForNoise.SetShapeImageWidth(width);
174 void BubbleEmitter::SetBubbleScale( float scale )
176 for(unsigned int i=0; i < mNumShader; i++ )
178 mEffect[i].SetDynamicScale( scale );
180 mEffectForNoise.SetDynamicScale( scale );
183 void BubbleEmitter::SetBubbleDensity( unsigned int density )
185 DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
187 if( density == mDensity )
195 ConstructBubbleMesh( meshData, mNumBubblePerShader*mDensity);
196 for(unsigned int i=0; i < mNumShader; i++ )
198 mMesh[i].UpdateMeshData(meshData);
203 // clear the resources created for the off screen rendering
204 void BubbleEmitter::OnRenderFinished(RenderTask& source)
206 Actor sourceActor = source.GetSourceActor();
207 sourceActor.RemoveShaderEffect();
208 Stage::GetCurrent().Remove(sourceActor);
210 Stage::GetCurrent().GetRenderTaskList().RemoveTask(source);
213 void BubbleEmitter::SetBlendMode( bool enable )
217 for(unsigned int i=0; i < mNumShader; i++ )
220 // TODO: if BlendColor would be public api from renderable actor, then can optimize the constant color
221 mMeshActor[i].SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
222 BlendingFactor::ZERO, BlendingFactor::ONE);
224 mMeshActorForNoise.SetBlendFunc(BlendingFactor::SRC_ALPHA, BlendingFactor::ONE,
225 BlendingFactor::ZERO, BlendingFactor::ONE);
229 for(unsigned int i=0; i < mNumShader; i++ )
231 // using default blend func
232 mMeshActor[i].SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
233 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
235 mMeshActorForNoise.SetBlendFunc( BlendingFactor::SRC_ALPHA, BlendingFactor::ONE_MINUS_SRC_ALPHA,
236 BlendingFactor::ONE, BlendingFactor::ONE_MINUS_SRC_ALPHA );
240 void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
242 unsigned int curUniform = mCurrentUniform % mNumBubblePerShader;
243 unsigned int groupIdx = mCurrentUniform / mNumBubblePerShader;
244 SetBubbleParameter( mEffect[groupIdx], curUniform, emitPosition, direction, displacement);
245 animation.AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
246 1.f, AlphaFunctions::Linear );
248 if( mCurrentUniform % mNumShader == 0 )
250 unsigned int uniform = mCurrentUniform / mNumShader;
251 SetBubbleParameter(mEffectForNoise, uniform, emitPosition, displacement);
252 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetPercentagePropertyName(uniform) ),
253 1.f, AlphaFunctions::Linear );
256 mCurrentUniform = (mCurrentUniform + 1) % mTotalNumOfBubble;
259 void BubbleEmitter::StartExplosion( float duration, float multiple )
261 Animation animation = Animation::New( duration );
262 for(unsigned int i=0; i < mNumShader; i++ )
264 animation.AnimateTo( Property( mEffect[i], mEffect[i].GetMagnificationPropertyName() ),
265 multiple, AlphaFunctions::EaseOut);
267 animation.AnimateTo( Property( mEffectForNoise, mEffectForNoise.GetMagnificationPropertyName() ),
268 multiple, AlphaFunctions::EaseOut);
271 animation.FinishedSignal().Connect(this, &BubbleEmitter::OnExplosionFinished);
274 void BubbleEmitter::Restore()
276 for(unsigned int i=0; i < mNumShader; i++ )
278 mEffect[i].ResetParameters();
280 mEffectForNoise.ResetParameters();
283 void BubbleEmitter::GenMaterial()
285 mCustomMaterial = Material::New("CustomMaterial");
286 mCustomMaterial.SetOpacity(1.0f);
287 mCustomMaterial.SetDiffuseColor(Color::WHITE);
288 mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
289 mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
290 mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
291 mCustomMaterial.SetDiffuseTexture( mShapeImage );
294 void BubbleEmitter::AddVertex(MeshData::VertexContainer& vertices, Vector3 XYZ, Vector2 UV)
296 MeshData::Vertex meshVertex;
297 meshVertex.x = XYZ.x;
298 meshVertex.y = XYZ.y;
299 meshVertex.z = XYZ.z;
302 vertices.push_back(meshVertex);
305 void BubbleEmitter::AddTriangle(MeshData::FaceIndices& faces,
306 size_t v0, size_t v1, size_t v2)
313 void BubbleEmitter::ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble)
315 MeshData::VertexContainer vertices;
316 MeshData::FaceIndices faces;
317 BoneContainer bones(0);
319 for(unsigned int index = 0; index < numOfBubble; index ++)
321 float curSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y);
326 float depth = static_cast<float>( index );
327 AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
328 AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
329 AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
330 AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
332 unsigned int idx = index * 4;
333 AddTriangle( faces, idx, idx+1, idx+2);
334 AddTriangle( faces, idx, idx+2, idx+3);
337 meshData.SetData(vertices, faces, bones, mCustomMaterial);
338 meshData.SetHasColor(false);
339 meshData.SetHasTextureCoords(true);
342 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
343 const Vector2& emitPosition, const Vector2& displacement )
345 int halfRange = displacement.x / 2;
346 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, rand()%static_cast<int>(displacement.y) - halfRange);
347 if(randomVec.y > 0.0f)
349 randomVec.y *= 0.33f;
352 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
353 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
355 effect.SetPercentage( curUniform, 0.f);
358 void BubbleEmitter::SetBubbleParameter( BubbleEffect& effect, unsigned int curUniform,
359 const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
361 Vector2 dir(direction);
363 int halfRange = displacement.x / 2;
364 // for the y coordinate, always negative, so bubbles always go upwards
365 Vector2 randomVec(rand()%static_cast<int>(displacement.x) - halfRange, -rand()%static_cast<int>(displacement.y));
367 randomVec.x -= dir.x*halfRange;
368 randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
370 if(randomVec.y > 0.0f)
372 randomVec.y *= 0.33f;
374 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
375 effect.SetStartAndEndPosition( curUniform, startAndEndPos );
377 effect.SetPercentage( curUniform, 0.f);
380 void BubbleEmitter::OnExplosionFinished( Animation& source )
385 float BubbleEmitter::RandomRange(float f0, float f1)
387 return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
390 } // namespace Internal
392 } // namespace Toolkit