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