Changes after TouchedSignal changes
[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/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     Window window = application.GetWindow();
128     window.SetBackgroundColor( Color::BLACK );
129
130     // Connect to the window's key signal to allow Back and Escape to exit.
131     window.KeyEventSignal().Connect( this, &RadialProgressController::OnKeyEvent );
132
133     // 1. Create actor to show the effect
134     mActor = Actor::New();
135     mActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
136     mActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
137     mActor.SetProperty( Actor::Property::SIZE, Vector2( TEXTURE_WIDTH, TEXTURE_HEIGHT ) );
138     mActor.RegisterProperty("uProgress", float(1.0f) );
139     window.Add( mActor );
140
141     // 1. Create stencil renderer i.e. a triangle fan in the shape of a circle
142     Renderer stencilRenderer = CreatePolygon( NUMBER_OF_SIDES );
143     mActor.AddRenderer( stencilRenderer );
144
145     // 2. Create textured quad renderer
146     Renderer texturedQuad = CreateTexturedQuad( TEXTURE_URL );
147     mActor.AddRenderer( texturedQuad );
148
149     // 5. Animate the progress uniform
150     Animation animation = Animation::New( PROGRESS_DURATION + INITIAL_DELAY );
151     animation.AnimateTo( Property(mActor,"uProgress"), float(NUMBER_OF_SIDES+1), TimePeriod(INITIAL_DELAY, PROGRESS_DURATION) );
152     animation.Play();
153
154     // 6. Exit the application when touched
155     window.GetRootLayer().TouchedSignal().Connect( this, &RadialProgressController::OnTouch );
156   }
157
158   bool OnTouch( Actor actor, const TouchEvent& touch )
159   {
160     // quit the application
161     mApplication.Quit();
162     return true;
163   }
164
165   /**
166    * Generates stencil mask geometry. Geometry is rendered as
167    * a triangle fan and occupies square 2.0x2.0.
168    * @param[in] numberOfSides The more subdivisions the more smooth mask animation.
169    */
170   Renderer CreatePolygon( unsigned int numberOfSides )
171   {
172     float count( numberOfSides );
173
174     // compute radial step in radians
175     const float STEP( (2.0f * M_PI) / count );
176     float angle( 0.0f );
177
178     std::vector< Vector3 > vertices;
179     vertices.push_back( Vector3::ZERO );
180
181     for( size_t i = 0; i <= numberOfSides; ++i )
182     {
183       vertices.push_back( Vector3( -0.5f * cos( angle ), -0.5f * sin( angle ), i+1 ) );
184       angle += STEP;
185     }
186
187     Property::Map vertexFormat;
188     vertexFormat[ "aPosition" ] = Property::VECTOR3;
189
190     // describe vertex format ( only 2-dimensional positions )
191     VertexBuffer vertexBuffer = VertexBuffer::New( vertexFormat );
192     vertexBuffer.SetData( vertices.data(), vertices.size() );
193
194     // create geometry
195     Geometry geometry = Geometry::New();
196     geometry.AddVertexBuffer( vertexBuffer );
197     geometry.SetType( Geometry::TRIANGLE_FAN );
198
199     Shader shader = Shader::New( VERTEX_SHADER_BASIC, FRAGMENT_SHADER_BASIC );
200     Renderer renderer = Renderer::New( geometry, shader );
201
202     // Setting stencil data. We don't want to render to the color buffer so
203     // with use of RenderMode property we specify that only stencil buffer will
204     // be affected.
205     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::STENCIL );
206
207     // Set stencil function
208     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS );
209
210     // Stencil function reference
211     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
212
213     // Stencil function mask
214     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
215
216     // Set stencil operations
217     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP );
218     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP );
219     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::REPLACE );
220
221     // Stencil mask to write
222     renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0xFF );
223
224     // Set depth index lower than textured quad renderer, so stencil will render first
225     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 1 );
226
227     return renderer;
228   }
229
230   /**
231    * Creates textured quad renderer
232    */
233   Renderer CreateTexturedQuad( const char* url )
234   {
235     // Create shader & geometry needed by Renderer
236
237     Shader shader = Shader::New( VERTEX_SHADER_TEXTURED, FRAGMENT_SHADER_TEXTURED );
238
239     Property::Map vertexFormat;
240     vertexFormat["aPosition"] = Property::VECTOR2;
241     VertexBuffer vertexBuffer = VertexBuffer::New( vertexFormat );
242
243     const float P( 0.5f );
244     const Vector2 vertices[] = {
245       Vector2( -P, -P ),
246       Vector2( +P, -P ),
247       Vector2( -P, +P ),
248       Vector2( +P, +P )
249     };
250
251     vertexBuffer.SetData( vertices, 4 );
252
253     // Instantiate quad geometry
254     Geometry geometry = Geometry::New();
255     geometry.AddVertexBuffer( vertexBuffer );
256     geometry.SetType( Geometry::TRIANGLE_STRIP );
257
258     // Load texture
259     PixelData pixelData = Toolkit::SyncImageLoader::Load( url );
260     Texture texture = Texture::New( TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
261     texture.Upload( pixelData );
262     texture.GenerateMipmaps();
263
264     // Create texture set
265     TextureSet textureSet = TextureSet::New();
266     textureSet.SetTexture( 0, texture  );
267
268     // Create renderer
269     Renderer renderer = Renderer::New( geometry, shader );
270     renderer.SetTextures( textureSet );
271
272     // Set mode indicating we will use both stencil and color buffers
273     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR_STENCIL );
274
275     // Stencil function - expecing drawing only when function mask matches exactly
276     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::EQUAL );
277     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
278     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
279
280     // We don't want to draw to the stencil, so setting stencil draw mask to 0
281     renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0x00 );
282
283     // Make sure the quad will render after drawing to stencil buffer
284     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 2 );
285
286     return renderer;
287   }
288
289   /**
290    * @brief Called when any key event is received
291    *
292    * Will use this to quit the application if Back or the Escape key is received
293    * @param[in] event The key event information
294    */
295   void OnKeyEvent( const KeyEvent& event )
296   {
297     if( event.GetState() == KeyEvent::DOWN )
298     {
299       if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
300       {
301         mApplication.Quit();
302       }
303     }
304   }
305
306 private:
307
308   Application&  mApplication;
309
310   Actor mActor;
311 };
312
313 int DALI_EXPORT_API main( int argc, char **argv )
314 {
315   Application application = Application::New( &argc, &argv );
316   RadialProgressController test( application );
317   application.MainLoop();
318   return 0;
319 }