2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali/dali.h>
21 #include "generated/radial-progress-basic-frag.h"
22 #include "generated/radial-progress-basic-vert.h"
23 #include "generated/radial-progress-textured-frag.h"
24 #include "generated/radial-progress-textured-vert.h"
28 namespace // unnamed namespace
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;
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
38 } // unnamed namespace
40 // This example shows how to render a radial progress indicator
42 class RadialProgressController : public ConnectionTracker
45 RadialProgressController(Application& application)
46 : mApplication(application)
48 // Connect to the Application's Init signal
49 mApplication.InitSignal().Connect(this, &RadialProgressController::Create);
52 ~RadialProgressController()
57 // The Init signal is received once (only) during the Application lifetime
58 void Create(Application& application)
60 Window window = application.GetWindow();
61 window.SetBackgroundColor(Color::BLACK);
63 // Connect to the window's key signal to allow Back and Escape to exit.
64 window.KeyEventSignal().Connect(this, &RadialProgressController::OnKeyEvent);
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));
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);
78 // 2. Create textured quad renderer
79 Renderer texturedQuad = CreateTexturedQuad(TEXTURE_URL);
80 mActor.AddRenderer(texturedQuad);
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));
87 // 6. Exit the application when touched
88 window.GetRootLayer().TouchedSignal().Connect(this, &RadialProgressController::OnTouch);
91 bool OnTouch(Actor actor, const TouchEvent& touch)
93 // quit the application
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.
103 Renderer CreatePolygon(unsigned int numberOfSides)
105 float count(numberOfSides);
107 // compute radial step in radians
108 const float STEP((2.0f * M_PI) / count);
111 std::vector<Vector3> vertices;
112 vertices.push_back(Vector3::ZERO);
114 for(size_t i = 0; i <= numberOfSides; ++i)
116 vertices.push_back(Vector3(-0.5f * cos(angle), -0.5f * sin(angle), i + 1));
120 Property::Map vertexFormat;
121 vertexFormat["aPosition"] = Property::VECTOR3;
123 // describe vertex format ( only 2-dimensional positions )
124 VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
125 vertexBuffer.SetData(vertices.data(), vertices.size());
128 Geometry geometry = Geometry::New();
129 geometry.AddVertexBuffer(vertexBuffer);
130 geometry.SetType(Geometry::TRIANGLE_FAN);
132 Shader shader = Shader::New(SHADER_RADIAL_PROGRESS_BASIC_VERT, SHADER_RADIAL_PROGRESS_BASIC_FRAG);
133 Renderer renderer = Renderer::New(geometry, shader);
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
138 renderer.SetProperty(Renderer::Property::RENDER_MODE, RenderMode::STENCIL);
140 // Set stencil function
141 renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS);
143 // Stencil function reference
144 renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1);
146 // Stencil function mask
147 renderer.SetProperty(Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF);
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);
154 // Stencil mask to write
155 renderer.SetProperty(Renderer::Property::STENCIL_MASK, 0xFF);
157 // Set depth index lower than textured quad renderer, so stencil will render first
158 renderer.SetProperty(Renderer::Property::DEPTH_INDEX, 1);
164 * Creates textured quad renderer
166 Renderer CreateTexturedQuad(const char* url)
168 // Create shader & geometry needed by Renderer
170 Shader shader = Shader::New(SHADER_RADIAL_PROGRESS_TEXTURED_VERT, SHADER_RADIAL_PROGRESS_TEXTURED_FRAG);
172 Property::Map vertexFormat;
173 vertexFormat["aPosition"] = Property::VECTOR2;
174 VertexBuffer vertexBuffer = VertexBuffer::New(vertexFormat);
177 const Vector2 vertices[] = {
183 vertexBuffer.SetData(vertices, 4);
185 // Instantiate quad geometry
186 Geometry geometry = Geometry::New();
187 geometry.AddVertexBuffer(vertexBuffer);
188 geometry.SetType(Geometry::TRIANGLE_STRIP);
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();
196 // Create texture set
197 TextureSet textureSet = TextureSet::New();
198 textureSet.SetTexture(0, texture);
201 Renderer renderer = Renderer::New(geometry, shader);
202 renderer.SetTextures(textureSet);
204 // Set mode indicating we will use both stencil and color buffers
205 renderer.SetProperty(Renderer::Property::RENDER_MODE, RenderMode::COLOR_STENCIL);
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);
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);
215 // Make sure the quad will render after drawing to stencil buffer
216 renderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2);
222 * @brief Called when any key event is received
224 * Will use this to quit the application if Back or the Escape key is received
225 * @param[in] event The key event information
227 void OnKeyEvent(const KeyEvent& event)
229 if(event.GetState() == KeyEvent::DOWN)
231 if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
239 Application& mApplication;
244 int DALI_EXPORT_API main(int argc, char** argv)
246 Application application = Application::New(&argc, &argv);
247 RadialProgressController test(application);
248 application.MainLoop();