Rendering of radial progress indicator
[platform/core/uifw/dali-demo.git] / examples / rendering-radial-progress / radial-progress.cpp
1 /*
2  * Copyright (c) 2017 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/dali.h>
19 #include <dali-toolkit/dali-toolkit.h>
20
21 using namespace Dali;
22
23 namespace // unnamed namespace
24 {
25
26 const char* TEXTURE_URL = DEMO_IMAGE_DIR "RadialEffect-280x280.png";
27 const unsigned int TEXTURE_WIDTH = 280;
28 const unsigned int TEXTURE_HEIGHT = 280;
29
30 const int NUMBER_OF_SIDES( 64 ); // number of sides of the polygon used as a stencil
31 const float INITIAL_DELAY( 2.0f ); // initial delay before showing the circle
32 const float PROGRESS_DURATION( 0.5f ); // number of seconds to fully show the circle
33
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
103 } // unnamed namespace
104
105
106 // This example shows how to render a radial progress indicator
107 //
108 class RadialProgressController : public ConnectionTracker
109 {
110 public:
111
112   RadialProgressController( Application& application )
113   : mApplication( application )
114   {
115     // Connect to the Application's Init signal
116     mApplication.InitSignal().Connect( this, &RadialProgressController::Create );
117   }
118
119   ~RadialProgressController()
120   {
121     // Nothing to do here
122   }
123
124   // The Init signal is received once (only) during the Application lifetime
125   void Create( Application& application )
126   {
127     Stage stage = Stage::GetCurrent();
128     stage.SetBackgroundColor( Color::BLACK );
129
130     // 1. Create actor to show the effect
131     mActor = Actor::New();
132     mActor.SetAnchorPoint( AnchorPoint::CENTER );
133     mActor.SetParentOrigin( ParentOrigin::CENTER );
134     mActor.SetSize( Vector2( TEXTURE_WIDTH, TEXTURE_HEIGHT ) );
135     mActor.RegisterProperty("uProgress", float(1.0f) );
136     stage.Add( mActor );
137
138     // 1. Create stencil renderer i.e. a triangle fan in the shape of a circle
139     Renderer stencilRenderer = CreatePolygon( NUMBER_OF_SIDES );
140     mActor.AddRenderer( stencilRenderer );
141
142     // 2. Create textured quad renderer
143     Renderer texturedQuad = CreateTexturedQuad( TEXTURE_URL );
144     mActor.AddRenderer( texturedQuad );
145
146     // 5. Animate the progress uniform
147     Animation animation = Animation::New( PROGRESS_DURATION + INITIAL_DELAY );
148     animation.AnimateTo( Property(mActor,"uProgress"), float(NUMBER_OF_SIDES+1), TimePeriod(INITIAL_DELAY, PROGRESS_DURATION) );
149     animation.Play();
150
151     // 6. Exit the application when touched
152     stage.GetRootLayer().TouchSignal().Connect( this, &RadialProgressController::OnTouch );
153   }
154
155   bool OnTouch( Actor actor, const TouchData& touch )
156   {
157     // quit the application
158     mApplication.Quit();
159     return true;
160   }
161
162   /**
163    * Generates stencil mask geometry. Geometry is rendered as
164    * a triangle fan and occupies square 2.0x2.0.
165    * @param[in] numberOfSides The more subdivisions the more smooth mask animation.
166    */
167   Renderer CreatePolygon( unsigned int numberOfSides )
168   {
169     float count( numberOfSides );
170
171     // compute radial step in radians
172     const float STEP( (2.0f * M_PI) / count );
173     float angle( 0.0f );
174
175     std::vector< Vector3 > vertices;
176     vertices.push_back( Vector3::ZERO );
177
178     for( size_t i = 0; i <= numberOfSides; ++i )
179     {
180       vertices.push_back( Vector3( -0.5f * cos( angle ), -0.5f * sin( angle ), i+1 ) );
181       angle += STEP;
182     }
183
184     Property::Map vertexFormat;
185     vertexFormat[ "aPosition" ] = Property::VECTOR3;
186
187     // describe vertex format ( only 2-dimensional positions )
188     PropertyBuffer vertexBuffer = PropertyBuffer::New( vertexFormat );
189     vertexBuffer.SetData( vertices.data(), vertices.size() );
190
191     // create geometry
192     Geometry geometry = Geometry::New();
193     geometry.AddVertexBuffer( vertexBuffer );
194     geometry.SetType( Geometry::TRIANGLE_FAN );
195
196     Shader shader = Shader::New( VERTEX_SHADER_BASIC, FRAGMENT_SHADER_BASIC );
197     Renderer renderer = Renderer::New( geometry, shader );
198
199     // Setting stencil data. We don't want to render to the color buffer so
200     // with use of RenderMode property we specify that only stencil buffer will
201     // be affected.
202     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::STENCIL );
203
204     // Set stencil function
205     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS );
206
207     // Stencil function reference
208     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
209
210     // Stencil function mask
211     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
212
213     // Set stencil operations
214     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP );
215     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP );
216     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::REPLACE );
217
218     // Stencil mask to write
219     renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0xFF );
220
221     // Set depth index lower than textured quad renderer, so stencil will render first
222     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 1 );
223
224     return renderer;
225   }
226
227   /**
228    * Creates textured quad renderer
229    */
230   Renderer CreateTexturedQuad( const char* url )
231   {
232     // Create shader & geometry needed by Renderer
233
234     Shader shader = Shader::New( VERTEX_SHADER_TEXTURED, FRAGMENT_SHADER_TEXTURED );
235
236     Property::Map vertexFormat;
237     vertexFormat["aPosition"] = Property::VECTOR2;
238     PropertyBuffer vertexBuffer = PropertyBuffer::New( vertexFormat );
239
240     const float P( 0.5f );
241     const Vector2 vertices[] = {
242       Vector2( -P, -P ),
243       Vector2( +P, -P ),
244       Vector2( -P, +P ),
245       Vector2( +P, +P )
246     };
247
248     vertexBuffer.SetData( vertices, 4 );
249
250     // Instantiate quad geometry
251     Geometry geometry = Geometry::New();
252     geometry.AddVertexBuffer( vertexBuffer );
253     geometry.SetType( Geometry::TRIANGLE_STRIP );
254
255     // Load texture
256     PixelData pixelData = Toolkit::SyncImageLoader::Load( url );
257     Texture texture = Texture::New( TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
258     texture.Upload( pixelData );
259     texture.GenerateMipmaps();
260
261     // Create texture set
262     TextureSet textureSet = TextureSet::New();
263     textureSet.SetTexture( 0, texture  );
264
265     // Create renderer
266     Renderer renderer = Renderer::New( geometry, shader );
267     renderer.SetTextures( textureSet );
268
269     // Set mode indicating we will use both stencil and color buffers
270     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR_STENCIL );
271
272     // Stencil function - expecing drawing only when function mask matches exactly
273     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::EQUAL );
274     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
275     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
276
277     // We don't want to draw to the stencil, so setting stencil draw mask to 0
278     renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0x00 );
279
280     // Make sure the quad will render after drawing to stencil buffer
281     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 2 );
282
283     return renderer;
284   }
285
286 private:
287
288   Application&  mApplication;
289
290   Actor mActor;
291 };
292
293 void RunTest( Application& application )
294 {
295   RadialProgressController test( application );
296
297   application.MainLoop();
298 }
299
300 // Entry point for Linux & Tizen applications
301 //
302 int DALI_EXPORT_API main( int argc, char **argv )
303 {
304   Application application = Application::New( &argc, &argv );
305
306   RunTest( application );
307
308   return 0;
309 }