2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
19 #include "bubble-animator.h"
\r
21 #include <dali/public-api/animation/constraint.h>
\r
22 #include <dali/public-api/math/random.h>
\r
23 #include <dali/public-api/rendering/shader.h>
\r
24 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
\r
25 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
\r
26 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
\r
27 #include <dali-toolkit/devel-api/shader-effects/distance-field-effect.h>
\r
29 using namespace Dali;
\r
30 using namespace Dali::Toolkit;
\r
34 const char* const BUBBLE_COLOR_STYLE_NAME[] =
\r
41 constexpr int NUMBER_OF_BUBBLE_COLORS(sizeof(BUBBLE_COLOR_STYLE_NAME) / sizeof(BUBBLE_COLOR_STYLE_NAME[0]));
\r
43 const char* const SHAPE_IMAGE_TABLE[] =
\r
45 DEMO_IMAGE_DIR "shape-circle.png",
\r
46 DEMO_IMAGE_DIR "shape-bubble.png"
\r
48 constexpr int NUMBER_OF_SHAPE_IMAGES(sizeof(SHAPE_IMAGE_TABLE) / sizeof(SHAPE_IMAGE_TABLE[0]));
\r
50 constexpr int NUM_BACKGROUND_IMAGES = 18;
\r
51 constexpr float BACKGROUND_SPREAD_SCALE = 1.5f;
\r
53 constexpr unsigned int BACKGROUND_ANIMATION_DURATION = 15000; // 15 secs
\r
55 constexpr float BUBBLE_MIN_Z = -1.0;
\r
56 constexpr float BUBBLE_MAX_Z = 0.0f;
\r
59 * Constraint to return a position for a bubble based on the scroll value and vertical wrapping
\r
61 struct AnimateBubbleConstraint
\r
64 AnimateBubbleConstraint(const Vector3& initialPos, float scale)
\r
65 : mInitialX(initialPos.x),
\r
70 void operator()(Vector3& position, const PropertyInputContainer& inputs)
\r
72 const Vector3& parentSize = inputs[1]->GetVector3();
\r
73 const Vector3& childSize = inputs[2]->GetVector3();
\r
75 // Wrap bubbles vertically.
\r
76 float range = parentSize.y + childSize.y;
\r
77 // This performs a float mod (we don't use fmod as we want the arithmetic modulus as opposed to the remainder).
\r
78 position.y -= range * (floor(position.y / range) + 0.5f);
\r
80 // Bubbles X position moves parallax to horizontal
\r
81 // panning by a scale factor unique to each bubble.
\r
82 position.x = mInitialX + (inputs[0]->GetVector2().x * mScale);
\r
90 } // unnamed namespace
\r
92 void BubbleAnimator::Initialize(Dali::Actor parent, Dali::Actor scrollView)
\r
94 mScrollView = scrollView;
\r
96 // Populate background and bubbles - needs to be scrollViewLayer so scroll ends show
\r
97 Actor bubbleContainer = Actor::New();
\r
98 bubbleContainer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
\r
99 bubbleContainer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
\r
100 bubbleContainer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
\r
101 AddBackgroundActors(bubbleContainer, NUM_BACKGROUND_IMAGES);
\r
102 parent.Add(bubbleContainer);
\r
104 // Background animation
\r
105 mAnimationTimer = Timer::New(BACKGROUND_ANIMATION_DURATION);
\r
106 mAnimationTimer.TickSignal().Connect(this, &BubbleAnimator::PauseAnimation);
\r
107 mAnimationTimer.Start();
\r
108 mBackgroundAnimsPlaying = true;
\r
111 bool BubbleAnimator::PauseAnimation()
\r
113 if(mBackgroundAnimsPlaying)
\r
115 for(auto&& anim : mBackgroundAnimations)
\r
120 mBackgroundAnimsPlaying = false;
\r
125 void BubbleAnimator::PlayAnimation()
\r
127 if(!mBackgroundAnimsPlaying)
\r
129 for(auto&& anim : mBackgroundAnimations)
\r
134 mBackgroundAnimsPlaying = true;
\r
137 mAnimationTimer.SetInterval(BACKGROUND_ANIMATION_DURATION);
\r
139 void BubbleAnimator::InitializeBackgroundActors(Dali::Actor actor)
\r
141 // Delete current animations
\r
142 mBackgroundAnimations.clear();
\r
144 // Create new animations
\r
145 const Vector3 size = actor.GetTargetSize();
\r
147 for(unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i)
\r
149 Actor child = actor.GetChildAt(i);
\r
151 // Calculate a random position
\r
152 Vector3 childPos(Random::Range(-size.x * 0.5f * BACKGROUND_SPREAD_SCALE, size.x * 0.85f * BACKGROUND_SPREAD_SCALE),
\r
153 Random::Range(-size.y, size.y),
\r
154 Random::Range(BUBBLE_MIN_Z, BUBBLE_MAX_Z));
\r
156 child.SetProperty(Actor::Property::POSITION, childPos);
\r
158 // Define bubble horizontal parallax and vertical wrapping
\r
159 Actor scrollView = mScrollView.GetHandle();
\r
162 Constraint animConstraint = Constraint::New<Vector3>(child, Actor::Property::POSITION, AnimateBubbleConstraint(childPos, Random::Range(-0.85f, 0.25f)));
\r
163 animConstraint.AddSource(Source(scrollView, ScrollView::Property::SCROLL_POSITION));
\r
164 animConstraint.AddSource(Dali::ParentSource(Dali::Actor::Property::SIZE));
\r
165 animConstraint.AddSource(Dali::LocalSource(Dali::Actor::Property::SIZE));
\r
166 animConstraint.SetRemoveAction(Constraint::DISCARD);
\r
167 animConstraint.Apply();
\r
170 // Kickoff animation
\r
171 Animation animation = Animation::New(Random::Range(30.0f, 160.0f));
\r
172 animation.AnimateBy(Property(child, Actor::Property::POSITION), Vector3(0.0f, -2000.0f, 0.0f), AlphaFunction::LINEAR);
\r
173 animation.SetLooping(true);
\r
175 mBackgroundAnimations.push_back(animation);
\r
180 void BubbleAnimator::AddBackgroundActors(Actor layer, int count)
\r
182 for(int i = 0; i < count; ++i)
\r
184 float randSize = Random::Range(10.0f, 400.0f);
\r
185 int shapeType = static_cast<int>(Random::Range(0.0f, NUMBER_OF_SHAPE_IMAGES - 1) + 0.5f);
\r
187 ImageView dfActor = ImageView::New();
\r
188 dfActor.SetProperty(Actor::Property::SIZE, Vector2(randSize, randSize));
\r
189 dfActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
\r
191 // Set the Image URL and the custom shader at the same time
\r
192 Dali::Property::Map effect = Toolkit::CreateDistanceFieldEffect();
\r
193 Property::Map imageMap;
\r
194 imageMap.Add(ImageVisual::Property::URL, SHAPE_IMAGE_TABLE[shapeType]);
\r
195 imageMap.Add(Toolkit::Visual::Property::SHADER, effect);
\r
196 dfActor.SetProperty(Toolkit::ImageView::Property::IMAGE, imageMap);
\r
198 dfActor.SetStyleName(BUBBLE_COLOR_STYLE_NAME[i % NUMBER_OF_BUBBLE_COLORS]);
\r
200 layer.Add(dfActor);
\r
203 // Positioning will occur when the layer is relaid out
\r
204 layer.OnRelayoutSignal().Connect(this, &BubbleAnimator::InitializeBackgroundActors);
\r