DALi Version 2.0.11
[platform/core/uifw/dali-demo.git] / shared / bubble-animator.cpp
1 /*\r
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
3  *\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
7  *\r
8  * http://www.apache.org/licenses/LICENSE-2.0\r
9  *\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
15  *\r
16  */\r
17 \r
18 // CLASS HEADER\r
19 #include "bubble-animator.h"\r
20 \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
28 \r
29 using namespace Dali;\r
30 using namespace Dali::Toolkit;\r
31 \r
32 namespace\r
33 {\r
34 const char* const BUBBLE_COLOR_STYLE_NAME[] =\r
35 {\r
36   "BubbleColor1",\r
37   "BubbleColor2",\r
38   "BubbleColor3",\r
39   "BubbleColor4"\r
40 };\r
41 constexpr int NUMBER_OF_BUBBLE_COLORS(sizeof(BUBBLE_COLOR_STYLE_NAME) / sizeof(BUBBLE_COLOR_STYLE_NAME[0]));\r
42 \r
43 const char* const SHAPE_IMAGE_TABLE[] =\r
44 {\r
45   DEMO_IMAGE_DIR "shape-circle.png",\r
46   DEMO_IMAGE_DIR "shape-bubble.png"\r
47 };\r
48 constexpr int NUMBER_OF_SHAPE_IMAGES(sizeof(SHAPE_IMAGE_TABLE) / sizeof(SHAPE_IMAGE_TABLE[0]));\r
49 \r
50 constexpr int   NUM_BACKGROUND_IMAGES   = 18;\r
51 constexpr float BACKGROUND_SPREAD_SCALE = 1.5f;\r
52 \r
53 constexpr unsigned int BACKGROUND_ANIMATION_DURATION = 15000; // 15 secs\r
54 \r
55 constexpr float BUBBLE_MIN_Z = -1.0;\r
56 constexpr float BUBBLE_MAX_Z = 0.0f;\r
57 \r
58 /**\r
59  * Constraint to return a position for a bubble based on the scroll value and vertical wrapping\r
60  */\r
61 struct AnimateBubbleConstraint\r
62 {\r
63 public:\r
64   AnimateBubbleConstraint(const Vector3& initialPos, float scale)\r
65   : mInitialX(initialPos.x),\r
66     mScale(scale)\r
67   {\r
68   }\r
69 \r
70   void operator()(Vector3& position, const PropertyInputContainer& inputs)\r
71   {\r
72     const Vector3& parentSize = inputs[1]->GetVector3();\r
73     const Vector3& childSize  = inputs[2]->GetVector3();\r
74 \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
79 \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
83   }\r
84 \r
85 private:\r
86   float mInitialX;\r
87   float mScale;\r
88 };\r
89 \r
90 } // unnamed namespace\r
91 \r
92 void BubbleAnimator::Initialize(Dali::Actor parent, Dali::Actor scrollView)\r
93 {\r
94   mScrollView = scrollView;\r
95 \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
103 \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
109 }\r
110 \r
111 bool BubbleAnimator::PauseAnimation()\r
112 {\r
113   if(mBackgroundAnimsPlaying)\r
114   {\r
115     for(auto&& anim : mBackgroundAnimations)\r
116     {\r
117       anim.Stop();\r
118     }\r
119 \r
120     mBackgroundAnimsPlaying = false;\r
121   }\r
122   return false;\r
123 }\r
124 \r
125 void BubbleAnimator::PlayAnimation()\r
126 {\r
127   if(!mBackgroundAnimsPlaying)\r
128   {\r
129     for(auto&& anim : mBackgroundAnimations)\r
130     {\r
131       anim.Play();\r
132     }\r
133 \r
134     mBackgroundAnimsPlaying = true;\r
135   }\r
136 \r
137   mAnimationTimer.SetInterval(BACKGROUND_ANIMATION_DURATION);\r
138 }\r
139 void BubbleAnimator::InitializeBackgroundActors(Dali::Actor actor)\r
140 {\r
141   // Delete current animations\r
142   mBackgroundAnimations.clear();\r
143 \r
144   // Create new animations\r
145   const Vector3 size = actor.GetTargetSize();\r
146 \r
147   for(unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i)\r
148   {\r
149     Actor child = actor.GetChildAt(i);\r
150 \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
155 \r
156     child.SetProperty(Actor::Property::POSITION, childPos);\r
157 \r
158     // Define bubble horizontal parallax and vertical wrapping\r
159     Actor scrollView = mScrollView.GetHandle();\r
160     if( scrollView )\r
161     {\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
168     }\r
169 \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
174     animation.Play();\r
175     mBackgroundAnimations.push_back(animation);\r
176   }\r
177 \r
178 }\r
179 \r
180 void BubbleAnimator::AddBackgroundActors(Actor layer, int count)\r
181 {\r
182   for(int i = 0; i < count; ++i)\r
183   {\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
186 \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
190 \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
197 \r
198     dfActor.SetStyleName(BUBBLE_COLOR_STYLE_NAME[i % NUMBER_OF_BUBBLE_COLORS]);\r
199 \r
200     layer.Add(dfActor);\r
201   }\r
202 \r
203   // Positioning will occur when the layer is relaid out\r
204   layer.OnRelayoutSignal().Connect(this, &BubbleAnimator::InitializeBackgroundActors);\r
205 }\r