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.
21 #include <dali/dali.h>
22 #include "dali-toolkit/dali-toolkit.h"
24 #include "../shared/view.h"
32 const char * const TEXTURE_IMAGE ( DALI_IMAGE_DIR "bubble-effect-texture-border.png" );
33 const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
34 const char * const APPLICATION_TITLE( "Bubble Effect" );
35 const char * const CHANGE_IMAGE_ICON( DALI_IMAGE_DIR "icon_mode.png" );
37 const char* BACKGROUND_IMAGES[]=
39 DALI_IMAGE_DIR "background-1.jpg",
40 DALI_IMAGE_DIR "background-2.jpg",
41 DALI_IMAGE_DIR "background-3.jpg",
42 DALI_IMAGE_DIR "background-4.jpg",
44 const unsigned int NUM_BACKGROUND_IMAGES( sizeof(BACKGROUND_IMAGES) / sizeof(BACKGROUND_IMAGES[0]) );
46 const float MIN_DISTANCE( 2.f);
47 const float MAX_DISTANCE( 200.f);
48 const float BUBBLE_SIZE( 40.f );
49 const float BUBBLE_MIN_SIZE( 5.f );
50 const unsigned long MAX_TIME_INTERVAL(100);
51 const unsigned int NUMBER_OF_BUBBLES( 100 ); //this value cannot be bigger than 100;
52 const unsigned int NUMBER_OF_GROUP( 7 );
53 const unsigned int TOTAL_NUMBER_OF_BUBBLES( NUMBER_OF_BUBBLES * NUMBER_OF_GROUP );
54 } // unnamed namespace
56 class BubbleEffect : public ShaderEffect
63 static BubbleEffect New( unsigned int numberOfBubble )
65 std::ostringstream meshVertexStringStream;
66 meshVertexStringStream << "#define NUMBER_OF_BUBBLE "<< numberOfBubble << "\n";
67 std::string meshVertex(
68 " uniform float uGravity; \n"
69 " uniform vec4 uStartAndEndPos[NUMBER_OF_BUBBLE];\n"
70 " uniform float uEasing[NUMBER_OF_BUBBLE];\n"
71 " uniform float uPercentage[NUMBER_OF_BUBBLE];\n"
72 " uniform vec2 uStageSize; \n"
73 " uniform vec2 offset[9]; \n"
74 " varying float vPercentage;\n"
75 " varying vec2 vEffectTexCoord;\n"
78 " mediump vec4 position = vec4( aPosition.x, aPosition.y, 0.0, 1.0 );\n"
79 " int zCoord = int(aPosition.z); \n"
80 " int idx = int(mod(aPosition.z, float(NUMBER_OF_BUBBLE)));\n"
81 " int groupIdx = (zCoord - idx) / NUMBER_OF_BUBBLE;\n"
82 " vec4 startAndEnd = uStartAndEndPos[idx]; \n"
83 " startAndEnd.zw += offset[groupIdx];\n"
85 " if( uPercentage[idx] < 1.0 )\n"
87 " float positionDelta = uPercentage[idx];\n"
88 " if (mod(uEasing[idx], 4.0) > 1.5) { positionDelta = pow(uPercentage[idx], 2.0); } \n"
89 " else if (mod(uEasing[idx], 8.0) > 3.5) { positionDelta = 1.0 - pow((1.0-uPercentage[idx]),2.0); }\n"
90 " else if (mod(uEasing[idx], 16.0) > 7.5) { positionDelta = pow(2.0, 10.0 * (uPercentage[idx] - 1.0)) - 0.001; }\n"
91 " else if (mod(uEasing[idx], 32.0) > 15.5) { positionDelta = 1.001 * (-pow(2.0, -10.0 * uPercentage[idx]) + 1.0); }\n"
93 " position.xy = position.xy + startAndEnd.xy + startAndEnd.zw * positionDelta; \n"
94 " if (mod(uEasing[idx],64.0) > 31.5) { position.y = position.y - (0.5*uGravity * pow(uPercentage[idx]+0.1, 2.0)); }\n"
96 " gl_Position = uMvpMatrix * position;\n"
98 " mediump vec2 start = uCustomTextureCoords.xy;\n"
99 " mediump vec2 scale = uCustomTextureCoords.zw;\n"
100 " vTexCoord = vec2( start.x + aTexCoord.x * scale.x, start.y + aTexCoord.y * scale.y );\n"
101 " vPercentage = uPercentage[idx];\n"
102 " vEffectTexCoord = startAndEnd.xy / uStageSize; \n"
104 meshVertexStringStream << meshVertex;
106 std::string meshFragment(
107 " varying float vPercentage;\n"
108 " varying vec2 vEffectTexCoord;\n"
112 " vec4 fragColor = texture2D(sEffect, vEffectTexCoord);\n"
113 " fragColor.rgb *= 1.2; \n"
114 " fragColor *= uColor;\n"
115 " fragColor.a *= texture2D(sTexture, vTexCoord).a * ( 1.0-vPercentage*vPercentage );\n"
116 " gl_FragColor = fragColor;\n"
119 ShaderEffect shaderEffect = ShaderEffect::New( meshVertexStringStream.str(), meshFragment,
120 GeometryType( GEOMETRY_TYPE_TEXTURED_MESH),
121 ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING ) );
122 BubbleEffect handle( shaderEffect );
123 handle.mNumOfBubbles = numberOfBubble;
124 handle.SetUniform( "uGravity", 100.f );
125 handle.SetUniform( "uStageSize", Stage::GetCurrent().GetSize() );
126 for( unsigned int i=0; i<numberOfBubble; i++ )
128 handle.SetPercentage( i, 1.f);
136 void SetBubbleParameter(unsigned int idx, const Vector2& emitPosition, Vector2 direction)
138 Vector2 randomVec(rand()%400-200, rand()%400-200);
139 float length = randomVec.Length();
141 direction.Normalize();
142 Vector2 endPos = (randomVec - direction*4.f);
144 Vector4 startAndEndPos( emitPosition.x, emitPosition.y, endPos.x*length, endPos.y*length );
145 SetStartAndEndPos( idx, startAndEndPos );
147 float easing = pow( 2, rand()%5-1 ) + ( rand()%2-1 )*32;
148 SetEasing( idx, easing );
150 SetPercentage( idx, 0.f);
152 float offset = 100.f;
153 SetUniform("offset[0]", Vector2(0.f,0.f));
154 SetUniform("offset[1]", Vector2(offset,0.f));
155 SetUniform("offset[2]", Vector2(-offset,0.f));
156 SetUniform("offset[3]", Vector2(0.f,offset));
157 SetUniform("offset[4]", Vector2(0.f,-offset));
158 SetUniform("offset[5]", Vector2(offset,offset)*0.707f );
159 SetUniform("offset[6]", Vector2(offset,-offset)*0.707f);
160 SetUniform("offset[7]", Vector2(-offset,offset)*0.707f);
161 SetUniform("offset[8]", Vector2(-offset,-offset)*0.707f);
164 std::string GetPercentagePropertyName( unsigned int idx ) const
166 assert( idx < mNumOfBubbles );
167 std::ostringstream oss;
168 oss<< "uPercentage["<< idx << "]";
174 BubbleEffect( ShaderEffect handle )
175 : ShaderEffect( handle )
178 void SetStartAndEndPos( unsigned int idx, const Vector4& startAndEndPos )
180 assert( idx < mNumOfBubbles );
181 std::ostringstream oss;
182 oss<< "uStartAndEndPos["<< idx << "]";
183 SetUniform( oss.str(), startAndEndPos );
186 void SetEasing( unsigned int idx, float easing )
188 assert( idx < mNumOfBubbles );
189 std::ostringstream oss;
190 oss<< "uEasing["<< idx << "]";
191 SetUniform( oss.str(), easing );
194 void SetPercentage( unsigned int idx, float percentage )
196 assert( idx < mNumOfBubbles );
197 std::ostringstream oss;
198 oss<< "uPercentage["<< idx << "]";
199 SetUniform( oss.str(), percentage );
204 unsigned int mNumOfBubbles;
207 class BubbleEffectExample : public ConnectionTracker
210 BubbleEffectExample(Application &app)
212 mCurrentUniform( 0 ),
215 mRescoucesCleared( false ),
216 mCurrentBackgroundImageId( 0 )
218 app.InitSignal().Connect(this, &BubbleEffectExample::Create);
221 ~BubbleEffectExample()
227 void Create(Application& app)
229 Stage stage = Stage::GetCurrent();
230 Vector2 size = stage.GetSize();
232 // Creates a default view with a default tool bar.
233 // The view is added to the stage.
234 Toolkit::ToolBar toolBar;
235 mContent = DemoHelper::CreateView( app,
242 // Create a effect toggle button. (right of toolbar)
243 Image imageLayout = Image::New( CHANGE_IMAGE_ICON );
244 Toolkit::PushButton layoutButton = Toolkit::PushButton::New();
245 layoutButton.SetBackgroundImage(imageLayout);
246 layoutButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnImageChageIconClicked );
247 toolBar.AddControl( layoutButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
249 mRoot = Actor::New();
250 mRoot.SetParentOrigin( ParentOrigin::CENTER );
253 mFrameBufferImage = FrameBufferImage::New( size.width/4.f, size.height/4.f, Pixel::RGBA8888, Dali::Image::Unused );
254 mTimer = Timer::New( 1000 );
255 mTimer.TickSignal().Connect( this, &BubbleEffectExample::ClearBlurResource );
257 SetImage( BACKGROUND_IMAGES[ mCurrentBackgroundImageId ] );
261 ConstructBubbleMesh( meshData, NUMBER_OF_BUBBLES*9, BUBBLE_SIZE);
262 for(unsigned int i=0; i < NUMBER_OF_GROUP; i++ )
264 mMesh[i] = Mesh::New( meshData );
265 mMeshActor[i] = MeshActor::New( mMesh[i] );
266 mMeshActor[i].SetAffectedByLighting( false );
267 mMeshActor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
268 stage.Add( mMeshActor[i] );
269 mEffect[i] = BubbleEffect::New( NUMBER_OF_BUBBLES );
270 mEffect[i].SetEffectImage( mFrameBufferImage );
271 mMeshActor[i].SetShaderEffect( mEffect[i] );
274 Stage::GetCurrent().KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent);
277 void OnKeyEvent(const KeyEvent& event)
279 if(event.state == KeyEvent::Down)
281 if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
288 void SetImage( const std::string& imagePath )
294 mScreen.TouchedSignal().Disconnect( this, &BubbleEffectExample::OnTouch );
295 mRoot.Remove( mScreen );
299 Stage stage = Stage::GetCurrent();
301 Image image = Image::New( imagePath );
302 mScreen = ImageActor::New( image );
303 mScreen.SetSize( stage.GetSize() );
304 mScreen.SetZ( -1.f );
305 mScreen.SetParentOrigin(ParentOrigin::CENTER);
307 mScreen.TouchedSignal().Connect( this, &BubbleEffectExample::OnTouch );
309 mGaussianBlurView = Toolkit::GaussianBlurView::New( 7, 2.5f, Pixel::RGBA8888, 0.25f, 0.25f, true );
310 mGaussianBlurView.SetParentOrigin(ParentOrigin::CENTER);
311 mGaussianBlurView.SetSize(stage.GetSize());
312 mGaussianBlurView.SetUserImageAndOutputRenderTarget( image, mFrameBufferImage );
313 stage.Add( mGaussianBlurView );
314 mGaussianBlurView.Activate();
316 mRescoucesCleared = false;
322 bool ClearBlurResource()
324 if( !mRescoucesCleared )
326 Stage::GetCurrent().Remove( mGaussianBlurView );
327 mGaussianBlurView.Deactivate();
328 mGaussianBlurView.Reset();
329 mRescoucesCleared = true;
336 mCustomMaterial = Material::New("CustomMaterial");
337 mCustomMaterial.SetOpacity(1.0f);
338 mCustomMaterial.SetDiffuseColor(Color::WHITE);
339 mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
340 mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP );
341 mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP );
342 mCustomMaterial.SetDiffuseTexture( Image::New( TEXTURE_IMAGE ) );
345 void AddVertex(MeshData::VertexContainer& vertices, Vector3 V, Vector2 UV)
347 MeshData::Vertex meshVertex;
353 vertices.push_back(meshVertex);
356 void AddTriangle(MeshData::FaceIndices& faces,
357 size_t v0, size_t v1, size_t v2)
364 void ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble, int size )
366 MeshData::VertexContainer vertices;
367 MeshData::FaceIndices faces;
368 BoneContainer bones(0);
370 for(unsigned int index = 0; index < numOfBubble; index ++)
372 float curSize = static_cast<float>( rand()%size + BUBBLE_MIN_SIZE);
373 float depth = static_cast<float>( index );
374 AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) );
375 AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f ));
376 AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) );
377 AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) );
379 unsigned int idx = index * 4;
380 AddTriangle( faces, idx, idx+1, idx+2);
381 AddTriangle( faces, idx, idx+2, idx+3);
384 meshData.SetData(vertices, faces, bones, mCustomMaterial);
385 meshData.SetHasColor(false);
386 meshData.SetHasNormals(true);
387 meshData.SetHasTextureCoords(true);
390 void SetUpAnimation( Vector2 emitPosition, Vector2 direction )
392 unsigned int curUniform = mCurrentUniform % NUMBER_OF_BUBBLES;
393 unsigned int groupIdx = mCurrentUniform / NUMBER_OF_BUBBLES;
394 mEffect[groupIdx].SetBubbleParameter(curUniform, emitPosition, direction);
395 float duration = RandomRange( 1.f, 2.f );
396 mAnimation[mCurrentUniform] = Animation::New( duration );
397 mAnimationIndexPair[mAnimation[mCurrentUniform]] = mCurrentUniform;
398 mAnimation[mCurrentUniform].AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ),
399 1.f, AlphaFunctions::DoubleEaseInOutSine60 );
400 mAnimation[mCurrentUniform].Play();
401 mAnimation[mCurrentUniform].FinishedSignal().Connect(this, &BubbleEffectExample::OnAnimationFinished);
403 mCurrentUniform = (mCurrentUniform + 1) % (TOTAL_NUMBER_OF_BUBBLES);
406 void OnAnimationFinished( Animation& source )
408 mAnimation[mAnimationIndexPair[source]].Reset();
409 mAnimationIndexPair.erase( source );
412 float RandomRange(float f0, float f1)
414 return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f);
417 bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event)
424 if ( event.GetPointCount() > 0 )
426 const TouchPoint &point = event.GetPoint(0);
427 float distance = hypotf( point.local.x - mLastTouchPosition.x, point.local.y - mLastTouchPosition.y );
428 if ( distance > MIN_DISTANCE )
430 // when the finger moves fast, interpolate linearly between two touch points
431 if(event.time - mLastTouchTime < MAX_TIME_INTERVAL && distance < MAX_DISTANCE)
433 float num = floor(distance / MIN_DISTANCE);
434 unsigned int numStep = static_cast<unsigned int>( num );
435 Vector2 step = ( point.screen - mLastTouchPosition ) * MIN_DISTANCE / distance;
436 for(unsigned int i = 0; i<numStep; i++)
438 SetUpAnimation( mLastTouchPosition + step*i, step );
443 SetUpAnimation( point.screen, point.screen-mLastTouchPosition );
446 mLastTouchTime = event.time;
447 mLastTouchPosition = point.screen;
453 bool OnImageChageIconClicked( Toolkit::Button button )
455 mCurrentBackgroundImageId = (mCurrentBackgroundImageId + 1 ) % NUM_BACKGROUND_IMAGES;
456 SetImage( BACKGROUND_IMAGES[ mCurrentBackgroundImageId ] );
464 Mesh mMesh[NUMBER_OF_GROUP];
465 MeshActor mMeshActor[NUMBER_OF_GROUP];
466 Material mCustomMaterial;
467 BubbleEffect mEffect[NUMBER_OF_GROUP];
468 unsigned int mCurrentUniform;
469 Animation mAnimation[TOTAL_NUMBER_OF_BUBBLES];
471 std::map<Animation, unsigned int> mAnimationIndexPair;
472 unsigned long mLastTouchTime;
473 Vector2 mLastTouchPosition;
475 Toolkit::GaussianBlurView mGaussianBlurView;
476 FrameBufferImage mFrameBufferImage;
478 bool mRescoucesCleared;
482 unsigned int mCurrentBackgroundImageId;
485 /*****************************************************************************/
488 RunTest(Application& app)
490 BubbleEffectExample theApp(app);
494 /*****************************************************************************/
497 main(int argc, char **argv)
499 Application app = Application::New(&argc, &argv);