Use Geometry::QUAD() in toolkit
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / transition-effects / cube-transition-effect-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 // CLASS HEADER
19 #include "cube-transition-effect-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <dali/public-api/object/type-registry.h>
24 #include <dali/devel-api/object/type-registry-helper.h>
25 #include <dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h>
26 #include <dali/integration-api/debug.h>
27
28 namespace Dali
29 {
30
31 namespace Toolkit
32 {
33
34 namespace Internal
35 {
36
37 namespace
38 {
39
40 // Setup properties, signals and actions using the type-registry.
41 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::CubeTransitionEffect, Dali::BaseHandle, NULL );
42
43 DALI_SIGNAL_REGISTRATION( Toolkit, CubeTransitionEffect, "transitionCompleted",  SIGNAL_TRANSITION_COMPLETED )
44
45 DALI_TYPE_REGISTRATION_END()
46
47 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
48   attribute mediump vec2 aPosition;\n
49   varying mediump vec2 vTexCoord;\n
50   uniform mediump mat4 uMvpMatrix;\n
51   uniform mediump vec3 uSize;\n
52   uniform mediump vec4 uTextureRect;\n
53   \n
54   void main()\n
55   {\n
56     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
57     vertexPosition.xyz *= uSize;\n
58     vertexPosition = uMvpMatrix * vertexPosition;\n
59     \n
60     vTexCoord = aPosition + vec2(0.5);\n
61     vTexCoord = mix(uTextureRect.xy, uTextureRect.zw, vTexCoord);\n
62
63     gl_Position = vertexPosition;\n
64   }\n
65 );
66
67 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
68   varying mediump vec2 vTexCoord;\n
69   uniform sampler2D sTexture;\n
70   uniform lowp vec4 uColor;\n
71   uniform lowp vec4 uSamplerRect;
72   \n
73   void main()\n
74   {\n
75     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
76   }\n
77 );
78
79 Actor CreateTile( const Vector4& samplerRect )
80 {
81  Actor tile = Actor::New();
82   tile.SetAnchorPoint( AnchorPoint::CENTER );
83   tile.RegisterProperty( "uTextureRect", samplerRect );
84   return tile;
85 }
86
87 }
88
89 const Vector4 CubeTransitionEffect::FULL_BRIGHTNESS( 1.0f, 1.0f, 1.0f, 1.0f );
90 const Vector4 CubeTransitionEffect::HALF_BRIGHTNESS( 0.5f, 0.5f, 0.5f, 1.0f );
91
92 CubeTransitionEffect::CubeTransitionEffect( unsigned int rows, unsigned int columns )
93 : Control( ControlBehaviour( 0 ) ),
94   mRows( rows ),
95   mColumns( columns ),
96   mIsAnimating( false ),
97   mIsPaused( false ),
98   mAnimationDuration( 1.f ),
99   mCubeDisplacement( 0.f )
100 {
101 }
102
103 CubeTransitionEffect::~CubeTransitionEffect()
104 {
105 }
106
107 void CubeTransitionEffect::SetTargetRight( unsigned int idx )
108 {
109   mBoxType[ idx ] = RIGHT;
110
111   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
112
113   mTargetTiles[ idx ].SetParentOrigin( Vector3( 1.f, 0.5f, 0.5f) );
114   mTargetTiles[ idx ].SetOrientation( Degree( 90.f ), Vector3::YAXIS );
115 }
116
117 void CubeTransitionEffect::SetTargetLeft( unsigned int idx )
118 {
119   mBoxType[ idx ] = LEFT;
120
121   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
122
123   mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.f, 0.5f, 0.5f) );
124   mTargetTiles[ idx ].SetOrientation( Degree( -90.f ), Vector3::YAXIS );
125 }
126
127 void CubeTransitionEffect::SetTargetBottom( unsigned int idx )
128 {
129   mBoxType[ idx ] = BOTTOM;
130
131   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
132
133   mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.5f, 0.f, 0.5f) );
134   mTargetTiles[ idx ].SetOrientation( Degree( 90.f ), Vector3::XAXIS );
135 }
136
137 void CubeTransitionEffect::SetTargetTop( unsigned int idx )
138 {
139   mBoxType[ idx ] = TOP;
140
141   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
142
143   mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.5f, 1.f, 0.5f) );
144   mTargetTiles[ idx ].SetOrientation( Degree( -90.f ), Vector3::XAXIS );
145 }
146
147 void CubeTransitionEffect::OnRelayout( const Vector2& size, RelayoutContainer& container )
148 {
149   mTileSize = Vector2( size.x / mColumns, size.y / mRows );
150
151   mBoxRoot.SetProperty( Actor::Property::SIZE_WIDTH, size.x );
152   mBoxRoot.SetProperty( Actor::Property::SIZE_HEIGHT, size.y );
153   mBoxRoot.SetProperty( Actor::Property::SIZE_DEPTH, 1.0f );
154
155   for( size_t i = 0; i < mBoxes.size(); ++i )
156   {
157     mBoxes[ i ].SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
158     mBoxes[ i ].SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
159
160     switch( mBoxType[i] )
161     {
162       case LEFT:
163       case RIGHT:
164       {
165         mBoxes[ i ].SetProperty( Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
166         mBoxes[ i ].SetProperty( Actor::Property::SIZE_DEPTH, mTileSize.x );
167         break;
168       }
169       case BOTTOM:
170       case TOP:
171       {
172         mBoxes[ i ].SetProperty( Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
173         mBoxes[ i ].SetProperty( Actor::Property::SIZE_DEPTH, mTileSize.y );
174         break;
175       }
176     }
177   }
178
179   for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
180   {
181     it->SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
182     it->SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
183   }
184   for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
185   {
186     it->SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
187     it->SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
188   }
189 }
190
191 void CubeTransitionEffect::Initialize()
192 {
193   Self().RegisterProperty( "uTextureRect", Vector4( 0.0f, 0.0f, 1.0f, 1.0f ) );
194
195   mBoxType.Resize(mColumns * mRows);
196
197   //create the box parents
198   mBoxRoot = Actor::New();
199   mBoxRoot.SetParentOrigin( ParentOrigin::CENTER );
200   mBoxRoot.SetAnchorPoint( AnchorPoint::CENTER );
201
202   mCurrentTiles.clear();
203   mTargetTiles.clear();
204
205   mCurrentTiles.reserve( mColumns * mRows );
206   mTargetTiles.reserve( mColumns * mRows );
207
208   Vector2 gridSizeInv( 1.0f / mColumns, 1.0f / mRows );
209   Vector3 offset( 0.5f * gridSizeInv.x, 0.5f * gridSizeInv.y, 0.0f );
210
211   Vector3 anchor;
212   for( unsigned int y = 0; y < mRows; ++y, anchor.y += 1.0f / mRows )
213   {
214     anchor.x = 0.0f;
215     for( unsigned int x = 0; x <mColumns; ++x, anchor.x += 1.0f / mColumns )
216     {
217       Vector4 textureRect( anchor.x, anchor.y, anchor.x + gridSizeInv.x, anchor.y + gridSizeInv.y );
218
219       Actor currentTile = CreateTile( textureRect );
220       currentTile.SetProperty( Actor::Property::COLOR, FULL_BRIGHTNESS );
221       currentTile.SetParentOrigin( ParentOrigin::CENTER );
222       mCurrentTiles.push_back( currentTile );
223
224       Actor targetTile = CreateTile( textureRect );
225       targetTile.SetProperty( Actor::Property::COLOR, HALF_BRIGHTNESS );
226       mTargetTiles.push_back( targetTile );
227
228       Actor box = Actor::New();
229       box.SetParentOrigin( anchor + offset );
230       box.SetAnchorPoint( AnchorPoint::CENTER );
231
232       box.Add( currentTile );
233       box.Add( targetTile );
234
235       mBoxRoot.Add( box );
236
237       mBoxes.push_back( box );
238     }
239   }
240
241   OnInitialize();
242 }
243
244 void CubeTransitionEffect::OnStageConnection( int depth )
245 {
246   Control::OnStageConnection( depth );
247
248   Geometry geometry = Geometry::QUAD();
249   Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
250
251   TextureSet textureSet = TextureSet::New();
252
253   if( mCurrentImage )
254   {
255     textureSet.SetImage( 0u, mCurrentImage );
256   }
257   mCurrentRenderer = Renderer::New( geometry, shader );
258   mCurrentRenderer.SetTextures( textureSet );
259
260   mCurrentRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, depth );
261   Self().AddRenderer( mCurrentRenderer );
262 }
263
264 void CubeTransitionEffect::OnStageDisconnection()
265 {
266   if( mCurrentRenderer )
267   {
268     Self().RemoveRenderer( mCurrentRenderer );
269
270     for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
271     {
272       it->RemoveRenderer( mCurrentRenderer );
273     }
274     mCurrentRenderer.Reset();
275   }
276
277   if( mTargetRenderer )
278   {
279     for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
280     {
281       it->RemoveRenderer( mTargetRenderer );
282     }
283     mTargetRenderer.Reset();
284   }
285
286   Control::OnStageDisconnection();
287 }
288
289 void CubeTransitionEffect::SetTransitionDuration( float duration )
290 {
291   mAnimationDuration = duration;
292 }
293
294 float CubeTransitionEffect::GetTransitionDuration( ) const
295 {
296   return mAnimationDuration;
297 }
298
299 void CubeTransitionEffect::SetCubeDisplacement( float displacement )
300 {
301   mCubeDisplacement = displacement;
302 }
303
304 float CubeTransitionEffect::GetCubeDisplacement() const
305 {
306   return mCubeDisplacement;
307 }
308
309 bool CubeTransitionEffect::IsTransitioning()
310 {
311   return mIsAnimating;
312 }
313
314 void CubeTransitionEffect::SetCurrentImage( Image image )
315 {
316   mCurrentImage = image;
317   if( mCurrentRenderer )
318   {
319     TextureSet textureSet = mCurrentRenderer.GetTextures();
320     textureSet.SetImage( 0u, mCurrentImage );
321   }
322 }
323
324 void CubeTransitionEffect::SetTargetImage( Image image )
325 {
326   mTargetImage = image;
327
328   if( mTargetRenderer )
329   {
330     TextureSet textureSet = mTargetRenderer.GetTextures();
331     textureSet.SetImage( 0u, mTargetImage );
332   }
333 }
334
335 void CubeTransitionEffect::StartTransition( bool toNextImage )
336 {
337   Vector3 size = Self().GetCurrentSize();
338   if( toNextImage )
339   {
340     StartTransition( Vector2(size.x* 0.5f, size.y*0.5f), Vector2( -10.f, 0.f ) );
341   }
342   else
343   {
344     StartTransition( Vector2(size.x* 0.5f, size.y*0.5f), Vector2( 10.f, 0.f ));
345   }
346 }
347
348 void CubeTransitionEffect::StartTransition( Vector2 panPosition, Vector2 panDisplacement )
349 {
350   if( !mCurrentRenderer )
351   {
352     DALI_LOG_ERROR( "Trying to transition a cube transition without an image set" );
353     return;
354   }
355
356   //create the target renderer
357   TextureSet textureSet = TextureSet::New();
358   if( mTargetImage )
359   {
360     textureSet.SetImage( 0u, mTargetImage );
361   }
362   Geometry geometry = mCurrentRenderer.GetGeometry();
363   Shader shader( mCurrentRenderer.GetShader() );
364   mTargetRenderer = Renderer::New( geometry, shader );
365   mTargetRenderer.SetTextures( textureSet );
366
367   int depthIndex = mCurrentRenderer.GetProperty<int>(Renderer::Property::DEPTH_INDEX);
368   mTargetRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, depthIndex );
369
370   for( size_t i = 0; i < mBoxes.size(); ++i )
371   {
372     mBoxes[ i ].SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
373   }
374
375   for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
376   {
377     it->SetParentOrigin( Vector3( 0.5f, 0.5f, 1.0f) );
378     it->SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
379     it->AddRenderer( mCurrentRenderer );
380   }
381   for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
382   {
383     it->AddRenderer( mTargetRenderer );
384   }
385
386   Self().RemoveRenderer( mCurrentRenderer );
387   Self().Add( mBoxRoot );
388
389   if(mAnimation)
390   {
391     mAnimation.Clear();
392     mAnimation.Reset();
393   }
394
395   mAnimation = Animation::New( mAnimationDuration );
396   mAnimation.FinishedSignal().Connect( this, &CubeTransitionEffect::OnTransitionFinished );
397
398   OnStartTransition( panPosition, panDisplacement );
399 }
400
401 void CubeTransitionEffect::PauseTransition()
402 {
403   if( mIsAnimating && !mIsPaused )
404   {
405     mAnimation.Pause();
406     mIsPaused = true;
407   }
408 }
409
410 void CubeTransitionEffect::ResumeTransition()
411 {
412   if( mIsAnimating && mIsPaused)
413   {
414     mAnimation.Play();
415     mIsPaused = false;
416   }
417 }
418
419 void CubeTransitionEffect::StopTransition()
420 {
421   ResetToInitialState();
422 }
423
424 void CubeTransitionEffect::ResetToInitialState()
425 {
426   mAnimation.Clear();
427   mAnimation.Reset();
428   mIsAnimating = false;
429
430   Self().Remove( mBoxRoot );
431
432   for( size_t i = 0; i < mBoxes.size(); ++i )
433   {
434     mBoxes[ i ].SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
435   }
436
437   for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
438   {
439     it->SetParentOrigin( Vector3( 0.5f, 0.5f, 1.0f) );
440     it->SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
441     it->SetProperty( Actor::Property::COLOR, FULL_BRIGHTNESS );
442   }
443   if( mCurrentRenderer )
444   {
445     for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
446     {
447       it->RemoveRenderer( mCurrentRenderer );
448     }
449     Self().AddRenderer( mCurrentRenderer );
450   }
451
452   for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
453   {
454     it->SetProperty( Actor::Property::COLOR, HALF_BRIGHTNESS );
455   }
456   if( mTargetRenderer )
457   {
458     for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
459     {
460       it->RemoveRenderer( mTargetRenderer );
461     }
462   }
463 }
464
465 void CubeTransitionEffect::OnTransitionFinished(Animation& source)
466 {
467
468   std::swap( mCurrentTiles, mTargetTiles );
469   std::swap( mCurrentRenderer, mTargetRenderer );
470   std::swap( mCurrentImage, mTargetImage );
471
472   ResetToInitialState();
473
474   //Emit signal
475   Toolkit::CubeTransitionEffect handle( GetOwner() );
476   mTransitionCompletedSignal.Emit( handle, mCurrentImage );
477 }
478
479 Toolkit::CubeTransitionEffect::TransitionCompletedSignalType& CubeTransitionEffect::TransitionCompletedSignal()
480 {
481   return mTransitionCompletedSignal;
482 }
483
484 bool CubeTransitionEffect::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
485 {
486   Dali::BaseHandle handle( object );
487
488   bool connected( true );
489   Toolkit::CubeTransitionEffect cubeTransitionEffect = Toolkit::CubeTransitionEffect::DownCast( handle );
490
491   if( 0 == strcmp( signalName.c_str(), SIGNAL_TRANSITION_COMPLETED ) )
492   {
493     cubeTransitionEffect.TransitionCompletedSignal().Connect( tracker, functor );
494   }
495   else
496   {
497     // signalName does not match any signal
498     connected = false;
499   }
500
501   return connected;
502 }
503
504 } // namespace Internal
505
506 } // namespace Toolkit
507
508 } // namespace Dali