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