+void DaliTableView::SetupBackground( Actor bubbleContainer )
+{
+ // Create distance field shapes.
+ BufferImage distanceFields[2];
+ Size imageSize( 512, 512 );
+
+ CreateShapeImage( CIRCLE, imageSize, distanceFields[0] );
+ CreateShapeImage( BUBBLE, imageSize, distanceFields[1] );
+
+ // Add bubbles to the bubbleContainer.
+ // Note: The bubbleContainer is parented externally to this function.
+ AddBackgroundActors( bubbleContainer, NUM_BACKGROUND_IMAGES, distanceFields );
+}
+
+void DaliTableView::InitialiseBackgroundActors( Actor actor )
+{
+ // Delete current animations
+ mBackgroundAnimations.clear();
+
+ // Create new animations
+ const Vector3 size = actor.GetTargetSize();
+
+ for( unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i )
+ {
+ Actor child = actor.GetChildAt( i );
+
+ // Calculate a random position
+ Vector3 childPos( Random::Range( -size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.85f * BACKGROUND_SPREAD_SCALE ),
+ Random::Range( -size.y, size.y ),
+ Random::Range( BUBBLE_MIN_Z, BUBBLE_MAX_Z ) );
+
+ child.SetPosition( childPos );
+
+ // Define bubble horizontal parallax and vertical wrapping
+ Constraint animConstraint = Constraint::New < Vector3 > ( child, Actor::Property::POSITION, AnimateBubbleConstraint( childPos, Random::Range( -0.85f, 0.25f ) ) );
+ animConstraint.AddSource( Source( mScrollView, ScrollView::Property::SCROLL_POSITION ) );
+ animConstraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
+ animConstraint.AddSource( Dali::LocalSource( Dali::Actor::Property::SIZE ) );
+ animConstraint.SetRemoveAction( Constraint::Discard );
+ animConstraint.Apply();
+
+ // Kickoff animation
+ Animation animation = Animation::New( Random::Range( 30.0f, 160.0f ) );
+ animation.AnimateBy( Property( child, Actor::Property::POSITION ), Vector3( 0.0f, -2000.0f, 0.0f ), AlphaFunction::LINEAR );
+ animation.SetLooping( true );
+ animation.Play();
+ mBackgroundAnimations.push_back( animation );
+ }
+}
+
+void DaliTableView::AddBackgroundActors( Actor layer, int count, BufferImage* distanceField )
+{
+ for( int i = 0; i < count; ++i )
+ {
+ float randSize = Random::Range( 10.0f, 400.0f );
+ int distanceFieldType = static_cast<int>( Random::Range( 0.0f, 1.0f ) + 0.5f );
+ ImageView dfActor = ImageView::New( distanceField[ distanceFieldType ] );
+ dfActor.SetSize( Vector2( randSize, randSize ) );
+ dfActor.SetParentOrigin( ParentOrigin::CENTER );
+
+ Dali::Property::Map effect = Toolkit::CreateDistanceFieldEffect();
+ dfActor.SetProperty( Toolkit::ImageView::Property::IMAGE, effect );
+ dfActor.SetColor( BUBBLE_COLOR[ i%NUMBER_OF_BUBBLE_COLOR ] );
+
+ layer.Add( dfActor );
+ }
+
+ // Positioning will occur when the layer is relaid out
+ layer.OnRelayoutSignal().Connect( this, &DaliTableView::InitialiseBackgroundActors );
+}
+
+void DaliTableView::CreateShapeImage( ShapeType shapeType, const Size& size, BufferImage& distanceFieldOut )
+{
+ // this bitmap will hold the alpha map for the distance field shader
+ distanceFieldOut = BufferImage::New( size.width, size.height, Pixel::A8 );
+
+ // Generate bit pattern
+ std::vector< unsigned char > imageDataA8;
+ imageDataA8.reserve( size.width * size.height ); // A8
+
+ switch( shapeType )
+ {
+ case CIRCLE:
+ GenerateCircle( size, imageDataA8 );
+ break;
+ case BUBBLE:
+ GenerateCircle( size, imageDataA8, true );
+ break;
+ default:
+ break;
+ }
+
+ PixelBuffer* buffer = distanceFieldOut.GetBuffer();
+ if( buffer )
+ {
+ GenerateDistanceFieldMap( &imageDataA8[ 0 ], size, buffer, size, 8.0f, size );
+ distanceFieldOut.Update();
+ }
+}
+
+void DaliTableView::GenerateCircle( const Size& size, std::vector< unsigned char >& distanceFieldOut, bool hollow )
+{
+ const float radius = size.width * 0.5f * size.width * 0.5f;
+ Vector2 center( size.width / 2, size.height / 2 );
+
+ for( int h = 0; h < size.height; ++h )
+ {
+ for( int w = 0; w < size.width; ++w )
+ {
+ Vector2 pos( w, h );
+ Vector2 dist = pos - center;
+
+ float distance = ( dist.x * dist.x ) + ( dist.y * dist.y );
+
+ // If hollow, check the distance against a min & max value, otherwise just use the max value.
+ unsigned char fillByte = ( hollow ? ( ( distance <= radius ) && ( distance > ( radius * 0.7f ) ) ) : ( distance <= radius ) ) ? 0xFF : 0x00;
+
+ distanceFieldOut.push_back( fillByte );
+ }
+ }
+}
+