095f3e7e3f4a7749597f4551daf32b50c23ec870
[platform/core/uifw/dali-demo.git] / examples / color-transition / color-transition.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 #include "utils.h"
18 #include "color-transition-controller.h"
19 #include "dali/dali.h"
20 #include "dali-toolkit/dali-toolkit.h"
21
22 using namespace Dali;
23 using namespace Dali::Toolkit;
24
25 namespace
26 {
27 const float TRANSITION_DURATION = 1.f;
28
29 const Vector3 INITIAL_COLOR{ 1.f, 1.f, .25f };
30
31 const char* const FLOW_MAPS[] = {
32   "circular",
33   "multi-circle",
34   "concentric",
35   "spiral",
36   "conical",
37   "blinds",
38   "radial",
39   "swipe",
40   "bubbles",
41   "image"
42 };
43
44 Texture LoadTexture(const std::string& path)
45 {
46   PixelData pixelData = SyncImageLoader::Load(path);
47
48   Texture texture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(),
49     pixelData.GetWidth(), pixelData.GetHeight());
50   texture.Upload(pixelData);
51   return texture;
52 }
53
54 TextLabel MakeTextLabel(const char* text, const Vector4& color, float pointSize, const Vector2& size)
55 {
56   auto tl = TextLabel::New(text);
57   CenterActor(tl);
58   tl.SetProperty(Actor::Property::SIZE, size);
59   tl.SetProperty(TextLabel::Property::POINT_SIZE, pointSize);
60   tl.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
61   tl.SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
62   tl.SetProperty(TextLabel::Property::MULTI_LINE, true);
63   tl.SetProperty(TextLabel::Property::TEXT_COLOR, color);
64   return tl;
65 }
66
67 }
68
69 /**
70  * Demonstrates colour transition using flow maps and uv rotation / scaling.
71  *
72  * Flow maps are greyscale images where the value of the pixels signifies the
73  * progress of the animation, which is added to an animated value which we
74  * use to lerp between old and new colour.
75  *
76  * The colour of the content is used to scale the source / target colour, i.e.
77  * white is affected most, dark is affected less.
78  *
79  * Controls:
80  * - Double-tap middle (33%) of screen: transition using random flow map;
81  * - Double-tap outside the middle of screen: transition using one of the
82  *   effects (flow maps) mapped to the given segment of the screen;
83  */
84 class ColorTransition: public ConnectionTracker
85 {
86 public:
87   ColorTransition(Application& app)
88   : mApp(app)
89   {
90     app.InitSignal().Connect(this, &ColorTransition::OnInit);
91     app.TerminateSignal().Connect(this, &ColorTransition::OnTerminate);
92   }
93
94 private:
95   static void OnTransitionFinished(void* data)
96   {
97     auto& me = *static_cast<ColorTransition*>(data);
98     me.OnTransitionFinished();
99   }
100
101   void OnInit(Application& app)
102   {
103     auto window = mApp.GetWindow();
104     auto windowSize = Vector2{ window.GetSize() };
105
106     // create content root
107     Actor content = Actor::New();
108     CenterActor(content);
109     content.SetProperty(Actor::Property::SIZE, windowSize);
110     window.Add(content);
111     mColorTransitionContent = content;
112
113     // create some example content
114     TextLabel tlHello = MakeTextLabel("<b>HELLO</b>", Vector4::ONE, 60.f, windowSize);
115     tlHello.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
116     tlHello.SetProperty(Actor::Property::POSITION_Y, -60.f);
117     content.Add(tlHello);
118
119     TextLabel tlWorld = MakeTextLabel("<i>WORLD</i>", Vector4(1.f, 1.f, 1.f, .5f), 60.f, windowSize);
120     tlWorld.SetProperty(TextLabel::Property::ENABLE_MARKUP, true);
121     tlWorld.SetProperty(Actor::Property::POSITION_Y, 60.f);
122     content.Add(tlWorld);
123
124     ImageView ivIcon = ImageView::New(Application::GetResourcePath() + "images/application-icon-2.png");
125     CenterActor(ivIcon);
126     ivIcon.SetProperty(Actor::Property::POSITION_Y, 120.f);
127     content.Add(ivIcon);
128
129     // create main root
130     Actor mainRoot = Actor::New();
131     CenterActor(mainRoot);
132     window.Add(mainRoot);
133     mMainRoot = mainRoot;
134
135     auto renderTasks = window.GetRenderTaskList();
136     auto weakRenderTasks = WeakHandle<RenderTaskList>(renderTasks);
137     auto controller = new ColorTransitionController(weakRenderTasks, content, window.GetRenderTaskList(), INITIAL_COLOR);
138     mController.reset(controller);
139     mainRoot.Add(mController->GetComposite());
140
141     // add content unaffected by effect, to scene.
142     TextLabel tlInstructions = MakeTextLabel("Double tap to change Color", Vector4(.5f, .5f, .5f, 1.f), 10.f, windowSize);
143     tlInstructions.SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "TOP");
144     mainRoot.Add(tlInstructions);
145
146     // hook up event handlers
147     window.KeyEventSignal().Connect(this, &ColorTransition::OnKeyEvent);
148
149     auto tapDetector = TapGestureDetector::New(2);
150     tapDetector.DetectedSignal().Connect(this, &ColorTransition::OnDoubleTap);
151     tapDetector.Attach(window.GetRootLayer());
152     mDoubleTapDetector = tapDetector;
153
154     mController->SetOnFinished(OnTransitionFinished, this);
155   }
156
157   void OnTerminate(Application& app)
158   {
159     auto window = mApp.GetWindow();
160     mDoubleTapDetector.Detach(window.GetRootLayer());
161
162     UnparentAndReset(mColorTransitionContent);
163     UnparentAndReset(mMainRoot);
164
165     mController.reset();
166   }
167
168   void OnKeyEvent(const KeyEvent& event)
169   {
170     if (event.GetState() == KeyEvent::DOWN)
171     {
172       if (IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
173       {
174         mApp.Quit();
175       }
176     }
177   }
178
179   void OnDoubleTap(Actor /*actor*/, const TapGesture& tap)
180   {
181     auto window = mApp.GetWindow();
182     auto windowSize = Vector2{ window.GetSize() };
183     Vector2 clip = tap.GetScreenPoint() / windowSize - Vector2::ONE * .5f; // [-.5, .5]
184     if (clip.Length() < .333f * .5f)
185     {
186       LoadFlowMap(FLOW_MAPS[rand() % std::extent<decltype(FLOW_MAPS)>::value]);
187     }
188     else
189     {
190       float theta = fmodf((atan2(clip.y, clip.x) + M_PI) / (M_PI * 2.) + .75f, 1.f);
191       int i = std::extent<decltype(FLOW_MAPS)>::value * theta;
192
193       LoadFlowMap(FLOW_MAPS[i]);
194     }
195     RandomizeUvTransform();
196
197     Vector3 color(rand() % 5, rand() % 5, rand() % 5);
198     color /= 4.f;
199
200     mDoubleTapDetector.Detach(mApp.GetWindow().GetRootLayer());
201     mController->RequestTransition(TRANSITION_DURATION, color);
202   }
203
204   void LoadFlowMap(const char* const name)
205   {
206     DALI_ASSERT_DEBUG(name && "Flow map name must be given");
207     if (mLastFlowMap != name)
208     {
209       std::string flowMapDir = Application::GetResourcePath() + "images/color-transition/";
210       std::string flowMapPath = flowMapDir + name + ".png";
211       auto flowMap = LoadTexture(flowMapPath);
212       DALI_ASSERT_DEBUG(flowMap && "Failed to load flow map.");
213       mController->SetFlowMap(flowMap);
214     }
215   }
216
217   void RandomizeUvTransform()
218   {
219     mController->SetUvTransform((rand() % 12) * M_PI / 12., 1.f,
220       (rand() % 12) * M_PI / 12., .5f);
221   }
222
223   void OnTransitionFinished()
224   {
225     mDoubleTapDetector.Attach(mApp.GetWindow().GetRootLayer());
226   }
227
228   Application& mApp;
229
230   const char* mLastFlowMap = nullptr;
231
232   Actor mColorTransitionContent;
233   Actor mMainRoot;
234
235   std::unique_ptr<ColorTransitionController> mController;
236
237   TapGestureDetector mDoubleTapDetector;
238 };
239
240 int DALI_EXPORT_API main(int argc, char** argv)
241 {
242   auto app = Application::New(&argc, &argv
243 #ifdef WIN32
244     , ".//dali-toolkit-default-theme.json"
245 #endif
246   );
247   ColorTransition ct(app);
248   app.MainLoop();
249   return 0;
250 }