Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / rendering-radial-progress / radial-progress.cpp
1 /*
2  * Copyright (c) 2020 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
18 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali/dali.h>
20
21 using namespace Dali;
22
23 namespace // unnamed namespace
24 {
25 const char*        TEXTURE_URL    = DEMO_IMAGE_DIR "RadialEffect-280x280.png";
26 const unsigned int TEXTURE_WIDTH  = 280;
27 const unsigned int TEXTURE_HEIGHT = 280;
28
29 const int   NUMBER_OF_SIDES(64);     // number of sides of the polygon used as a stencil
30 const float INITIAL_DELAY(2.0f);     // initial delay before showing the circle
31 const float PROGRESS_DURATION(0.5f); // number of seconds to fully show the circle
32
33 // clang-format off
34
35 /*
36  * Vertex shader for textured quad
37  */
38 const char* VERTEX_SHADER_TEXTURED = DALI_COMPOSE_SHADER(
39 attribute mediump vec2 aPosition;\n
40 uniform   mediump mat4 uMvpMatrix;\n // DALi shader builtin
41 uniform   mediump vec3 uSize;\n // DALi shader builtin
42 \n
43 varying mediump vec2 vTexCoord;\n
44 void main()\n
45 {\n
46   mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
47   vertexPosition.xyz *= uSize;\n
48   vTexCoord = vec2(1.0, 1.0)*(aPosition + vec2(0.5) );\n
49   gl_Position = uMvpMatrix * vertexPosition;\n
50 }\n
51 );
52
53 /*
54  * Fragment shaderfor textured quad
55  */
56 const char* FRAGMENT_SHADER_TEXTURED = DALI_COMPOSE_SHADER(
57 uniform sampler2D uTexture;\n
58 \n
59 varying mediump vec2 vTexCoord;\n
60 void main()\n
61 {\n
62   mediump vec4 texColor = texture2D( uTexture, vTexCoord );\n
63   gl_FragColor = texColor;\n
64 }\n
65 );
66
67 /*
68  * Vertex shader for polygon
69  */
70 const char* VERTEX_SHADER_BASIC = DALI_COMPOSE_SHADER(
71 attribute mediump vec3 aPosition;\n
72 uniform   mediump mat4 uMvpMatrix;\n // DALi shader builtin
73 uniform   mediump vec3 uSize;\n // DALi shader builtin
74 uniform   mediump float uProgress;\n
75 \n
76 varying mediump vec2 vTexCoord;\n
77 void main()\n
78 {\n
79   mediump vec4 vertexPosition = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n
80 \n
81   float index = aPosition.z;\n
82   if( uProgress < index )\n
83   {\n
84     vertexPosition = vec4(0.0, 0.0, 0.0, 1.0);\n
85   }\n
86 \n
87   vertexPosition.xyz *= uSize;\n
88   gl_Position = uMvpMatrix * vertexPosition;\n
89 }\n
90 );
91
92 /*
93  * Fragment shader for polygon
94  */
95 const char* FRAGMENT_SHADER_BASIC = DALI_COMPOSE_SHADER(
96
97 void main()\n
98 {\n
99   gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 );\n
100 }\n
101 );
102 // clang-format on
103
104 } // unnamed namespace
105
106 // This example shows how to render a radial progress indicator
107 //
108 class RadialProgressController : public ConnectionTracker
109 {
110 public:
111   RadialProgressController(Application& application)
112   : mApplication(application)
113   {
114     // Connect to the Application's Init signal
115     mApplication.InitSignal().Connect(this, &RadialProgressController::Create);
116   }
117
118   ~RadialProgressController()
119   {
120     // Nothing to do here
121   }
122
123   // The Init signal is received once (only) during the Application lifetime
124   void Create(Application& application)
125   {
126     Window window = application.GetWindow();
127     window.SetBackgroundColor(Color::BLACK);
128
129     // Connect to the window's key signal to allow Back and Escape to exit.
130     window.KeyEventSignal().Connect(this, &RadialProgressController::OnKeyEvent);
131
132     // 1. Create actor to show the effect
133     mActor = Actor::New();
134     mActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
135     mActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
136     mActor.SetProperty(Actor::Property::SIZE, Vector2(TEXTURE_WIDTH, TEXTURE_HEIGHT));
137     mActor.RegisterProperty("uProgress", float(1.0f));
138     window.Add(mActor);
139
140     // 1. Create stencil renderer i.e. a triangle fan in the shape of a circle
141     Renderer stencilRenderer = CreatePolygon(NUMBER_OF_SIDES);
142     mActor.AddRenderer(stencilRenderer);
143
144     // 2. Create textured quad renderer
145     Renderer texturedQuad = CreateTexturedQuad(TEXTURE_URL);
146     mActor.AddRenderer(texturedQuad);
147
148     // 5. Animate the progress uniform
149     Animation animation = Animation::New(PROGRESS_DURATION + INITIAL_DELAY);
150     animation.AnimateTo(Property(mActor, "uProgress"), float(NUMBER_OF_SIDES + 1), TimePeriod(INITIAL_DELAY, PROGRESS_DURATION));
151     animation.Play();
152
153     // 6. Exit the application when touched
154     window.GetRootLayer().TouchedSignal().Connect(this, &RadialProgressController::OnTouch);
155   }
156
157   bool OnTouch(Actor actor, const TouchEvent& touch)
158   {
159     // quit the application
160     mApplication.Quit();
161     return true;
162   }
163
164   /**
165    * Generates stencil mask geometry. Geometry is rendered as
166    * a triangle fan and occupies square 2.0x2.0.
167    * @param[in] numberOfSides The more subdivisions the more smooth mask animation.
168    */
169   Renderer CreatePolygon(unsigned int numberOfSides)
170   {
171     float count(numberOfSides);
172
173     // compute radial step in radians
174     const float STEP((2.0f * M_PI) / count);
175     float       angle(0.0f);
176
177     std::vector<Vector3> vertices;
178     vertices.push_back(Vector3::ZERO);
179
180     for(size_t i = 0; i <= numberOfSides; ++i)
181     {
182       vertices.push_back(Vector3(-0.5f * cos(angle), -0.5f * sin(angle), i + 1));
183       angle += STEP;
184     }
185
186     Property::Map vertexFormat;
187     vertexFormat["aPosition"] = Property::VECTOR3;
188
189     // describe vertex format ( only 2-dimensional positions )
190     VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
191     vertexBuffer.SetData(vertices.data(), vertices.size());
192
193     // create geometry
194     Geometry geometry = Geometry::New();
195     geometry.AddVertexBuffer(vertexBuffer);
196     geometry.SetType(Geometry::TRIANGLE_FAN);
197
198     Shader   shader   = Shader::New(VERTEX_SHADER_BASIC, FRAGMENT_SHADER_BASIC);
199     Renderer renderer = Renderer::New(geometry, shader);
200
201     // Setting stencil data. We don't want to render to the color buffer so
202     // with use of RenderMode property we specify that only stencil buffer will
203     // be affected.
204     renderer.SetProperty(Renderer::Property::RENDER_MODE, RenderMode::STENCIL);
205
206     // Set stencil function
207     renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS);
208
209     // Stencil function reference
210     renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1);
211
212     // Stencil function mask
213     renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF);
214
215     // Set stencil operations
216     renderer.SetProperty(Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP);
217     renderer.SetProperty(Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP);
218     renderer.SetProperty(Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::REPLACE);
219
220     // Stencil mask to write
221     renderer.SetProperty(Renderer::Property::STENCIL_MASK, 0xFF);
222
223     // Set depth index lower than textured quad renderer, so stencil will render first
224     renderer.SetProperty(Renderer::Property::DEPTH_INDEX, 1);
225
226     return renderer;
227   }
228
229   /**
230    * Creates textured quad renderer
231    */
232   Renderer CreateTexturedQuad(const char* url)
233   {
234     // Create shader & geometry needed by Renderer
235
236     Shader shader = Shader::New(VERTEX_SHADER_TEXTURED, FRAGMENT_SHADER_TEXTURED);
237
238     Property::Map vertexFormat;
239     vertexFormat["aPosition"] = Property::VECTOR2;
240     VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
241
242     const float   P(0.5f);
243     const Vector2 vertices[] = {
244       Vector2(-P, -P),
245       Vector2(+P, -P),
246       Vector2(-P, +P),
247       Vector2(+P, +P)};
248
249     vertexBuffer.SetData(vertices, 4);
250
251     // Instantiate quad geometry
252     Geometry geometry = Geometry::New();
253     geometry.AddVertexBuffer(vertexBuffer);
254     geometry.SetType(Geometry::TRIANGLE_STRIP);
255
256     // Load texture
257     PixelData pixelData = Toolkit::SyncImageLoader::Load(url);
258     Texture   texture   = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
259     texture.Upload(pixelData);
260     texture.GenerateMipmaps();
261
262     // Create texture set
263     TextureSet textureSet = TextureSet::New();
264     textureSet.SetTexture(0, texture);
265
266     // Create renderer
267     Renderer renderer = Renderer::New(geometry, shader);
268     renderer.SetTextures(textureSet);
269
270     // Set mode indicating we will use both stencil and color buffers
271     renderer.SetProperty(Renderer::Property::RENDER_MODE, RenderMode::COLOR_STENCIL);
272
273     // Stencil function - expecing drawing only when function mask matches exactly
274     renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION, StencilFunction::EQUAL);
275     renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1);
276     renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF);
277
278     // We don't want to draw to the stencil, so setting stencil draw mask to 0
279     renderer.SetProperty(Renderer::Property::STENCIL_MASK, 0x00);
280
281     // Make sure the quad will render after drawing to stencil buffer
282     renderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2);
283
284     return renderer;
285   }
286
287   /**
288    * @brief Called when any key event is received
289    *
290    * Will use this to quit the application if Back or the Escape key is received
291    * @param[in] event The key event information
292    */
293   void OnKeyEvent(const KeyEvent& event)
294   {
295     if(event.GetState() == KeyEvent::DOWN)
296     {
297       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
298       {
299         mApplication.Quit();
300       }
301     }
302   }
303
304 private:
305   Application& mApplication;
306
307   Actor mActor;
308 };
309
310 int DALI_EXPORT_API main(int argc, char** argv)
311 {
312   Application              application = Application::New(&argc, &argv);
313   RadialProgressController test(application);
314   application.MainLoop();
315   return 0;
316 }