PropertyBuffer SetData clean-up
[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 Geometry CreateQuadGeometry()
89 {
90   const float halfWidth = 0.5f;
91   const float halfHeight = 0.5f;
92   struct QuadVertex { Vector2 position;};
93   QuadVertex quadVertexData[4] =
94   {
95       { Vector2(-halfWidth, -halfHeight) },
96       { Vector2( halfWidth, -halfHeight) },
97       { Vector2(-halfWidth, halfHeight)  },
98       { Vector2( halfWidth, halfHeight)  }
99   };
100
101   Property::Map quadVertexFormat;
102   quadVertexFormat["aPosition"] = Property::VECTOR2;
103   PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
104   quadVertices.SetData( quadVertexData, 4 );
105
106   // Create the geometry object
107   Geometry geometry = Geometry::New();
108   geometry.AddVertexBuffer( quadVertices );
109   geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
110
111   return geometry;
112 }
113
114 }
115
116 const Vector4 CubeTransitionEffect::FULL_BRIGHTNESS( 1.0f, 1.0f, 1.0f, 1.0f );
117 const Vector4 CubeTransitionEffect::HALF_BRIGHTNESS( 0.5f, 0.5f, 0.5f, 1.0f );
118
119 CubeTransitionEffect::CubeTransitionEffect( unsigned int rows, unsigned int columns )
120 : Control( ControlBehaviour( 0 ) ),
121   mRows( rows ),
122   mColumns( columns ),
123   mIsAnimating( false ),
124   mIsPaused( false ),
125   mAnimationDuration( 1.f ),
126   mCubeDisplacement( 0.f )
127 {
128 }
129
130 CubeTransitionEffect::~CubeTransitionEffect()
131 {
132 }
133
134 void CubeTransitionEffect::SetTargetRight( unsigned int idx )
135 {
136   mBoxType[ idx ] = RIGHT;
137
138   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
139
140   mTargetTiles[ idx ].SetParentOrigin( Vector3( 1.f, 0.5f, 0.5f) );
141   mTargetTiles[ idx ].SetOrientation( Degree( 90.f ), Vector3::YAXIS );
142 }
143
144 void CubeTransitionEffect::SetTargetLeft( unsigned int idx )
145 {
146   mBoxType[ idx ] = LEFT;
147
148   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
149
150   mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.f, 0.5f, 0.5f) );
151   mTargetTiles[ idx ].SetOrientation( Degree( -90.f ), Vector3::YAXIS );
152 }
153
154 void CubeTransitionEffect::SetTargetBottom( unsigned int idx )
155 {
156   mBoxType[ idx ] = BOTTOM;
157
158   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
159
160   mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.5f, 0.f, 0.5f) );
161   mTargetTiles[ idx ].SetOrientation( Degree( 90.f ), Vector3::XAXIS );
162 }
163
164 void CubeTransitionEffect::SetTargetTop( unsigned int idx )
165 {
166   mBoxType[ idx ] = TOP;
167
168   mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
169
170   mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.5f, 1.f, 0.5f) );
171   mTargetTiles[ idx ].SetOrientation( Degree( -90.f ), Vector3::XAXIS );
172 }
173
174 void CubeTransitionEffect::OnRelayout( const Vector2& size, RelayoutContainer& container )
175 {
176   mTileSize = Vector2( size.x / mColumns, size.y / mRows );
177
178   mBoxRoot.SetProperty( Actor::Property::SIZE_WIDTH, size.x );
179   mBoxRoot.SetProperty( Actor::Property::SIZE_HEIGHT, size.y );
180   mBoxRoot.SetProperty( Actor::Property::SIZE_DEPTH, 1.0f );
181
182   for( size_t i = 0; i < mBoxes.size(); ++i )
183   {
184     mBoxes[ i ].SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
185     mBoxes[ i ].SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
186
187     switch( mBoxType[i] )
188     {
189       case LEFT:
190       case RIGHT:
191       {
192         mBoxes[ i ].SetProperty( Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
193         mBoxes[ i ].SetProperty( Actor::Property::SIZE_DEPTH, mTileSize.x );
194         break;
195       }
196       case BOTTOM:
197       case TOP:
198       {
199         mBoxes[ i ].SetProperty( Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
200         mBoxes[ i ].SetProperty( Actor::Property::SIZE_DEPTH, mTileSize.y );
201         break;
202       }
203     }
204   }
205
206   for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
207   {
208     it->SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
209     it->SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
210   }
211   for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
212   {
213     it->SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
214     it->SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
215   }
216 }
217
218 void CubeTransitionEffect::Initialize()
219 {
220   Self().RegisterProperty( "uTextureRect", Vector4( 0.0f, 0.0f, 1.0f, 1.0f ) );
221
222   mBoxType.Resize(mColumns * mRows);
223
224   //create the box parents
225   mBoxRoot = Actor::New();
226   mBoxRoot.SetParentOrigin( ParentOrigin::CENTER );
227   mBoxRoot.SetAnchorPoint( AnchorPoint::CENTER );
228
229   mCurrentTiles.clear();
230   mTargetTiles.clear();
231
232   mCurrentTiles.reserve( mColumns * mRows );
233   mTargetTiles.reserve( mColumns * mRows );
234
235   Vector2 gridSizeInv( 1.0f / mColumns, 1.0f / mRows );
236   Vector3 offset( 0.5f * gridSizeInv.x, 0.5f * gridSizeInv.y, 0.0f );
237
238   Vector3 anchor;
239   for( unsigned int y = 0; y < mRows; ++y, anchor.y += 1.0f / mRows )
240   {
241     anchor.x = 0.0f;
242     for( unsigned int x = 0; x <mColumns; ++x, anchor.x += 1.0f / mColumns )
243     {
244       Vector4 textureRect( anchor.x, anchor.y, anchor.x + gridSizeInv.x, anchor.y + gridSizeInv.y );
245
246       Actor currentTile = CreateTile( textureRect );
247       currentTile.SetProperty( Actor::Property::COLOR, FULL_BRIGHTNESS );
248       currentTile.SetParentOrigin( ParentOrigin::CENTER );
249       mCurrentTiles.push_back( currentTile );
250
251       Actor targetTile = CreateTile( textureRect );
252       targetTile.SetProperty( Actor::Property::COLOR, HALF_BRIGHTNESS );
253       mTargetTiles.push_back( targetTile );
254
255       Actor box = Actor::New();
256       box.SetParentOrigin( anchor + offset );
257       box.SetAnchorPoint( AnchorPoint::CENTER );
258
259       box.Add( currentTile );
260       box.Add( targetTile );
261
262       mBoxRoot.Add( box );
263
264       mBoxes.push_back( box );
265     }
266   }
267
268   OnInitialize();
269 }
270
271 void CubeTransitionEffect::OnStageConnection( int depth )
272 {
273   Geometry geometry = CreateQuadGeometry();
274   Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
275
276   Material material = Material::New( shader );
277
278   if( mCurrentImage )
279   {
280     material.AddTexture( mCurrentImage, "sTexture" );
281   }
282   mCurrentRenderer = Renderer::New( geometry, material );
283
284   mCurrentRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, depth );
285   Self().AddRenderer( mCurrentRenderer );
286 }
287
288 void CubeTransitionEffect::OnStageDisconnection()
289 {
290   if( mCurrentRenderer )
291   {
292     Self().RemoveRenderer( mCurrentRenderer );
293
294     for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
295     {
296       it->RemoveRenderer( mCurrentRenderer );
297     }
298     mCurrentRenderer.Reset();
299   }
300
301   if( mTargetRenderer )
302   {
303     for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
304     {
305       it->RemoveRenderer( mTargetRenderer );
306     }
307     mTargetRenderer.Reset();
308   }
309 }
310
311 void CubeTransitionEffect::SetTransitionDuration( float duration )
312 {
313   mAnimationDuration = duration;
314 }
315
316 float CubeTransitionEffect::GetTransitionDuration( ) const
317 {
318   return mAnimationDuration;
319 }
320
321 void CubeTransitionEffect::SetCubeDisplacement( float displacement )
322 {
323   mCubeDisplacement = displacement;
324 }
325
326 float CubeTransitionEffect::GetCubeDisplacement() const
327 {
328   return mCubeDisplacement;
329 }
330
331 bool CubeTransitionEffect::IsTransitioning()
332 {
333   return mIsAnimating;
334 }
335
336 void CubeTransitionEffect::SetCurrentImage( Image image )
337 {
338   mCurrentImage = image;
339
340   if( mCurrentRenderer )
341   {
342     Material material = mCurrentRenderer.GetMaterial();
343
344     int index = material.GetTextureIndex("sTexture" );
345     if( index != -1 )
346     {
347       material.SetTextureImage( index, mCurrentImage );
348     }
349     else
350     {
351       material.AddTexture( mCurrentImage, "sTexture" );
352     }
353   }
354 }
355
356 void CubeTransitionEffect::SetTargetImage( Image image )
357 {
358   mTargetImage = image;
359
360   if( mTargetRenderer )
361   {
362     Material material = mTargetRenderer.GetMaterial();
363     material.AddTexture( mTargetImage, "sTexture" );
364   }
365 }
366
367 void CubeTransitionEffect::StartTransition( bool toNextImage )
368 {
369   Vector3 size = Self().GetCurrentSize();
370   if( toNextImage )
371   {
372     StartTransition( Vector2(size.x* 0.5f, size.y*0.5f), Vector2( -10.f, 0.f ) );
373   }
374   else
375   {
376     StartTransition( Vector2(size.x* 0.5f, size.y*0.5f), Vector2( 10.f, 0.f ));
377   }
378 }
379
380 void CubeTransitionEffect::StartTransition( Vector2 panPosition, Vector2 panDisplacement )
381 {
382   if( !mCurrentRenderer )
383   {
384     DALI_LOG_ERROR( "Trying to transition a cube transition without an image set" );
385     return;
386   }
387
388   //create the target renderer
389   Material material = Material::New( mCurrentRenderer.GetMaterial().GetShader() );
390   if( mTargetImage )
391   {
392     material.AddTexture( mTargetImage, "sTexture" );
393   }
394   Geometry geometry = mCurrentRenderer.GetGeometry();
395   mTargetRenderer = Renderer::New( geometry, material );
396
397   int depthIndex = mCurrentRenderer.GetProperty<int>(Renderer::Property::DEPTH_INDEX);
398   mTargetRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, depthIndex );
399
400   for( size_t i = 0; i < mBoxes.size(); ++i )
401   {
402     mBoxes[ i ].SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
403   }
404
405   for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
406   {
407     it->SetParentOrigin( Vector3( 0.5f, 0.5f, 1.0f) );
408     it->SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
409     it->AddRenderer( mCurrentRenderer );
410   }
411   for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
412   {
413     it->AddRenderer( mTargetRenderer );
414   }
415
416   Self().RemoveRenderer( mCurrentRenderer );
417   Self().Add( mBoxRoot );
418
419   if(mAnimation)
420   {
421     mAnimation.Clear();
422     mAnimation.Reset();
423   }
424
425   mAnimation = Animation::New( mAnimationDuration );
426   mAnimation.FinishedSignal().Connect( this, &CubeTransitionEffect::OnTransitionFinished );
427
428   OnStartTransition( panPosition, panDisplacement );
429 }
430
431 void CubeTransitionEffect::PauseTransition()
432 {
433   if( mIsAnimating && !mIsPaused )
434   {
435     mAnimation.Pause();
436     mIsPaused = true;
437   }
438 }
439
440 void CubeTransitionEffect::ResumeTransition()
441 {
442   if( mIsAnimating && mIsPaused)
443   {
444     mAnimation.Play();
445     mIsPaused = false;
446   }
447 }
448
449 void CubeTransitionEffect::StopTransition()
450 {
451   ResetToInitialState();
452 }
453
454 void CubeTransitionEffect::ResetToInitialState()
455 {
456   mAnimation.Clear();
457   mAnimation.Reset();
458   mIsAnimating = false;
459
460   Self().Remove( mBoxRoot );
461
462   for( size_t i = 0; i < mBoxes.size(); ++i )
463   {
464     mBoxes[ i ].SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
465   }
466
467   for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
468   {
469     it->SetParentOrigin( Vector3( 0.5f, 0.5f, 1.0f) );
470     it->SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
471     it->SetProperty( Actor::Property::COLOR, FULL_BRIGHTNESS );
472   }
473   if( mCurrentRenderer )
474   {
475     for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
476     {
477       it->RemoveRenderer( mCurrentRenderer );
478     }
479     Self().AddRenderer( mCurrentRenderer );
480   }
481
482   for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
483   {
484     it->SetProperty( Actor::Property::COLOR, HALF_BRIGHTNESS );
485   }
486   if( mTargetRenderer )
487   {
488     for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
489     {
490       it->RemoveRenderer( mTargetRenderer );
491     }
492   }
493 }
494
495 void CubeTransitionEffect::OnTransitionFinished(Animation& source)
496 {
497
498   std::swap( mCurrentTiles, mTargetTiles );
499   std::swap( mCurrentRenderer, mTargetRenderer );
500   std::swap( mCurrentImage, mTargetImage );
501
502   ResetToInitialState();
503
504   //Emit signal
505   Toolkit::CubeTransitionEffect handle( GetOwner() );
506   mTransitionCompletedSignal.Emit( handle, mCurrentImage );
507 }
508
509 Toolkit::CubeTransitionEffect::TransitionCompletedSignalType& CubeTransitionEffect::TransitionCompletedSignal()
510 {
511   return mTransitionCompletedSignal;
512 }
513
514 bool CubeTransitionEffect::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
515 {
516   Dali::BaseHandle handle( object );
517
518   bool connected( true );
519   Toolkit::CubeTransitionEffect cubeTransitionEffect = Toolkit::CubeTransitionEffect::DownCast( handle );
520
521   if( 0 == strcmp( signalName.c_str(), SIGNAL_TRANSITION_COMPLETED ) )
522   {
523     cubeTransitionEffect.TransitionCompletedSignal().Connect( tracker, functor );
524   }
525   else
526   {
527     // signalName does not match any signal
528     connected = false;
529   }
530
531   return connected;
532 }
533
534 } // namespace Internal
535
536 } // namespace Toolkit
537
538 } // namespace Dali