Moved Core Rendering API from devel-api to public-api
[platform/core/uifw/dali-demo.git] / examples / radial-menu / radial-sweep-view-impl.cpp
1 /*
2  * Copyright (c) 2016 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 "radial-sweep-view-impl.h"
19
20 #include <dali/public-api/rendering/renderer.h>
21 #include <sstream>
22
23 using namespace Dali;
24
25 namespace
26 {
27
28 const char* VERTEX_SHADER_PREFIX( "#define MATH_PI_2 1.570796\n#define MATH_PI_4 0.785398\n" );
29
30 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
31 attribute mediump float   aAngleIndex;\n
32 attribute mediump vec2    aPosition1;\n
33 attribute mediump vec2    aPosition2;\n
34 uniform   mediump mat4    uMvpMatrix;\n
35 uniform   mediump float   uStartAngle;\n
36 uniform   mediump float   uRotationAngle;\n
37 \n
38 void main()\n
39 {\n
40   float currentAngle = uStartAngle + uRotationAngle;\n
41   float angleInterval1 =  MATH_PI_4 * aAngleIndex;\n
42   vec4 vertexPosition = vec4(0.0, 0.0, 0.0, 1.0);\n
43   if( currentAngle >=  angleInterval1)\n
44   {\n
45     float angleInterval2 =  angleInterval1 + MATH_PI_2;\n
46     float angle = currentAngle < angleInterval2 ? currentAngle : angleInterval2;\n
47     float delta;\n
48     if( mod( aAngleIndex+4.0, 4.0) < 2.0  )\n
49     {\n
50       delta = 0.5 - 0.5*cos(angle) / sin(angle);\n
51     }\n
52     else\n
53     {\n
54       delta = 0.5 + 0.5*sin(angle) / cos(angle);\n
55     }\n
56     vertexPosition.xy = mix( aPosition1, aPosition2, delta );\n
57   }\n
58   gl_Position = uMvpMatrix * vertexPosition;\n
59 }
60 );
61
62 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
63 uniform lowp  vec4    uColor;\n
64 \n
65 void main()\n
66 {\n
67   gl_FragColor = uColor;\n
68 }\n
69 );
70
71 float HoldZeroFastEaseInOutHoldOne(float progress)
72 {
73   if( progress < 0.2f)
74   {
75     return 0.0f;
76   }
77   else if(progress < 0.5f)
78   {
79     progress = (progress-0.2) / 0.3f;
80     return  progress*progress*progress*0.5f;
81   }
82   else if(progress < 0.8f)
83   {
84     progress = ((progress - 0.5f) / 0.3f) - 1.0f;
85     return (progress*progress*progress+1.0f) * 0.5f + 0.5f;
86   }
87   else
88   {
89     return 1.0f;
90   }
91 }
92
93 } // anonymous namespace
94
95
96 RadialSweepView RadialSweepViewImpl::New( )
97 {
98   return New( 2.0f, 100.0f, ANGLE_0, ANGLE_0, ANGLE_0, ANGLE_360 );
99 }
100
101
102 RadialSweepView RadialSweepViewImpl::New( float duration, float diameter, Radian initialAngle, Radian finalAngle, Radian initialSector, Radian finalSector )
103 {
104   RadialSweepViewImpl* impl= new RadialSweepViewImpl(duration, diameter, initialAngle, finalAngle, initialSector, finalSector);
105   RadialSweepView handle = RadialSweepView(*impl);
106   return handle;
107 }
108
109 RadialSweepViewImpl::RadialSweepViewImpl( float duration, float diameter, Radian initialAngle, Radian finalAngle, Radian initialSector, Radian finalSector )
110 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
111   mDuration(duration),
112   mDiameter(diameter),
113   mInitialAngle(initialAngle),
114   mFinalAngle(finalAngle),
115   mInitialSector(initialSector),
116   mFinalSector(finalSector),
117   mInitialActorAngle(0),
118   mFinalActorAngle(0),
119   mEasingFunction(HoldZeroFastEaseInOutHoldOne),
120   mStartAngleIndex(Property::INVALID_INDEX),
121   mRotationAngleIndex(Property::INVALID_INDEX),
122   mRotateActorsWithStencil(false),
123   mRotateActors(false)
124 {
125 }
126
127 void RadialSweepViewImpl::SetDuration(float duration)
128 {
129   mDuration = duration;
130 }
131
132 void RadialSweepViewImpl::SetEasingFunction( Dali::AlphaFunction easingFunction )
133 {
134   mEasingFunction = easingFunction;
135 }
136
137 void RadialSweepViewImpl::SetDiameter(float diameter)
138 {
139   mDiameter = diameter;
140 }
141
142 void RadialSweepViewImpl::SetInitialAngle( Dali::Radian initialAngle)
143 {
144   mInitialAngle = initialAngle;
145 }
146
147 void RadialSweepViewImpl::SetFinalAngle( Dali::Radian finalAngle)
148 {
149   mFinalAngle = finalAngle;
150 }
151
152 void RadialSweepViewImpl::SetInitialSector( Dali::Radian initialSector)
153 {
154   mInitialSector = initialSector;
155 }
156
157 void RadialSweepViewImpl::SetFinalSector( Dali::Radian finalSector)
158 {
159   mFinalSector = finalSector;
160 }
161
162 void RadialSweepViewImpl::SetInitialActorAngle( Dali::Radian initialAngle )
163 {
164   mInitialActorAngle = initialAngle;
165   mRotateActors = true;
166 }
167
168 void RadialSweepViewImpl::SetFinalActorAngle( Dali::Radian finalAngle )
169 {
170   mFinalActorAngle = finalAngle;
171   mRotateActors = true;
172 }
173
174 float RadialSweepViewImpl::GetDuration( )
175 {
176   return mDuration;
177 }
178
179 float RadialSweepViewImpl::GetDiameter( )
180 {
181   return mDiameter;
182 }
183
184 Dali::Radian RadialSweepViewImpl::GetInitialAngle( )
185 {
186   return mInitialAngle;
187 }
188
189 Dali::Radian RadialSweepViewImpl::GetFinalAngle( )
190 {
191   return mFinalAngle;
192 }
193
194 Dali::Radian RadialSweepViewImpl::GetInitialSector( )
195 {
196   return mInitialSector;
197 }
198
199 Dali::Radian RadialSweepViewImpl::GetFinalSector( )
200 {
201   return mFinalSector;
202 }
203
204 Dali::Radian RadialSweepViewImpl::GetInitialActorAngle( )
205 {
206   return mInitialActorAngle;
207 }
208
209 Dali::Radian RadialSweepViewImpl::GetFinalActorAngle(  )
210 {
211   return mFinalActorAngle;
212 }
213
214 void RadialSweepViewImpl::RotateActorsWithStencil(bool rotate)
215 {
216   mRotateActorsWithStencil = rotate;
217 }
218
219 void RadialSweepViewImpl::Add(Actor actor)
220 {
221   if( ! mLayer )
222   {
223     mLayer = Layer::New();
224     Self().Add(mLayer);
225     mLayer.SetSize( Stage::GetCurrent().GetSize() );
226     mLayer.SetParentOrigin( ParentOrigin::CENTER );
227   }
228
229   mLayer.Add(actor);
230 }
231
232 void RadialSweepViewImpl::Activate( Animation anim, float offsetTime, float duration )
233 {
234   bool startAnimation=false;
235   if( ! anim )
236   {
237     mAnim = Animation::New( mDuration );
238     anim = mAnim;
239     startAnimation = true;
240   }
241
242   if( ! mStencilActor )
243   {
244     CreateStencil( mInitialSector );
245     mLayer.Add( mStencilActor );
246     mStencilActor.SetScale(mDiameter);
247   }
248
249   mStencilActor.SetOrientation( mInitialAngle, Vector3::ZAXIS );
250   mStencilActor.SetProperty( mRotationAngleIndex, mInitialSector.radian );
251
252   if( mRotateActors )
253   {
254     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
255     {
256       Actor actor = mLayer.GetChildAt(i);
257       if( actor != mStencilActor )
258       {
259         anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( mInitialActorAngle ), Vector3::ZAXIS ) );
260       }
261     }
262   }
263
264   anim.AnimateTo( Property( mStencilActor, mRotationAngleIndex ), mFinalSector.radian, mEasingFunction, TimePeriod( offsetTime, duration ) );
265   anim.AnimateTo( Property( mStencilActor, Actor::Property::ORIENTATION ), Quaternion( Radian( mFinalAngle ), Vector3::ZAXIS ), mEasingFunction, TimePeriod( offsetTime, duration ) );
266
267   if( mRotateActorsWithStencil )
268   {
269     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
270     {
271       Actor actor = mLayer.GetChildAt(i);
272       if( actor != mStencilActor )
273       {
274         anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( mFinalAngle.radian - mInitialAngle.radian ) , Vector3::ZAXIS ), mEasingFunction, TimePeriod( offsetTime, duration ) );
275       }
276     }
277   }
278   else if( mRotateActors )
279   {
280     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
281     {
282       Actor actor = mLayer.GetChildAt(i);
283       if( actor != mStencilActor )
284       {
285         anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( mFinalActorAngle ), Vector3::ZAXIS ), mEasingFunction, TimePeriod( offsetTime, duration ) );
286       }
287     }
288   }
289
290
291   if( startAnimation )
292   {
293     anim.SetLooping(true);
294     anim.Play();
295   }
296 }
297
298
299 void RadialSweepViewImpl::Deactivate()
300 {
301   if( mAnim )
302   {
303     mAnim.Stop();
304   }
305 }
306
307 void RadialSweepViewImpl::CreateStencil( Radian initialSector )
308 {
309   // Create the stencil mesh geometry
310   //     3-----2
311   //     | \ / |
312   //     |  0--1 , 6
313   //     | / \ |
314   //     4-----5
315
316   struct VertexPosition { float angleIndex; Vector2 position1; Vector2 position2; };
317   VertexPosition vertexData[7] = { // With X coordinate inverted to make the animation go anti clockwise from left center
318       { 9.f,  Vector2( 0.f, 0.f ),     Vector2( 0.f, 0.f )     }, // center point, keep static
319       { 0.f,  Vector2( -0.5f, 0.f ),   Vector2( -0.5f, 0.f )   }, // vertex 1, 0 degree, keep static
320       { -1.f, Vector2( -0.5f, 0.5f ),  Vector2( -0.5f, -0.5f ) }, // -45 ~ 45 degrees  ( 0 ~ 45)
321       { 1.f,  Vector2( -0.5f, -0.5f ), Vector2( 0.5f, -0.5f )  }, // 45 ~ 135 degrees
322       { 3.f,  Vector2( 0.5f, -0.5f ),  Vector2( 0.5f, 0.5f )   }, // 135 ~ 225 degrees
323       { 5.f,  Vector2( 0.5f, 0.5f ),   Vector2( -0.5f, 0.5f )  }, // 225 ~ 315 degrees
324       { 7.f,  Vector2( -0.5f, 0.5f ),  Vector2( -0.5f, -0.5f ) }  // 315 ~ 405 degrees ( 315 ~ 359.999 )
325   };
326   Property::Map vertexFormat;
327   vertexFormat["aAngleIndex"] = Property::FLOAT;
328   vertexFormat["aPosition1"] = Property::VECTOR2;
329   vertexFormat["aPosition2"] = Property::VECTOR2;
330   PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
331   vertices.SetData( vertexData, 7u );
332
333   unsigned short indexData[15] = { 0,1,2,0,2,3,0,3,4,0,4,5,0,5,6 };
334
335   Geometry meshGeometry = Geometry::New();
336   meshGeometry.AddVertexBuffer( vertices );
337   meshGeometry.SetIndexBuffer( &indexData[0], sizeof( indexData )/sizeof(indexData[0]) );
338
339   // Create shader
340   std::ostringstream vertexShaderStringStream;
341   vertexShaderStringStream<<VERTEX_SHADER_PREFIX<<VERTEX_SHADER;
342   Shader shader = Shader::New( vertexShaderStringStream.str(), FRAGMENT_SHADER );
343
344   // Create renderer
345   Renderer renderer = Renderer::New( meshGeometry, shader );
346
347   mStencilActor = Actor::New();
348   mStencilActor.AddRenderer( renderer );
349   mStencilActor.SetSize(1.f, 1.f);
350
351   // register properties
352   mStartAngleIndex = mStencilActor.RegisterProperty("uStartAngle", 0.f);
353   mRotationAngleIndex = mStencilActor.RegisterProperty("uRotationAngle", initialSector.radian);
354
355   mStencilActor.SetDrawMode( DrawMode::STENCIL );
356   mStencilActor.SetParentOrigin( ParentOrigin::CENTER );
357 }