Cleaned up Degree, Radian, AngleAxis and Quaternion classes
[platform/core/uifw/dali-demo.git] / examples / radial-menu / radial-sweep-view-impl.cpp
1 /*
2  * Copyright (c) 2014 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 using namespace Dali;
21
22 namespace
23 {
24
25 /**
26  * Method to project a point on a circle of radius halfSide at given
27  * angle onto a square of side 2 * halfSide
28  */
29 void CircleSquareProjection( Vector3& position, Radian angle, float halfSide )
30 {
31   //  135  90   45
32   //     +--+--+
33   //     | \|/ |
34   // 180 +--+--+ 0
35   //     | /|\ |
36   //     +--+--+
37   //  225  270  315
38   if( angle >= Dali::ANGLE_45 && angle < Dali::ANGLE_135 )
39   {
40     position.x = halfSide * cosf(angle) / sinf(angle);
41     position.y = -halfSide;
42   }
43   else if( angle >= Dali::ANGLE_135 && angle < Dali::ANGLE_225 )
44   {
45     position.x = -halfSide;
46     position.y = halfSide * sinf(angle) / cosf(angle);
47   }
48   else if( angle >= Dali::ANGLE_225 && angle < Dali::ANGLE_315 )
49   {
50     position.x = -halfSide * cosf(angle) / sinf(angle);
51     position.y =  halfSide;
52   }
53   else
54   {
55     position.x = halfSide;
56     position.y = -halfSide * sinf(angle) / cosf(angle);
57   }
58
59   position.z = 0.0f;
60 }
61
62 float HoldZeroFastEaseInOutHoldOne(float progress)
63 {
64   if( progress < 0.2f)
65   {
66     return 0.0f;
67   }
68   else if(progress < 0.5f)
69   {
70     return AlphaFunctions::EaseIn((progress-0.2) / 0.3f) * 0.5f;
71   }
72   else if(progress < 0.8f)
73   {
74     return AlphaFunctions::EaseOut((progress - 0.5f) / 0.3f) * 0.5f + 0.5f;
75   }
76   else
77   {
78     return 1.0f;
79   }
80 }
81
82 struct SquareFanConstraint
83 {
84   SquareFanConstraint(int sideIndex)
85   : mSideIndex(sideIndex)
86   {
87   }
88
89   void operator()( Vector3& current, const PropertyInputContainer& inputs )
90   {
91     float degree = fmodf((inputs[0]->GetFloat() + inputs[1]->GetFloat()), 360.0f);
92     if(degree < 0.0f)
93     {
94       degree += 360.0f;
95     }
96
97     float startAngle = (90.0f*mSideIndex)-45.0f;
98     float endAngle = (90.0f*mSideIndex)+45.0f;
99     if(degree < startAngle)
100     {
101       current = Vector3::ZERO;
102     }
103     else
104     {
105       if( degree >= endAngle )
106       {
107         degree = endAngle;
108       }
109       CircleSquareProjection( current, Degree(degree), 0.5f );
110       current.x = -current.x; // Inverting X makes the animation go anti clockwise from left center
111     }
112   }
113
114   int mSideIndex;
115 };
116
117 } // anonymous namespace
118
119
120 RadialSweepView RadialSweepViewImpl::New( )
121 {
122   return New( 2.0f, 100.0f, Degree(0.0f), Degree(0.0f), Degree(0.0f), Degree(359.999f) );
123 }
124
125
126 RadialSweepView RadialSweepViewImpl::New( float duration, float diameter, Degree initialAngle, Degree finalAngle, Degree initialSector, Degree finalSector )
127 {
128   RadialSweepViewImpl* impl= new RadialSweepViewImpl(duration, diameter, initialAngle, finalAngle, initialSector, finalSector);
129   RadialSweepView handle = RadialSweepView(*impl);
130   return handle;
131 }
132
133 RadialSweepViewImpl::RadialSweepViewImpl( float duration, float diameter, Degree initialAngle, Degree finalAngle, Degree initialSector, Degree finalSector )
134 : Control( CONTROL_BEHAVIOUR_NONE ),
135   mDuration(duration),
136   mDiameter(diameter),
137   mInitialAngle(initialAngle),
138   mFinalAngle(finalAngle),
139   mInitialSector(initialSector),
140   mFinalSector(finalSector),
141   mInitialActorAngle(0),
142   mFinalActorAngle(0),
143   mEasingFunction(HoldZeroFastEaseInOutHoldOne),
144   mStartAngleIndex(Property::INVALID_INDEX),
145   mRotationAngleIndex(Property::INVALID_INDEX),
146   mRotateActorsWithStencil(false),
147   mRotateActors(false)
148 {
149 }
150
151 void RadialSweepViewImpl::SetDuration(float duration)
152 {
153   mDuration = duration;
154 }
155
156 void RadialSweepViewImpl::SetEasingFunction( Dali::AlphaFunction easingFunction )
157 {
158   mEasingFunction = easingFunction;
159 }
160
161 void RadialSweepViewImpl::SetDiameter(float diameter)
162 {
163   mDiameter = diameter;
164 }
165
166 void RadialSweepViewImpl::SetInitialAngle( Dali::Degree initialAngle)
167 {
168   mInitialAngle = initialAngle;
169 }
170
171 void RadialSweepViewImpl::SetFinalAngle( Dali::Degree finalAngle)
172 {
173   mFinalAngle = finalAngle;
174 }
175
176 void RadialSweepViewImpl::SetInitialSector( Dali::Degree initialSector)
177 {
178   mInitialSector = initialSector;
179 }
180
181 void RadialSweepViewImpl::SetFinalSector( Dali::Degree finalSector)
182 {
183   mFinalSector = finalSector;
184 }
185
186 void RadialSweepViewImpl::SetInitialActorAngle( Dali::Degree initialAngle )
187 {
188   mInitialActorAngle = initialAngle;
189   mRotateActors = true;
190 }
191
192 void RadialSweepViewImpl::SetFinalActorAngle( Dali::Degree finalAngle )
193 {
194   mFinalActorAngle = finalAngle;
195   mRotateActors = true;
196 }
197
198 float RadialSweepViewImpl::GetDuration( )
199 {
200   return mDuration;
201 }
202
203 float RadialSweepViewImpl::GetDiameter( )
204 {
205   return mDiameter;
206 }
207
208 Dali::Degree RadialSweepViewImpl::GetInitialAngle( )
209 {
210   return mInitialAngle;
211 }
212
213 Dali::Degree RadialSweepViewImpl::GetFinalAngle( )
214 {
215   return mFinalAngle;
216 }
217
218 Dali::Degree RadialSweepViewImpl::GetInitialSector( )
219 {
220   return mInitialSector;
221 }
222
223 Dali::Degree RadialSweepViewImpl::GetFinalSector( )
224 {
225   return mFinalSector;
226 }
227
228 Dali::Degree RadialSweepViewImpl::GetInitialActorAngle( )
229 {
230   return mInitialActorAngle;
231 }
232
233 Dali::Degree RadialSweepViewImpl::GetFinalActorAngle(  )
234 {
235   return mFinalActorAngle;
236 }
237
238 void RadialSweepViewImpl::RotateActorsWithStencil(bool rotate)
239 {
240   mRotateActorsWithStencil = rotate;
241 }
242
243 void RadialSweepViewImpl::Add(Actor actor)
244 {
245   if( ! mLayer )
246   {
247     mLayer = Layer::New();
248     Self().Add(mLayer);
249     mLayer.SetSize( Stage::GetCurrent().GetSize() );
250     mLayer.SetPositionInheritanceMode(USE_PARENT_POSITION);
251   }
252
253   mLayer.Add(actor);
254 }
255
256 void RadialSweepViewImpl::Activate( Animation anim, float offsetTime, float duration )
257 {
258   bool startAnimation=false;
259   if( ! anim )
260   {
261     mAnim = Animation::New( mDuration );
262     anim = mAnim;
263     startAnimation = true;
264   }
265
266   if( ! mStencilActor )
267   {
268     CreateStencil( mInitialSector );
269     mLayer.Add( mStencilActor );
270     mStencilActor.SetSize(mDiameter, mDiameter);
271   }
272
273   mStencilActor.SetOrientation( Degree(mInitialAngle), Vector3::ZAXIS );
274   mStencilActor.SetProperty( mRotationAngleIndex, mInitialSector.degree );
275
276   if( mRotateActors )
277   {
278     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
279     {
280       Actor actor = mLayer.GetChildAt(i);
281       if( actor != mStencilActor )
282       {
283         anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( mInitialActorAngle ), Vector3::ZAXIS ) );
284       }
285     }
286   }
287
288   anim.AnimateTo( Property( mStencilActor, mRotationAngleIndex ), mFinalSector.degree, mEasingFunction, TimePeriod( offsetTime, duration ) );
289   anim.AnimateTo( Property( mStencilActor, Actor::Property::ORIENTATION ), Quaternion( Radian( mFinalAngle ), Vector3::ZAXIS ), mEasingFunction, TimePeriod( offsetTime, duration ) );
290
291   if( mRotateActorsWithStencil )
292   {
293     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
294     {
295       Actor actor = mLayer.GetChildAt(i);
296       if( actor != mStencilActor )
297       {
298         anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( mFinalAngle.degree - mInitialAngle.degree ) ), Vector3::ZAXIS ), mEasingFunction, TimePeriod( offsetTime, duration ) );
299       }
300     }
301   }
302   else if( mRotateActors )
303   {
304     for(unsigned int i=0, count=mLayer.GetChildCount(); i<count; i++)
305     {
306       Actor actor = mLayer.GetChildAt(i);
307       if( actor != mStencilActor )
308       {
309         anim.AnimateTo( Property( actor, Actor::Property::ORIENTATION ), Quaternion( Radian( mFinalActorAngle ), Vector3::ZAXIS ), mEasingFunction, TimePeriod( offsetTime, duration ) );
310       }
311     }
312   }
313
314
315   if( startAnimation )
316   {
317     anim.SetLooping(true);
318     anim.Play();
319   }
320 }
321
322
323 void RadialSweepViewImpl::Deactivate()
324 {
325   if( mAnim )
326   {
327     mAnim.Stop();
328   }
329   // mLayer.Remove( mStencilActor );
330   // mStencilActor.Reset();
331   // mMesh.Reset();
332   // mMaterial.Reset();
333 }
334
335 void RadialSweepViewImpl::CreateStencil( Degree initialSector )
336 {
337   mMaterial = Material::New("Material");
338   mMaterial.SetDiffuseColor(Color::WHITE);
339   mMaterial.SetAmbientColor(Vector4(0.0, 0.1, 0.1, 1.0));
340
341   // Generate a square mesh with a point at the center:
342
343   AnimatableMesh::Faces faces;
344   // Create triangles joining up the verts
345   faces.push_back(0); faces.push_back(1); faces.push_back(2);
346   faces.push_back(0); faces.push_back(2); faces.push_back(3);
347   faces.push_back(0); faces.push_back(3); faces.push_back(4);
348   faces.push_back(0); faces.push_back(4); faces.push_back(5);
349   faces.push_back(0); faces.push_back(5); faces.push_back(6);
350
351   mMesh = AnimatableMesh::New(7, faces, mMaterial);
352   mMesh[0].SetPosition( Vector3(  0.0f,  0.0f, 0.0f ) ); // Center pt
353
354   mStencilActor = MeshActor::New(mMesh);
355   mStencilActor.SetCullFace(CullNone); // Allow clockwise & anticlockwise faces
356
357   mStartAngleIndex = mStencilActor.RegisterProperty("start-angle", Property::Value(0.0f));
358   mRotationAngleIndex = mStencilActor.RegisterProperty("rotation-angle", Property::Value(initialSector.degree));
359
360   Source srcStart( mStencilActor, mStartAngleIndex );
361   Source srcRotation( mStencilActor, mRotationAngleIndex );
362
363   // Constrain the vertices of the square mesh to sweep out a sector as the
364   // rotation angle is animated.
365   Constraint constraint = Constraint::New<Vector3>( mMesh, mMesh.GetPropertyIndex(1, AnimatableVertex::Property::POSITION), SquareFanConstraint(0) );
366   constraint.AddSource( srcStart );
367   constraint.AddSource( srcStart );
368   constraint.Apply();
369
370   constraint = Constraint::New<Vector3>( mMesh, mMesh.GetPropertyIndex(2, AnimatableVertex::Property::POSITION), SquareFanConstraint(0) );
371   constraint.AddSource( srcStart );
372   constraint.AddSource( srcRotation );
373   constraint.Apply();
374
375   constraint = Constraint::New<Vector3>( mMesh, mMesh.GetPropertyIndex(3, AnimatableVertex::Property::POSITION), SquareFanConstraint(1) );
376   constraint.AddSource( srcStart );
377   constraint.AddSource( srcRotation );
378   constraint.Apply();
379
380   constraint = Constraint::New<Vector3>( mMesh, mMesh.GetPropertyIndex(4, AnimatableVertex::Property::POSITION), SquareFanConstraint(2) );
381   constraint.AddSource( srcStart );
382   constraint.AddSource( srcRotation );
383   constraint.Apply();
384
385   constraint = Constraint::New<Vector3>( mMesh, mMesh.GetPropertyIndex(5, AnimatableVertex::Property::POSITION), SquareFanConstraint(3) );
386   constraint.AddSource( srcStart );
387   constraint.AddSource( srcRotation );
388   constraint.Apply();
389
390   constraint = Constraint::New<Vector3>( mMesh, mMesh.GetPropertyIndex(6, AnimatableVertex::Property::POSITION), SquareFanConstraint(4) );
391   constraint.AddSource( srcStart );
392   constraint.AddSource( srcRotation );
393   constraint.Apply();
394
395   mStencilActor.SetDrawMode( DrawMode::STENCIL );
396   mStencilActor.SetPositionInheritanceMode(USE_PARENT_POSITION);
397 }