888322aea71577fa228a966c0263f7e7ed092d2f
[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/common/stage.h>
24 #include <dali/public-api/images/buffer-image.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27 #include <dali/public-api/render-tasks/render-task-list.h>
28
29 namespace Dali
30 {
31
32 namespace Toolkit
33 {
34
35 namespace Internal
36 {
37
38 namespace
39 {
40
41 // Setup properties, signals and actions using the type-registry.
42 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::CubeTransitionEffect, Dali::BaseHandle, NULL );
43
44 DALI_SIGNAL_REGISTRATION( CubeTransitionEffect, "transition-completed", SIGNAL_TRANSITION_COMPLETED )
45
46 DALI_TYPE_REGISTRATION_END()
47
48 }
49
50 const Vector4 CubeTransitionEffect::FULL_BRIGHTNESS( 1.0f, 1.0f, 1.0f, 1.0f );
51 const Vector4 CubeTransitionEffect::HALF_BRIGHTNESS( 0.5f, 0.5f, 0.5f, 1.0f );
52
53 CubeTransitionEffect::CubeTransitionEffect( unsigned int numRows, unsigned int numColumns, Size viewAreaSize )
54 : mNumRows( numRows ),
55   mNumColumns( numColumns ),
56   mViewAreaSize( viewAreaSize ),
57   mRotateIndex( 0 ),
58   mContainerIndex( 0 ),
59   mChangeTurningDirection( false ),
60   mIsToNextImage( true ),
61   mIsImageLoading( false ),
62   mAnimationDuration( 1.f ),
63   mIsAnimating( false ),
64   mIsPaused( false ),
65   mCubeDisplacement( 0.f ),
66   mFirstTransition( true ),
67   mBufferIndex( 0 )
68 {
69 }
70
71 CubeTransitionEffect::~CubeTransitionEffect()
72 {
73 }
74
75 void CubeTransitionEffect::Initialize()
76 {
77   //create root actor for the cube transition effect, only visible during the transition
78   mRoot = Actor::New();
79   mRoot.SetParentOrigin( ParentOrigin::CENTER );
80   mRoot.SetAnchorPoint( AnchorPoint::CENTER );
81   mRoot.SetVisible(false);
82
83   // create two groups of tiles,
84   // and one group of actors (cubes) serving as parents of every two tiles (one from each image).
85   unsigned int totalNum = mNumColumns* mNumRows;
86   mBoxes.resize( totalNum );
87   mTiles[0].resize( totalNum );
88   mTiles[1].resize( totalNum );
89   mTileSize = Vector2( mViewAreaSize.width / mNumColumns, mViewAreaSize.height / mNumRows );
90   const Vector3 basePosition( (-mViewAreaSize.width + mTileSize.width) * 0.5f,
91                               (-mViewAreaSize.height + mTileSize.height) * 0.5f,
92                               -mTileSize.width * 0.5f );
93
94   Image placeHolder = BufferImage::WHITE();
95   for( unsigned int y = 0; y < mNumRows; y++ )
96   {
97     float positionY = y * mTileSize.height + basePosition.y;
98     for( unsigned int x = 0; x < mNumColumns; x++)
99     {
100       unsigned int idx = y*mNumColumns + x;
101       Actor actor( Actor::New() );
102       mBoxes[idx] = actor;
103       actor.SetParentOrigin( ParentOrigin::CENTER );
104       actor.SetAnchorPoint( AnchorPoint::CENTER );
105       actor.SetPosition( x * mTileSize.width + basePosition.x,
106                          positionY,
107                          basePosition.z );
108       mRoot.Add( actor );
109
110       mTiles[ 0 ][idx] = CreateTile( placeHolder, FULL_BRIGHTNESS );
111       actor.Add( mTiles[ 0 ][idx] );
112
113       mTiles[ 1 ][idx] = CreateTile( placeHolder, HALF_BRIGHTNESS );
114       actor.Add( mTiles[ 1 ][idx] );
115     }
116   }
117
118   // helper actor to create a off-screen image using shader effect
119   mEmptyImage = ImageActor::New( placeHolder );
120   mEmptyImage.SetRelayoutEnabled( false );
121   mEmptyImage.SetSize(Stage::GetCurrent().GetSize());
122   mEmptyImage.SetParentOrigin( ParentOrigin::CENTER );
123   mEmptyImage.SetAnchorPoint( AnchorPoint::CENTER );
124   mFullImageCreator = FullAreaImageCreator::New();
125   mEmptyImage.SetShaderEffect( mFullImageCreator );
126   Stage::GetCurrent().Add(mEmptyImage);
127
128   // set up off-screen render task
129   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
130   mOffScreenTask = taskList.CreateTask();
131   mOffScreenTask.SetSourceActor(mEmptyImage);
132   mOffScreenTask.SetExclusive(true);
133   mOffScreenBuffer[0] = FrameBufferImage::New(mViewAreaSize.x, mViewAreaSize.y);
134   mOffScreenBuffer[1] = FrameBufferImage::New(mViewAreaSize.x, mViewAreaSize.y);
135   mOffScreenTask.SetTargetFrameBuffer(mOffScreenBuffer[mBufferIndex]);
136   mOffScreenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
137
138   OnInitialize();
139 }
140
141 ImageActor CubeTransitionEffect::CreateTile( Image image, const Vector4& color )
142 {
143   ImageActor tile = ImageActor::New( image );
144   tile.SetRelayoutEnabled( false );
145   tile.SetParentOrigin( ParentOrigin::CENTER );
146   tile.SetAnchorPoint( AnchorPoint::CENTER );
147   tile.SetSize( mTileSize );
148   tile.SetColorMode( Dali::USE_OWN_COLOR );
149   tile.SetColor( color );
150
151   return tile;
152 }
153
154 void CubeTransitionEffect::SetTransitionDuration( float duration )
155 {
156   mAnimationDuration = duration;
157 }
158
159 float CubeTransitionEffect::GetTransitionDuration( ) const
160 {
161   return mAnimationDuration;
162 }
163
164 void CubeTransitionEffect::SetCubeDisplacement( float displacement )
165 {
166   mCubeDisplacement = displacement;
167 }
168
169 float CubeTransitionEffect::GetCubeDisplacement() const
170 {
171   return mCubeDisplacement;
172 }
173
174 Actor CubeTransitionEffect::GetRoot()
175 {
176   return mRoot;
177 }
178
179 bool CubeTransitionEffect::IsTransiting()
180 {
181   return mIsImageLoading || mIsAnimating;
182 }
183
184 void CubeTransitionEffect::SetCurrentImage( ImageActor imageActor )
185 {
186   mContainerIndex = std::abs(mRotateIndex) % 2;
187   SetImage( imageActor );
188 }
189
190 void CubeTransitionEffect::SetTargetImage( ImageActor imageActor )
191 {
192   mContainerIndex = std::abs( mRotateIndex+1 ) % 2;
193   SetImage( imageActor );
194 }
195
196 void CubeTransitionEffect::SetImage( ImageActor imageActor )
197 {
198   mCurrentImage = imageActor;
199
200   Image image = imageActor.GetImage();
201   ResourceImage resourceImage = ResourceImage::DownCast( image );
202   mBufferIndex = mBufferIndex^1;
203
204   //must make sure the image is already loaded before using its attributes
205   if( resourceImage && resourceImage.GetLoadingState() != ResourceLoadingSucceeded )
206   {
207     mIsImageLoading = true;
208     resourceImage.LoadingFinishedSignal().Connect( this, &CubeTransitionEffect::OnImageLoaded );
209   }
210   else
211   {
212     mIsImageLoading = false;
213     PrepareTiles( image );
214   }
215 }
216
217 void CubeTransitionEffect::StartTransition( bool toNextImage )
218 {
219   if( toNextImage )
220   {
221     StartTransition( Vector2( mViewAreaSize.width, mViewAreaSize.height*0.5f ), Vector2( -10.f, 0.f ) );
222   }
223   else
224   {
225     StartTransition( Vector2( 0, mViewAreaSize.height*0.5f ), Vector2( 10.f, 0.f ));
226   }
227 }
228
229 void CubeTransitionEffect::StartTransition( Vector2 panPosition, Vector2 panDisplacement )
230 {
231   mRoot.SetVisible( true );
232   mCurrentImage.SetVisible( false );
233   bool toNextImage = ( panDisplacement.x < 0 ) ? true : false;
234   if( mIsToNextImage != toNextImage )
235   {
236     mChangeTurningDirection = true;
237   }
238   else
239   {
240     mChangeTurningDirection = false;
241   }
242   mIsToNextImage = toNextImage;
243
244   if( mIsToNextImage )
245   {
246     mRotateIndex += 1.f;
247   }
248   else
249   {
250     mRotateIndex -= 1.f;
251   }
252
253   if(mAnimation)
254   {
255     mAnimation.Clear();
256     mAnimation.Reset();
257   }
258   mAnimation = Animation::New( mAnimationDuration );
259   mAnimation.FinishedSignal().Connect(this, &CubeTransitionEffect::OnTransitionFinished);
260
261   OnStartTransition( panPosition, panDisplacement );
262 }
263
264 void CubeTransitionEffect::PauseTransition()
265 {
266   if( mIsAnimating && !mIsPaused )
267   {
268     mAnimation.Pause();
269     mIsPaused = true;
270   }
271 }
272
273 void CubeTransitionEffect::ResumeTransition()
274 {
275   if( mIsAnimating && mIsPaused)
276   {
277     mAnimation.Play();
278     mIsPaused = false;
279   }
280 }
281
282 void CubeTransitionEffect::StopTransition()
283 {
284   if( mIsAnimating )
285   {
286     mAnimation.Clear();
287     mAnimation.Reset();
288     mIsPaused = false;
289
290     //reset the position of the cubes
291     //reset the color of the tiles
292     //all these status should be the same as the final state when the transition animation is finished completely
293     const Vector3 basePosition( (-mViewAreaSize.width + mTileSize.width) * 0.5f,
294                                 (-mViewAreaSize.height + mTileSize.height) * 0.5f,
295                                  -mTileSize.width * 0.5f );
296     unsigned int anotherIndex = mContainerIndex^1;
297     for( unsigned int y = 0; y < mNumRows; y++ )
298     {
299       float positionY = y * mTileSize.height + basePosition.y;
300       for( unsigned int x = 0; x < mNumColumns; x++)
301       {
302         unsigned int idx = y*mNumColumns + x;
303         mBoxes[idx].SetPosition( x * mTileSize.width + basePosition.x,
304                                  positionY,
305                                  basePosition.z );
306         mTiles[mContainerIndex][idx].SetColor( FULL_BRIGHTNESS );
307         mTiles[anotherIndex][idx].SetColor( HALF_BRIGHTNESS);
308       }
309     }
310
311     // reset the rotation of the cubes, which is different process for different derived classes
312     OnStopTransition();
313
314     mRoot.SetVisible(false);
315     mCurrentImage.SetVisible(true);
316     mIsAnimating = false;
317     mFirstTransition = false;
318   }
319 }
320
321 void CubeTransitionEffect::OnImageLoaded(ResourceImage image)
322 {
323   mIsImageLoading = false;
324   PrepareTiles( image );
325 }
326
327 /**
328  * Set sub-image to each tile.
329  * @param[in] image The image content of the imageActor for transition
330  */
331 void CubeTransitionEffect::PrepareTiles( Image image )
332 {
333   // Fit the image to view area, while keeping the aspect; FitKeepAspectRatio(imageSize, viewAreaSize)
334   float scale = std::min(  mViewAreaSize.width / image.GetWidth(), mViewAreaSize.height / image.GetHeight() );
335   Vector2 imageSize(image.GetWidth()*scale, image.GetHeight()*scale);
336
337   mFullImageCreator.SetEffectImage(image);
338   mFullImageCreator.SetRegionSize(mViewAreaSize, imageSize);
339
340   mOffScreenTask.SetTargetFrameBuffer(mOffScreenBuffer[mBufferIndex]);
341   mOffScreenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
342
343   ImageActor::PixelArea pixelArea( 0, 0, mViewAreaSize.x / mNumColumns, mViewAreaSize.y / mNumRows);
344
345   for( unsigned int y = 0; y < mNumRows; y++ )
346   {
347     pixelArea.y = y * pixelArea.height;
348     for( unsigned int x = 0; x < mNumColumns; x++)
349     {
350       pixelArea.x = x * pixelArea.width;
351       unsigned int idx = y*mNumColumns + x;
352       mTiles[mContainerIndex][idx].SetImage( mOffScreenBuffer[mBufferIndex]);
353       mTiles[mContainerIndex][idx].SetPixelArea( pixelArea );
354     }
355   }
356 }
357
358
359 void CubeTransitionEffect::OnTransitionFinished(Animation& source)
360 {
361   mRoot.SetVisible(false);
362   mCurrentImage.SetVisible(true);
363   mIsAnimating = false;
364   mFirstTransition = false;
365
366   //Emit signal
367   Toolkit::CubeTransitionEffect handle( this );
368   mTransitionCompletedSignal.Emit( handle, mCurrentImage );
369 }
370
371 Toolkit::CubeTransitionEffect::TransitionCompletedSignalType& CubeTransitionEffect::TransitionCompletedSignal()
372 {
373   return mTransitionCompletedSignal;
374 }
375
376 bool CubeTransitionEffect::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
377 {
378   Dali::BaseHandle handle( object );
379
380   bool connected( true );
381   Toolkit::CubeTransitionEffect cubeTransitionEffect = Toolkit::CubeTransitionEffect::DownCast( handle );
382
383   if( 0 == strcmp( signalName.c_str(), SIGNAL_TRANSITION_COMPLETED ) )
384   {
385     cubeTransitionEffect.TransitionCompletedSignal().Connect( tracker, functor );
386   }
387   else
388   {
389     // signalName does not match any signal
390     connected = false;
391   }
392
393   return connected;
394 }
395
396 } // namespace Internal
397
398 } // namespace Toolkit
399
400 } // namespace Dali