Commit 84c8bd6c49e6cfb475d5999edfa17ce7aa8ab4e7
1 parent
446388d5
(Shader Effect) update the bubble effect demo
[Issue#] [Problem] [Cause] [Solution] Change-Id: I13cf665cab3e0a1fac999700a73c6cc3027640f1 Signed-off-by: Xiangyin Ma <x1.ma@samsung.com>
Showing
1 changed file
with
192 additions
and
388 deletions
examples/shader-effect/bubble-effect-example.cpp
| ... | ... | @@ -14,25 +14,18 @@ |
| 14 | 14 | // limitations under the License. |
| 15 | 15 | // |
| 16 | 16 | |
| 17 | -#include <stdio.h> | |
| 18 | -#include <unistd.h> | |
| 19 | -#include <getopt.h> | |
| 20 | -#include <sstream> | |
| 21 | 17 | #include <dali/dali.h> |
| 22 | -#include "dali-toolkit/dali-toolkit.h" | |
| 23 | - | |
| 18 | +#include <dali-toolkit/dali-toolkit.h> | |
| 24 | 19 | #include "../shared/view.h" |
| 25 | 20 | |
| 26 | 21 | using namespace Dali; |
| 27 | 22 | |
| 28 | -using Dali::Material; | |
| 29 | - | |
| 30 | 23 | namespace |
| 31 | 24 | { |
| 32 | -const char * const TEXTURE_IMAGE ( DALI_IMAGE_DIR "bubble-effect-texture-border.png" ); | |
| 33 | 25 | const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" ); |
| 34 | 26 | const char * const APPLICATION_TITLE( "Bubble Effect" ); |
| 35 | -const char * const CHANGE_IMAGE_ICON( DALI_IMAGE_DIR "icon-change.png" ); | |
| 27 | +const char * const CHANGE_BACKGROUND_ICON( DALI_IMAGE_DIR "icon-change.png" ); | |
| 28 | +const char * const CHANGE_BUBBLE_SHAPE_ICON( DALI_IMAGE_DIR "icon-replace.png" ); | |
| 36 | 29 | |
| 37 | 30 | const char* BACKGROUND_IMAGES[]= |
| 38 | 31 | { |
| ... | ... | @@ -42,180 +35,34 @@ const char* BACKGROUND_IMAGES[]= |
| 42 | 35 | DALI_IMAGE_DIR "background-4.jpg", |
| 43 | 36 | DALI_IMAGE_DIR "background-5.jpg", |
| 44 | 37 | }; |
| 45 | -const unsigned int NUM_BACKGROUND_IMAGES( sizeof(BACKGROUND_IMAGES) / sizeof(BACKGROUND_IMAGES[0]) ); | |
| 46 | - | |
| 47 | -const float MIN_DISTANCE( 2.f); | |
| 48 | -const float MAX_DISTANCE( 200.f); | |
| 49 | -const float BUBBLE_SIZE( 40.f ); | |
| 50 | -const float BUBBLE_MIN_SIZE( 5.f ); | |
| 51 | -const unsigned long MAX_TIME_INTERVAL(100); | |
| 52 | -const unsigned int NUMBER_OF_BUBBLES( 100 ); //this value cannot be bigger than 100; | |
| 53 | -const unsigned int NUMBER_OF_GROUP( 7 ); | |
| 54 | -const unsigned int TOTAL_NUMBER_OF_BUBBLES( NUMBER_OF_BUBBLES * NUMBER_OF_GROUP ); | |
| 55 | -} // unnamed namespace | |
| 56 | - | |
| 57 | -class BubbleEffect : public ShaderEffect | |
| 58 | -{ | |
| 59 | -public: | |
| 60 | - | |
| 61 | - BubbleEffect() | |
| 62 | - {} | |
| 63 | - | |
| 64 | - static BubbleEffect New( unsigned int numberOfBubble ) | |
| 65 | - { | |
| 66 | - std::ostringstream meshVertexStringStream; | |
| 67 | - meshVertexStringStream << "#define NUMBER_OF_BUBBLE "<< numberOfBubble << "\n"; | |
| 68 | - std::string meshVertex( | |
| 69 | - " uniform float uGravity; \n" | |
| 70 | - " uniform vec4 uStartAndEndPos[NUMBER_OF_BUBBLE];\n" | |
| 71 | - " uniform float uEasing[NUMBER_OF_BUBBLE];\n" | |
| 72 | - " uniform float uPercentage[NUMBER_OF_BUBBLE];\n" | |
| 73 | - " uniform vec2 uStageSize; \n" | |
| 74 | - " uniform vec2 offset[9]; \n" | |
| 75 | - " varying float vPercentage;\n" | |
| 76 | - " varying vec2 vEffectTexCoord;\n" | |
| 77 | - " void main()\n" | |
| 78 | - " {\n" | |
| 79 | - " mediump vec4 position = vec4( aPosition.x, aPosition.y, 0.0, 1.0 );\n" | |
| 80 | - " int zCoord = int(aPosition.z); \n" | |
| 81 | - " int idx = int(mod(aPosition.z, float(NUMBER_OF_BUBBLE)));\n" | |
| 82 | - " int groupIdx = (zCoord - idx) / NUMBER_OF_BUBBLE;\n" | |
| 83 | - " vec4 startAndEnd = uStartAndEndPos[idx]; \n" | |
| 84 | - " startAndEnd.zw += offset[groupIdx];\n" | |
| 85 | - "\n" | |
| 86 | - " if( uPercentage[idx] < 1.0 )\n" | |
| 87 | - " {\n" | |
| 88 | - " float positionDelta = uPercentage[idx];\n" | |
| 89 | - " if (mod(uEasing[idx], 4.0) > 1.5) { positionDelta = pow(uPercentage[idx], 2.0); } \n" | |
| 90 | - " else if (mod(uEasing[idx], 8.0) > 3.5) { positionDelta = 1.0 - pow((1.0-uPercentage[idx]),2.0); }\n" | |
| 91 | - " else if (mod(uEasing[idx], 16.0) > 7.5) { positionDelta = pow(2.0, 10.0 * (uPercentage[idx] - 1.0)) - 0.001; }\n" | |
| 92 | - " else if (mod(uEasing[idx], 32.0) > 15.5) { positionDelta = 1.001 * (-pow(2.0, -10.0 * uPercentage[idx]) + 1.0); }\n" | |
| 93 | - | |
| 94 | - " position.xy = position.xy + startAndEnd.xy + startAndEnd.zw * positionDelta; \n" | |
| 95 | - " if (mod(uEasing[idx],64.0) > 31.5) { position.y = position.y - (0.5*uGravity * pow(uPercentage[idx]+0.1, 2.0)); }\n" | |
| 96 | - " }\n" | |
| 97 | - " gl_Position = uMvpMatrix * position;\n" | |
| 98 | - "\n" | |
| 99 | - " mediump vec2 start = uCustomTextureCoords.xy;\n" | |
| 100 | - " mediump vec2 scale = uCustomTextureCoords.zw;\n" | |
| 101 | - " vTexCoord = vec2( start.x + aTexCoord.x * scale.x, start.y + aTexCoord.y * scale.y );\n" | |
| 102 | - " vPercentage = uPercentage[idx];\n" | |
| 103 | - " vEffectTexCoord = startAndEnd.xy / uStageSize; \n" | |
| 104 | - " }\n" ); | |
| 105 | - meshVertexStringStream << meshVertex; | |
| 106 | - | |
| 107 | - std::string meshFragment( | |
| 108 | - " varying float vPercentage;\n" | |
| 109 | - " varying vec2 vEffectTexCoord;\n" | |
| 110 | - "\n" | |
| 111 | - " void main()\n" | |
| 112 | - " {\n" | |
| 113 | - " vec4 fragColor = texture2D(sEffect, vEffectTexCoord);\n" | |
| 114 | - " fragColor.rgb *= 1.2; \n" | |
| 115 | - " fragColor *= uColor;\n" | |
| 116 | - " fragColor.a *= texture2D(sTexture, vTexCoord).a * ( 1.0-vPercentage*vPercentage );\n" | |
| 117 | - " gl_FragColor = fragColor;\n" | |
| 118 | - " }\n"); | |
| 119 | - | |
| 120 | - ShaderEffect shaderEffect = ShaderEffect::New( meshVertexStringStream.str(), meshFragment, | |
| 121 | - GeometryType( GEOMETRY_TYPE_TEXTURED_MESH), | |
| 122 | - ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING ) ); | |
| 123 | - BubbleEffect handle( shaderEffect ); | |
| 124 | - handle.mNumOfBubbles = numberOfBubble; | |
| 125 | - handle.SetUniform( "uGravity", 100.f ); | |
| 126 | - handle.SetUniform( "uStageSize", Stage::GetCurrent().GetSize() ); | |
| 127 | - for( unsigned int i=0; i<numberOfBubble; i++ ) | |
| 128 | - { | |
| 129 | - handle.SetPercentage( i, 1.f); | |
| 130 | - } | |
| 131 | - | |
| 132 | - srand(time(NULL)); | |
| 133 | - | |
| 134 | - return handle; | |
| 135 | - } | |
| 136 | - | |
| 137 | - void SetBubbleParameter(unsigned int idx, const Vector2& emitPosition, Vector2 direction) | |
| 138 | - { | |
| 139 | - Vector2 randomVec(rand()%400-200, rand()%400-200); | |
| 140 | - float length = randomVec.Length(); | |
| 141 | - randomVec /= length; | |
| 142 | - direction.Normalize(); | |
| 143 | - Vector2 endPos = (randomVec - direction*4.f); | |
| 144 | - endPos.Normalize(); | |
| 145 | - Vector4 startAndEndPos( emitPosition.x, emitPosition.y, endPos.x*length, endPos.y*length ); | |
| 146 | - SetStartAndEndPos( idx, startAndEndPos ); | |
| 147 | - | |
| 148 | - float easing = pow( 2, rand()%5-1 ) + ( rand()%2-1 )*32; | |
| 149 | - SetEasing( idx, easing ); | |
| 150 | - | |
| 151 | - SetPercentage( idx, 0.f); | |
| 152 | - | |
| 153 | - float offset = 100.f; | |
| 154 | - SetUniform("offset[0]", Vector2(0.f,0.f)); | |
| 155 | - SetUniform("offset[1]", Vector2(offset,0.f)); | |
| 156 | - SetUniform("offset[2]", Vector2(-offset,0.f)); | |
| 157 | - SetUniform("offset[3]", Vector2(0.f,offset)); | |
| 158 | - SetUniform("offset[4]", Vector2(0.f,-offset)); | |
| 159 | - SetUniform("offset[5]", Vector2(offset,offset)*0.707f ); | |
| 160 | - SetUniform("offset[6]", Vector2(offset,-offset)*0.707f); | |
| 161 | - SetUniform("offset[7]", Vector2(-offset,offset)*0.707f); | |
| 162 | - SetUniform("offset[8]", Vector2(-offset,-offset)*0.707f); | |
| 163 | - } | |
| 164 | - | |
| 165 | - std::string GetPercentagePropertyName( unsigned int idx ) const | |
| 166 | - { | |
| 167 | - assert( idx < mNumOfBubbles ); | |
| 168 | - std::ostringstream oss; | |
| 169 | - oss<< "uPercentage["<< idx << "]"; | |
| 170 | - return oss.str(); | |
| 171 | - } | |
| 172 | - | |
| 173 | -private: | |
| 174 | - // Helper for New() | |
| 175 | - BubbleEffect( ShaderEffect handle ) | |
| 176 | - : ShaderEffect( handle ) | |
| 177 | - {} | |
| 178 | - | |
| 179 | - void SetStartAndEndPos( unsigned int idx, const Vector4& startAndEndPos ) | |
| 180 | - { | |
| 181 | - assert( idx < mNumOfBubbles ); | |
| 182 | - std::ostringstream oss; | |
| 183 | - oss<< "uStartAndEndPos["<< idx << "]"; | |
| 184 | - SetUniform( oss.str(), startAndEndPos ); | |
| 185 | - } | |
| 186 | - | |
| 187 | - void SetEasing( unsigned int idx, float easing ) | |
| 188 | - { | |
| 189 | - assert( idx < mNumOfBubbles ); | |
| 190 | - std::ostringstream oss; | |
| 191 | - oss<< "uEasing["<< idx << "]"; | |
| 192 | - SetUniform( oss.str(), easing ); | |
| 193 | - } | |
| 194 | - | |
| 195 | - void SetPercentage( unsigned int idx, float percentage ) | |
| 196 | - { | |
| 197 | - assert( idx < mNumOfBubbles ); | |
| 198 | - std::ostringstream oss; | |
| 199 | - oss<< "uPercentage["<< idx << "]"; | |
| 200 | - SetUniform( oss.str(), percentage ); | |
| 201 | - } | |
| 38 | +const unsigned int NUM_BACKGROUND_IMAGES( sizeof( BACKGROUND_IMAGES ) / sizeof( BACKGROUND_IMAGES[0] ) ); | |
| 202 | 39 | |
| 203 | -private: | |
| 204 | - | |
| 205 | - unsigned int mNumOfBubbles; | |
| 40 | +const char* BUBBLE_SHAPE_IMAGES[] = | |
| 41 | +{ | |
| 42 | + DALI_IMAGE_DIR "blocks-ball.png", | |
| 43 | + DALI_IMAGE_DIR "icon-item-view-layout-spiral.png", | |
| 44 | + DALI_IMAGE_DIR "icon-replace.png", | |
| 45 | + DALI_IMAGE_DIR "icon-effect-cross.png" | |
| 206 | 46 | }; |
| 47 | +const unsigned int NUM_BUBBLE_SHAPE_IMAGES( sizeof( BUBBLE_SHAPE_IMAGES ) / sizeof( BUBBLE_SHAPE_IMAGES[0] ) ); | |
| 48 | + | |
| 49 | +const Vector2 DEFAULT_BUBBLE_SIZE( 10.f, 30.f ); | |
| 50 | +const unsigned int DEFAULT_NUMBER_OF_BUBBLES( 1000 ); | |
| 51 | +}// end LOCAL_STUFF | |
| 207 | 52 | |
| 53 | +// This example shows the usage of BubbleEmitter which displays lots of moving bubbles on the stage. | |
| 208 | 54 | class BubbleEffectExample : public ConnectionTracker |
| 209 | 55 | { |
| 210 | 56 | public: |
| 211 | 57 | BubbleEffectExample(Application &app) |
| 212 | 58 | : mApp(app), |
| 213 | - mCurrentUniform( 0 ), | |
| 214 | - mTouchable( false ), | |
| 215 | - mLastTouchTime( 0 ), | |
| 216 | - mRescoucesCleared( false ), | |
| 217 | - mCurrentBackgroundImageId( 0 ) | |
| 59 | + mHSVDelta( Vector3( 0.f, 0.f, 0.5f ) ), | |
| 60 | + mNeedNewAnimation( true ), | |
| 61 | + mTimerInterval( 16 ), | |
| 62 | + mCurrentBackgroundImageId( 0 ), | |
| 63 | + mCurrentBubbleShapeImageId( 0 ) | |
| 218 | 64 | { |
| 65 | + // Connect to the Application's Init signal | |
| 219 | 66 | app.InitSignal().Connect(this, &BubbleEffectExample::Create); |
| 220 | 67 | } |
| 221 | 68 | |
| ... | ... | @@ -223,264 +70,221 @@ public: |
| 223 | 70 | { |
| 224 | 71 | } |
| 225 | 72 | |
| 226 | -public: | |
| 73 | +private: | |
| 227 | 74 | |
| 75 | + // The Init signal is received once (only) during the Application lifetime | |
| 228 | 76 | void Create(Application& app) |
| 229 | 77 | { |
| 230 | 78 | Stage stage = Stage::GetCurrent(); |
| 231 | - Vector2 size = stage.GetSize(); | |
| 79 | + Vector2 stageSize = stage.GetSize(); | |
| 80 | + | |
| 81 | + stage.KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent); | |
| 232 | 82 | |
| 233 | 83 | // Creates a default view with a default tool bar. |
| 234 | 84 | // The view is added to the stage. |
| 235 | 85 | Toolkit::ToolBar toolBar; |
| 236 | - mContent = DemoHelper::CreateView( app, | |
| 237 | - mView, | |
| 238 | - toolBar, | |
| 239 | - "", | |
| 240 | - TOOLBAR_IMAGE, | |
| 241 | - APPLICATION_TITLE ); | |
| 242 | - | |
| 243 | - // Create a effect toggle button. (right of toolbar) | |
| 244 | - Image imageLayout = Image::New( CHANGE_IMAGE_ICON ); | |
| 245 | - Toolkit::PushButton layoutButton = Toolkit::PushButton::New(); | |
| 246 | - layoutButton.SetBackgroundImage(imageLayout); | |
| 247 | - layoutButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnImageChageIconClicked ); | |
| 248 | - toolBar.AddControl( layoutButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING ); | |
| 249 | - | |
| 250 | - mRoot = Actor::New(); | |
| 251 | - mRoot.SetParentOrigin( ParentOrigin::CENTER ); | |
| 252 | - stage.Add(mRoot); | |
| 253 | - | |
| 254 | - mFrameBufferImage = FrameBufferImage::New( size.width/4.f, size.height/4.f, Pixel::RGBA8888, Dali::Image::Unused ); | |
| 255 | - mTimer = Timer::New( 1000 ); | |
| 256 | - mTimer.TickSignal().Connect( this, &BubbleEffectExample::ClearBlurResource ); | |
| 257 | - | |
| 258 | - SetImage( BACKGROUND_IMAGES[ mCurrentBackgroundImageId ] ); | |
| 259 | - | |
| 260 | - GenMaterial(); | |
| 261 | - MeshData meshData; | |
| 262 | - ConstructBubbleMesh( meshData, NUMBER_OF_BUBBLES*9, BUBBLE_SIZE); | |
| 263 | - for(unsigned int i=0; i < NUMBER_OF_GROUP; i++ ) | |
| 86 | + Toolkit::View view; | |
| 87 | + Layer content = DemoHelper::CreateView( app, | |
| 88 | + view, | |
| 89 | + toolBar, | |
| 90 | + "", | |
| 91 | + TOOLBAR_IMAGE, | |
| 92 | + APPLICATION_TITLE ); | |
| 93 | + | |
| 94 | + // Add a button to change background. (right of toolbar) | |
| 95 | + mChangeBackgroundButton = Toolkit::PushButton::New(); | |
| 96 | + mChangeBackgroundButton.SetBackgroundImage( Image::New( CHANGE_BACKGROUND_ICON ) ); | |
| 97 | + mChangeBackgroundButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked ); | |
| 98 | + toolBar.AddControl( mChangeBackgroundButton, | |
| 99 | + DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, | |
| 100 | + Toolkit::Alignment::HorizontalRight, | |
| 101 | + DemoHelper::DEFAULT_MODE_SWITCH_PADDING ); | |
| 102 | + // Add a button to change bubble shape. ( left of bar ) | |
| 103 | + mChangeBubbleShapeButton = Toolkit::PushButton::New(); | |
| 104 | + mChangeBubbleShapeButton.SetBackgroundImage( Image::New( CHANGE_BUBBLE_SHAPE_ICON ) ); | |
| 105 | + mChangeBubbleShapeButton.ClickedSignal().Connect( this, &BubbleEffectExample::OnChangeIconClicked ); | |
| 106 | + toolBar.AddControl( mChangeBubbleShapeButton, | |
| 107 | + DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, | |
| 108 | + Toolkit::Alignment::HorizontalLeft, | |
| 109 | + DemoHelper::DEFAULT_MODE_SWITCH_PADDING ); | |
| 110 | + | |
| 111 | + // Create and initialize the BubbleEmitter object | |
| 112 | + mBubbleEmitter = Toolkit::BubbleEmitter::New( stageSize, | |
| 113 | + Image::New( BUBBLE_SHAPE_IMAGES[mCurrentBubbleShapeImageId] ), | |
| 114 | + DEFAULT_NUMBER_OF_BUBBLES, | |
| 115 | + DEFAULT_BUBBLE_SIZE); | |
| 116 | + mBackgroundImage = Image::New( BACKGROUND_IMAGES[mCurrentBackgroundImageId] ); | |
| 117 | + mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta ); | |
| 118 | + | |
| 119 | + // Get the root actor of all bubbles, and add it to stage. | |
| 120 | + Actor bubbleRoot = mBubbleEmitter.GetRootActor(); | |
| 121 | + bubbleRoot.SetParentOrigin(ParentOrigin::CENTER); | |
| 122 | + bubbleRoot.SetZ(0.1f); // Make sure the bubbles displayed on top og the background. | |
| 123 | + content.Add( bubbleRoot ); | |
| 124 | + | |
| 125 | + // Add the background image actor to stage | |
| 126 | + mBackgroundActor = ImageActor::New( mBackgroundImage ); | |
| 127 | + view.SetBackground( mBackgroundActor ); | |
| 128 | + | |
| 129 | + // Set up the timer to emit bubble regularly when the finger is touched down but not moved | |
| 130 | + mTimerForBubbleEmission = Timer::New( mTimerInterval ); | |
| 131 | + mTimerForBubbleEmission.TickSignal().Connect(this, &BubbleEffectExample::OnTimerTick); | |
| 132 | + | |
| 133 | + // Connect the callback to the touch signal on the background | |
| 134 | + mBackgroundActor.TouchedSignal().Connect( this, &BubbleEffectExample::OnTouch ); | |
| 135 | + } | |
| 136 | + | |
| 137 | + | |
| 138 | +/*********** | |
| 139 | + * Emit bubbles | |
| 140 | + *****************/ | |
| 141 | + | |
| 142 | + // Set up the animation of emitting bubbles, to be efficient, every animation controls multiple bubbles ( 4 here ) | |
| 143 | + void SetUpAnimation( Vector2 emitPosition, Vector2 direction ) | |
| 144 | + { | |
| 145 | + if( mNeedNewAnimation ) | |
| 264 | 146 | { |
| 265 | - mMesh[i] = Mesh::New( meshData ); | |
| 266 | - mMeshActor[i] = MeshActor::New( mMesh[i] ); | |
| 267 | - mMeshActor[i].SetAffectedByLighting( false ); | |
| 268 | - mMeshActor[i].SetParentOrigin(ParentOrigin::TOP_LEFT); | |
| 269 | - stage.Add( mMeshActor[i] ); | |
| 270 | - mEffect[i] = BubbleEffect::New( NUMBER_OF_BUBBLES ); | |
| 271 | - mEffect[i].SetEffectImage( mFrameBufferImage ); | |
| 272 | - mMeshActor[i].SetShaderEffect( mEffect[i] ); | |
| 147 | + float duration = Random::Range(1.f, 1.5f); | |
| 148 | + mEmitAnimation = Animation::New( duration ); | |
| 149 | + mNeedNewAnimation = false; | |
| 150 | + mAnimateComponentCount = 0; | |
| 273 | 151 | } |
| 274 | 152 | |
| 275 | - Stage::GetCurrent().KeyEventSignal().Connect(this, &BubbleEffectExample::OnKeyEvent); | |
| 153 | + mBubbleEmitter.EmitBubble( mEmitAnimation, emitPosition, direction + Vector2(0.f, 30.f) /* upwards */, Vector2(300, 600) ); | |
| 154 | + | |
| 155 | + mAnimateComponentCount++; | |
| 156 | + | |
| 157 | + if( mAnimateComponentCount % 4 ==0 ) | |
| 158 | + { | |
| 159 | + mEmitAnimation.Play(); | |
| 160 | + mNeedNewAnimation = true; | |
| 161 | + } | |
| 276 | 162 | } |
| 277 | 163 | |
| 278 | - void OnKeyEvent(const KeyEvent& event) | |
| 164 | + // Emit bubbles when the finger touches down but keep stationary. | |
| 165 | + // And stops emitting new bubble after being stationary for 2 seconds | |
| 166 | + bool OnTimerTick() | |
| 279 | 167 | { |
| 280 | - if(event.state == KeyEvent::Down) | |
| 168 | + if(mEmitPosition == mCurrentTouchPosition) // finger is not moving | |
| 281 | 169 | { |
| 282 | - if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) ) | |
| 170 | + mNonMovementCount++; | |
| 171 | + if(mNonMovementCount < (1000 / mTimerInterval)) // 1 seconds | |
| 283 | 172 | { |
| 284 | - mApp.Quit(); | |
| 173 | + for(int i = 0; i < 4; i++) // emit 4 bubbles every timer tick | |
| 174 | + { | |
| 175 | + SetUpAnimation( mCurrentTouchPosition+Vector2(rand()%5, rand()%5), Vector2(rand()%60-30, rand()%100-50) ); | |
| 176 | + } | |
| 285 | 177 | } |
| 286 | 178 | } |
| 287 | - } | |
| 288 | - | |
| 289 | - void SetImage( const std::string& imagePath ) | |
| 290 | - { | |
| 291 | - mTouchable = false; | |
| 292 | - | |
| 293 | - if( mScreen ) | |
| 179 | + else | |
| 294 | 180 | { |
| 295 | - mScreen.TouchedSignal().Disconnect( this, &BubbleEffectExample::OnTouch ); | |
| 296 | - mRoot.Remove( mScreen ); | |
| 297 | - ClearBlurResource(); | |
| 181 | + mNonMovementCount = 0; | |
| 182 | + mEmitPosition = mCurrentTouchPosition; | |
| 298 | 183 | } |
| 299 | 184 | |
| 300 | - Stage stage = Stage::GetCurrent(); | |
| 301 | - | |
| 302 | - Image image = Image::New( imagePath ); | |
| 303 | - mScreen = ImageActor::New( image ); | |
| 304 | - mScreen.SetSize( stage.GetSize() ); | |
| 305 | - mScreen.SetZ( -1.f ); | |
| 306 | - mScreen.SetParentOrigin(ParentOrigin::CENTER); | |
| 307 | - mRoot.Add(mScreen); | |
| 308 | - mScreen.TouchedSignal().Connect( this, &BubbleEffectExample::OnTouch ); | |
| 309 | - | |
| 310 | - mGaussianBlurView = Toolkit::GaussianBlurView::New( 7, 2.5f, Pixel::RGBA8888, 0.25f, 0.25f, true ); | |
| 311 | - mGaussianBlurView.SetParentOrigin(ParentOrigin::CENTER); | |
| 312 | - mGaussianBlurView.SetSize(stage.GetSize()); | |
| 313 | - mGaussianBlurView.SetUserImageAndOutputRenderTarget( image, mFrameBufferImage ); | |
| 314 | - stage.Add( mGaussianBlurView ); | |
| 315 | - mGaussianBlurView.Activate(); | |
| 316 | - | |
| 317 | - mRescoucesCleared = false; | |
| 318 | - mTimer.Start(); | |
| 319 | - | |
| 320 | - mTouchable = true; | |
| 185 | + return true; | |
| 321 | 186 | } |
| 322 | 187 | |
| 323 | - bool ClearBlurResource() | |
| 188 | + // Callback function of the touch signal on the background | |
| 189 | + bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event) | |
| 324 | 190 | { |
| 325 | - if( !mRescoucesCleared ) | |
| 191 | + const TouchPoint &point = event.GetPoint(0); | |
| 192 | + switch(point.state) | |
| 326 | 193 | { |
| 327 | - Stage::GetCurrent().Remove( mGaussianBlurView ); | |
| 328 | - mGaussianBlurView.Deactivate(); | |
| 329 | - mGaussianBlurView.Reset(); | |
| 330 | - mRescoucesCleared = true; | |
| 331 | - } | |
| 332 | - return false; | |
| 333 | - } | |
| 194 | + case TouchPoint::Down: | |
| 195 | + { | |
| 196 | + mCurrentTouchPosition = point.screen; | |
| 197 | + mEmitPosition = point.screen; | |
| 198 | + mTimerForBubbleEmission.Start(); | |
| 199 | + mNonMovementCount = 0; | |
| 334 | 200 | |
| 335 | - void GenMaterial() | |
| 336 | - { | |
| 337 | - mCustomMaterial = Material::New("CustomMaterial"); | |
| 338 | - mCustomMaterial.SetOpacity(1.0f); | |
| 339 | - mCustomMaterial.SetDiffuseColor(Color::WHITE); | |
| 340 | - mCustomMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0)); | |
| 341 | - mCustomMaterial.SetMapU( Material::MAPPING_MODE_WRAP ); | |
| 342 | - mCustomMaterial.SetMapV( Material::MAPPING_MODE_WRAP ); | |
| 343 | - mCustomMaterial.SetDiffuseTexture( Image::New( TEXTURE_IMAGE ) ); | |
| 344 | - } | |
| 201 | + break; | |
| 202 | + } | |
| 203 | + case TouchPoint::Motion: | |
| 204 | + { | |
| 205 | + Vector2 displacement = point.screen - mCurrentTouchPosition; | |
| 206 | + mCurrentTouchPosition = point.screen; | |
| 207 | + //emit multiple bubbles along the moving direction when the finger moves quickly | |
| 208 | + float step = std::min(5.f, displacement.Length()); | |
| 209 | + for( float i=0.25f; i<step; i=i+1.f) | |
| 210 | + { | |
| 211 | + SetUpAnimation( mCurrentTouchPosition+displacement*(i/step), displacement ); | |
| 212 | + } | |
| 213 | + break; | |
| 214 | + } | |
| 215 | + case TouchPoint::Up: | |
| 216 | + case TouchPoint::Leave: | |
| 217 | + case TouchPoint::Interrupted: | |
| 218 | + { | |
| 219 | + mTimerForBubbleEmission.Stop(); | |
| 220 | + break; | |
| 221 | + } | |
| 222 | + case TouchPoint::Stationary: | |
| 223 | + case TouchPoint::Last: | |
| 224 | + default: | |
| 225 | + { | |
| 226 | + break; | |
| 227 | + } | |
| 345 | 228 | |
| 346 | - void AddVertex(MeshData::VertexContainer& vertices, Vector3 V, Vector2 UV) | |
| 347 | - { | |
| 348 | - MeshData::Vertex meshVertex; | |
| 349 | - meshVertex.x = V.x; | |
| 350 | - meshVertex.y = V.y; | |
| 351 | - meshVertex.z = V.z; | |
| 352 | - meshVertex.u = UV.x; | |
| 353 | - meshVertex.v = UV.y; | |
| 354 | - vertices.push_back(meshVertex); | |
| 229 | + } | |
| 230 | + return true; | |
| 355 | 231 | } |
| 356 | 232 | |
| 357 | - void AddTriangle(MeshData::FaceIndices& faces, | |
| 358 | - size_t v0, size_t v1, size_t v2) | |
| 233 | + bool OnChangeIconClicked( Toolkit::Button button ) | |
| 359 | 234 | { |
| 360 | - faces.push_back(v0); | |
| 361 | - faces.push_back(v1); | |
| 362 | - faces.push_back(v2); | |
| 363 | - } | |
| 235 | + if(button == mChangeBackgroundButton) | |
| 236 | + { | |
| 237 | + mBackgroundImage = Image::New( BACKGROUND_IMAGES[ ++mCurrentBackgroundImageId % NUM_BACKGROUND_IMAGES ] ); | |
| 364 | 238 | |
| 365 | - void ConstructBubbleMesh( MeshData& meshData, unsigned int numOfBubble, int size ) | |
| 366 | - { | |
| 367 | - MeshData::VertexContainer vertices; | |
| 368 | - MeshData::FaceIndices faces; | |
| 369 | - BoneContainer bones(0); | |
| 239 | + mBubbleEmitter.SetBackground( mBackgroundImage, mHSVDelta ); | |
| 370 | 240 | |
| 371 | - for(unsigned int index = 0; index < numOfBubble; index ++) | |
| 241 | + mBackgroundActor.SetImage( mBackgroundImage ); | |
| 242 | + } | |
| 243 | + else if( button == mChangeBubbleShapeButton ) | |
| 372 | 244 | { |
| 373 | - float curSize = static_cast<float>( rand()%size + BUBBLE_MIN_SIZE); | |
| 374 | - float depth = static_cast<float>( index ); | |
| 375 | - AddVertex( vertices, Vector3(0.f,0.f,depth), Vector2(0.f,0.f) ); | |
| 376 | - AddVertex( vertices, Vector3(0.f,curSize,depth), Vector2( 0.f,1.f )); | |
| 377 | - AddVertex( vertices, Vector3(curSize,curSize,depth), Vector2(1.f,1.f) ); | |
| 378 | - AddVertex( vertices, Vector3(curSize,0.f,depth), Vector2(1.f,0.f) ); | |
| 379 | - | |
| 380 | - unsigned int idx = index * 4; | |
| 381 | - AddTriangle( faces, idx, idx+1, idx+2); | |
| 382 | - AddTriangle( faces, idx, idx+2, idx+3); | |
| 245 | + mBubbleEmitter.SetShapeImage( Image::New( BUBBLE_SHAPE_IMAGES[ ++mCurrentBubbleShapeImageId % NUM_BUBBLE_SHAPE_IMAGES ] ) ); | |
| 383 | 246 | } |
| 384 | - | |
| 385 | - meshData.SetData(vertices, faces, bones, mCustomMaterial); | |
| 386 | - meshData.SetHasColor(false); | |
| 387 | - meshData.SetHasNormals(true); | |
| 388 | - meshData.SetHasTextureCoords(true); | |
| 247 | + return true; | |
| 389 | 248 | } |
| 390 | 249 | |
| 391 | - void SetUpAnimation( Vector2 emitPosition, Vector2 direction ) | |
| 250 | + /** | |
| 251 | + * Main key event handler | |
| 252 | + */ | |
| 253 | + void OnKeyEvent(const KeyEvent& event) | |
| 392 | 254 | { |
| 393 | - unsigned int curUniform = mCurrentUniform % NUMBER_OF_BUBBLES; | |
| 394 | - unsigned int groupIdx = mCurrentUniform / NUMBER_OF_BUBBLES; | |
| 395 | - mEffect[groupIdx].SetBubbleParameter(curUniform, emitPosition, direction); | |
| 396 | - float duration = RandomRange( 1.f, 2.f ); | |
| 397 | - mAnimation[mCurrentUniform] = Animation::New( duration ); | |
| 398 | - mAnimationIndexPair[mAnimation[mCurrentUniform]] = mCurrentUniform; | |
| 399 | - mAnimation[mCurrentUniform].AnimateTo( Property( mEffect[groupIdx], mEffect[groupIdx].GetPercentagePropertyName(curUniform) ), | |
| 400 | - 1.f, AlphaFunctions::DoubleEaseInOutSine60 ); | |
| 401 | - mAnimation[mCurrentUniform].Play(); | |
| 402 | - mAnimation[mCurrentUniform].FinishedSignal().Connect(this, &BubbleEffectExample::OnAnimationFinished); | |
| 403 | - | |
| 404 | - mCurrentUniform = (mCurrentUniform + 1) % (TOTAL_NUMBER_OF_BUBBLES); | |
| 255 | + if(event.state == KeyEvent::Down) | |
| 256 | + { | |
| 257 | + if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) ) | |
| 258 | + { | |
| 259 | + mApp.Quit(); | |
| 260 | + } | |
| 261 | + } | |
| 405 | 262 | } |
| 406 | 263 | |
| 407 | - void OnAnimationFinished( Animation& source ) | |
| 408 | - { | |
| 409 | - mAnimation[mAnimationIndexPair[source]].Reset(); | |
| 410 | - mAnimationIndexPair.erase( source ); | |
| 411 | - } | |
| 264 | +private: | |
| 412 | 265 | |
| 413 | - float RandomRange(float f0, float f1) | |
| 414 | - { | |
| 415 | - return f0 + (rand() & 0xfff) * (f1-f0) * (1.0f/4095.0f); | |
| 416 | - } | |
| 266 | + Application& mApp; | |
| 267 | + Image mBackgroundImage; | |
| 268 | + ImageActor mBackgroundActor; | |
| 417 | 269 | |
| 418 | - bool OnTouch(Dali::Actor actor, const Dali::TouchEvent& event) | |
| 419 | - { | |
| 420 | - if(!mTouchable) | |
| 421 | - { | |
| 422 | - return false; | |
| 423 | - } | |
| 270 | + Toolkit::BubbleEmitter mBubbleEmitter; | |
| 271 | + Vector3 mHSVDelta; | |
| 424 | 272 | |
| 425 | - if ( event.GetPointCount() > 0 ) | |
| 426 | - { | |
| 427 | - const TouchPoint &point = event.GetPoint(0); | |
| 428 | - float distance = hypotf( point.local.x - mLastTouchPosition.x, point.local.y - mLastTouchPosition.y ); | |
| 429 | - if ( distance > MIN_DISTANCE ) | |
| 430 | - { | |
| 431 | - // when the finger moves fast, interpolate linearly between two touch points | |
| 432 | - if(event.time - mLastTouchTime < MAX_TIME_INTERVAL && distance < MAX_DISTANCE) | |
| 433 | - { | |
| 434 | - float num = floor(distance / MIN_DISTANCE); | |
| 435 | - unsigned int numStep = static_cast<unsigned int>( num ); | |
| 436 | - Vector2 step = ( point.screen - mLastTouchPosition ) * MIN_DISTANCE / distance; | |
| 437 | - for(unsigned int i = 0; i<numStep; i++) | |
| 438 | - { | |
| 439 | - SetUpAnimation( mLastTouchPosition + step*i, step ); | |
| 440 | - } | |
| 441 | - } | |
| 442 | - else | |
| 443 | - { | |
| 444 | - SetUpAnimation( point.screen, point.screen-mLastTouchPosition ); | |
| 445 | - } | |
| 273 | + Animation mEmitAnimation; | |
| 274 | + unsigned int mAnimateComponentCount; | |
| 275 | + bool mNeedNewAnimation; | |
| 446 | 276 | |
| 447 | - mLastTouchTime = event.time; | |
| 448 | - mLastTouchPosition = point.screen; | |
| 449 | - } | |
| 450 | - } | |
| 451 | - return true; | |
| 452 | - } | |
| 277 | + Timer mTimerForBubbleEmission; | |
| 278 | + unsigned int mNonMovementCount; | |
| 279 | + unsigned int mTimerInterval; | |
| 453 | 280 | |
| 454 | - bool OnImageChageIconClicked( Toolkit::Button button ) | |
| 455 | - { | |
| 456 | - mCurrentBackgroundImageId = (mCurrentBackgroundImageId + 1 ) % NUM_BACKGROUND_IMAGES; | |
| 457 | - SetImage( BACKGROUND_IMAGES[ mCurrentBackgroundImageId ] ); | |
| 458 | - return true; | |
| 459 | - } | |
| 281 | + Vector2 mCurrentTouchPosition; | |
| 282 | + Vector2 mEmitPosition; | |
| 460 | 283 | |
| 461 | -private: | |
| 462 | - Application& mApp; | |
| 463 | - Actor mRoot; | |
| 464 | - ImageActor mScreen; | |
| 465 | - Mesh mMesh[NUMBER_OF_GROUP]; | |
| 466 | - MeshActor mMeshActor[NUMBER_OF_GROUP]; | |
| 467 | - Material mCustomMaterial; | |
| 468 | - BubbleEffect mEffect[NUMBER_OF_GROUP]; | |
| 469 | - unsigned int mCurrentUniform; | |
| 470 | - Animation mAnimation[TOTAL_NUMBER_OF_BUBBLES]; | |
| 471 | - bool mTouchable; | |
| 472 | - std::map<Animation, unsigned int> mAnimationIndexPair; | |
| 473 | - unsigned long mLastTouchTime; | |
| 474 | - Vector2 mLastTouchPosition; | |
| 475 | - | |
| 476 | - Toolkit::GaussianBlurView mGaussianBlurView; | |
| 477 | - FrameBufferImage mFrameBufferImage; | |
| 478 | - Timer mTimer; | |
| 479 | - bool mRescoucesCleared; | |
| 480 | - | |
| 481 | - Layer mContent; | |
| 482 | - Toolkit::View mView; | |
| 483 | - unsigned int mCurrentBackgroundImageId; | |
| 284 | + Toolkit::PushButton mChangeBackgroundButton; | |
| 285 | + Toolkit::PushButton mChangeBubbleShapeButton; | |
| 286 | + unsigned int mCurrentBackgroundImageId; | |
| 287 | + unsigned int mCurrentBubbleShapeImageId; | |
| 484 | 288 | }; |
| 485 | 289 | |
| 486 | 290 | /*****************************************************************************/ | ... | ... |