// // Copyright (c) 2014 Samsung Electronics Co., Ltd. // // Licensed under the Flora License, Version 1.0 (the License); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://floralicense.org/license/ // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an AS IS BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include #include #include #include #include #include "dali-toolkit/dali-toolkit.h" #include "../shared/view.h" using namespace Dali; using Dali::Material; namespace { const char * const TEXTURE_IMAGE ( DALI_IMAGE_DIR "bubble-effect-texture-border.png" ); const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" ); const char * const APPLICATION_TITLE( "Bubble Effect" ); const char * const CHANGE_IMAGE_ICON( DALI_IMAGE_DIR "icon_mode.png" ); const char* BACKGROUND_IMAGES[]= { DALI_IMAGE_DIR "background-1.jpg", DALI_IMAGE_DIR "background-2.jpg", DALI_IMAGE_DIR "background-3.jpg", DALI_IMAGE_DIR "background-4.jpg", }; const unsigned int NUM_BACKGROUND_IMAGES( sizeof(BACKGROUND_IMAGES) / sizeof(BACKGROUND_IMAGES[0]) ); const float MIN_DISTANCE( 2.f); const float MAX_DISTANCE( 200.f); const float BUBBLE_SIZE( 40.f ); const float BUBBLE_MIN_SIZE( 5.f ); const unsigned long MAX_TIME_INTERVAL(100); const unsigned int NUMBER_OF_BUBBLES( 100 ); //this value cannot be bigger than 100; const unsigned int NUMBER_OF_GROUP( 7 ); const unsigned int TOTAL_NUMBER_OF_BUBBLES( NUMBER_OF_BUBBLES * NUMBER_OF_GROUP ); } // unnamed namespace class BubbleEffect : public ShaderEffect { public: BubbleEffect() {} static BubbleEffect New( unsigned int numberOfBubble ) { std::ostringstream meshVertexStringStream; meshVertexStringStream << "#define NUMBER_OF_BUBBLE "<< numberOfBubble << "\n"; std::string meshVertex( " uniform float uGravity; \n" " uniform vec4 uStartAndEndPos[NUMBER_OF_BUBBLE];\n" " uniform float uEasing[NUMBER_OF_BUBBLE];\n" " uniform float uPercentage[NUMBER_OF_BUBBLE];\n" " uniform vec2 uStageSize; \n" " uniform vec2 offset[9]; \n" " varying float vPercentage;\n" " varying vec2 vEffectTexCoord;\n" " void main()\n" " {\n" " mediump vec4 position = vec4( aPosition.x, aPosition.y, 0.0, 1.0 );\n" " int zCoord = int(aPosition.z); \n" " int idx = int(mod(aPosition.z, float(NUMBER_OF_BUBBLE)));\n" " int groupIdx = (zCoord - idx) / NUMBER_OF_BUBBLE;\n" " vec4 startAndEnd = uStartAndEndPos[idx]; \n" " startAndEnd.zw += offset[groupIdx];\n" "\n" " if( uPercentage[idx] < 1.0 )\n" " {\n" " float positionDelta = uPercentage[idx];\n" " if (mod(uEasing[idx], 4.0) > 1.5) { positionDelta = pow(uPercentage[idx], 2.0); } \n" " else if (mod(uEasing[idx], 8.0) > 3.5) { positionDelta = 1.0 - pow((1.0-uPercentage[idx]),2.0); }\n" " else if (mod(uEasing[idx], 16.0) > 7.5) { positionDelta = pow(2.0, 10.0 * (uPercentage[idx] - 1.0)) - 0.001; }\n" " else if (mod(uEasing[idx], 32.0) > 15.5) { positionDelta = 1.001 * (-pow(2.0, -10.0 * uPercentage[idx]) + 1.0); }\n" " position.xy = position.xy + startAndEnd.xy + startAndEnd.zw * positionDelta; \n" " if (mod(uEasing[idx],64.0) > 31.5) { position.y = position.y - (0.5*uGravity * pow(uPercentage[idx]+0.1, 2.0)); }\n" " }\n" " gl_Position = uMvpMatrix * position;\n" "\n" " mediump vec2 start = uCustomTextureCoords.xy;\n" " mediump vec2 scale = uCustomTextureCoords.zw;\n" " vTexCoord = vec2( start.x + aTexCoord.x * scale.x, start.y + aTexCoord.y * scale.y );\n" " vPercentage = uPercentage[idx];\n" " vEffectTexCoord = startAndEnd.xy / uStageSize; \n" " }\n" ); meshVertexStringStream << meshVertex; std::string meshFragment( " varying float vPercentage;\n" " varying vec2 vEffectTexCoord;\n" "\n" " void main()\n" " {\n" " vec4 fragColor = texture2D(sEffect, vEffectTexCoord);\n" " fragColor.rgb *= 1.2; \n" " fragColor *= uColor;\n" " fragColor.a *= texture2D(sTexture, vTexCoord).a * ( 1.0-vPercentage*vPercentage );\n" " gl_FragColor = fragColor;\n" " }\n"); ShaderEffect shaderEffect = ShaderEffect::New( meshVertexStringStream.str(), meshFragment, GeometryType( GEOMETRY_TYPE_TEXTURED_MESH), ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING ) ); BubbleEffect handle( shaderEffect ); handle.mNumOfBubbles = numberOfBubble; handle.SetUniform( "uGravity", 100.f ); handle.SetUniform( "uStageSize", Stage::GetCurrent().GetSize() ); for( unsigned int i=0; i( rand()%size + BUBBLE_MIN_SIZE); float depth = static_cast( index ); AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) ); AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f )); AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) ); AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) ); unsigned int idx = index * 4; AddTriangle( faces, idx, idx+1, idx+2); AddTriangle( faces, idx, idx+2, idx+3); } meshData.SetData(vertices, faces, bones, mCustomMaterial); meshData.SetHasColor(false); meshData.SetHasNormals(true); meshData.SetHasTextureCoords(true); } void SetUpAnimation( Vector2 emitPosition, Vector2 direction ) { unsigned int curUniform = mCurrentUniform % NUMBER_OF_BUBBLES; unsigned int groupIdx = mCurrentUniform / NUMBER_OF_BUBBLES; mEffect[groupIdx].SetBubbleParameter(curUniform, emitPosition, direction); float duration = RandomRange( 1.f, 2.f ); mAnimation[mCurrentUniform] = Animation::New( duration ); mAnimationIndexPair[mAnimation[mCurrentUniform]] = mCurrentUniform; mAnimation[mCurrentUniform].AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ), 1.f, AlphaFunctions::DoubleEaseInOutSine60 ); mAnimation[mCurrentUniform].Play(); mAnimation[mCurrentUniform].FinishedSignal().Connect(this, &BubbleEffectExample::OnAnimationFinished); mCurrentUniform = (mCurrentUniform + 1) % (TOTAL_NUMBER_OF_BUBBLES); } void OnAnimationFinished( Animation& source ) { mAnimation[mAnimationIndexPair[source]].Reset(); mAnimationIndexPair.erase( source ); } float RandomRange(float f0, float f1) { return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f); } bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event) { if(!mTouchable) { return false; } if ( event.GetPointCount() > 0 ) { const TouchPoint &point = event.GetPoint(0); float distance = hypotf( point.local.x - mLastTouchPosition.x, point.local.y - mLastTouchPosition.y ); if ( distance > MIN_DISTANCE ) { // when the finger moves fast, interpolate linearly between two touch points if(event.time - mLastTouchTime < MAX_TIME_INTERVAL && distance < MAX_DISTANCE) { float num = floor(distance / MIN_DISTANCE); unsigned int numStep = static_cast( num ); Vector2 step = ( point.screen - mLastTouchPosition ) * MIN_DISTANCE / distance; for(unsigned int i = 0; i mAnimationIndexPair; unsigned long mLastTouchTime; Vector2 mLastTouchPosition; Toolkit::GaussianBlurView mGaussianBlurView; FrameBufferImage mFrameBufferImage; Timer mTimer; bool mRescoucesCleared; Layer mContent; Toolkit::View mView; unsigned int mCurrentBackgroundImageId; }; /*****************************************************************************/ static void RunTest(Application& app) { BubbleEffectExample theApp(app); app.MainLoop(); } /*****************************************************************************/ int main(int argc, char **argv) { Application app = Application::New(&argc, &argv); RunTest(app); return 0; }