License conversion from Flora to Apache 2.0
[platform/core/uifw/dali-toolkit.git] / optional / dali-toolkit / internal / controls / magnifier / magnifier-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 <dali-toolkit/internal/controls/magnifier/magnifier-impl.h>
19
20 using namespace Dali;
21
22 namespace // unnamed namespace
23 {
24
25 const char* DEFAULT_FRAME_IMAGE_PATH = DALI_IMAGE_DIR "magnifier-image-frame.png";
26
27 const float IMAGE_BORDER_INDENT = 14.0f;            ///< Indent of border in pixels.
28
29 /**
30  * ImageBorderSizeConstraint
31  */
32 struct ImageBorderSizeConstraint
33 {
34   ImageBorderSizeConstraint()
35   : mSizeOffset(Vector3(IMAGE_BORDER_INDENT - 1, IMAGE_BORDER_INDENT - 1, 0.0f) * 2.0f)
36   {
37   }
38
39   Vector3 operator()(const Vector3&    current,
40                      const PropertyInput& referenceSizeProperty)
41   {
42     const Vector3& referenceSize = referenceSizeProperty.GetVector3();
43
44     return referenceSize + mSizeOffset;
45   }
46
47   Vector3 mSizeOffset;                        ///< The amount to offset the size from referenceSize
48 };
49
50 struct CameraActorPositionConstraint
51 {
52   CameraActorPositionConstraint(const Vector2& stageSize, float defaultCameraDistance = 0.0f)
53   : mStageSize(stageSize),
54     mDefaultCameraDistance(defaultCameraDistance)
55   {
56   }
57
58   Vector3 operator()(const Vector3& current,
59                      const PropertyInput& sourcePositionProperty)
60   {
61     const Vector3& sourcePosition = sourcePositionProperty.GetVector3();
62
63     return Vector3( sourcePosition.x + mStageSize.x * 0.5f,
64                     sourcePosition.y + mStageSize.y * 0.5f,
65                     sourcePosition.z + mDefaultCameraDistance);
66   }
67
68   Vector2 mStageSize;
69   float mDefaultCameraDistance;
70
71 };
72
73 struct RenderTaskViewportPositionConstraint
74 {
75   RenderTaskViewportPositionConstraint(const Vector2& stageSize)
76   : mStageSize(stageSize)
77   {
78   }
79
80   Vector2 operator()(const Vector2& current,
81                      const PropertyInput& positionProperty,
82                      const PropertyInput& magnifierSizeProperty,
83                      const PropertyInput& magnifierScaleProperty)
84   {
85     Vector2 position(positionProperty.GetVector3()); // World position?
86
87     //position -= mStageSize * 0.5f;
88
89     // should be updated when:
90     // Magnifier's world position/size/scale/parentorigin/anchorpoint changes.
91     // or Magnifier camera's world position changes.
92     Vector3 size = magnifierSizeProperty.GetVector3() * magnifierScaleProperty.GetVector3();
93
94     // Reposition, and resize viewport to reflect the world bounds of this Magnifier actor.
95     position.x += (mStageSize.width - size.width) * 0.5f;
96     position.y += (mStageSize.height - size.height) * 0.5f;
97
98     return position;
99   }
100
101   Vector2 mStageSize;
102 };
103
104 struct RenderTaskViewportSizeConstraint
105 {
106   RenderTaskViewportSizeConstraint()
107   {
108   }
109
110   Vector2 operator()(const Vector2& current,
111                      const PropertyInput& magnifierSizeProperty,
112                      const PropertyInput& magnifierScaleProperty)
113   {
114     return Vector2(magnifierSizeProperty.GetVector3() * magnifierScaleProperty.GetVector3());
115   }
116 };
117
118 /**
119  * Returns relative border (0.0f...1.0f x 0.0f...1.0f)
120  * from an absolute pixel specified border.
121  * @param[in] absolute A border using absolute pixel coordinates
122  * @param[in] width The width of the texture
123  * @param[in] height The height of the texture.
124  * @return A border relative to the size of the Image texture dimensions.
125  */
126 Vector4 GetRelativeBorder(Vector4 absolute, float width, float height)
127 {
128   return Vector4( absolute.x / width,
129                   absolute.y / height,
130                   absolute.z / width,
131                   absolute.w / height);
132 }
133
134 }
135
136 namespace Dali
137 {
138
139 namespace Toolkit
140 {
141
142 namespace Internal
143 {
144
145 ///////////////////////////////////////////////////////////////////////////////////////////////////
146 // Magnifier
147 ///////////////////////////////////////////////////////////////////////////////////////////////////
148
149 Dali::Toolkit::Magnifier Magnifier::New()
150 {
151   // Create the implementation
152   MagnifierPtr magnifier(new Magnifier());
153
154   // Pass ownership to CustomActor via derived handle
155   Dali::Toolkit::Magnifier handle(*magnifier);
156
157   // Second-phase init of the implementation
158   // This can only be done after the CustomActor connection has been made...
159   magnifier->Initialize();
160
161   return handle;
162 }
163
164 Magnifier::Magnifier()
165 : ControlImpl(true),
166   mPropertySourcePosition(Property::INVALID_INDEX),
167   mActorSize(Vector3::ZERO),
168   mMagnificationFactor(1.0f)
169 {
170 }
171
172 void Magnifier::SetSourceActor(Actor actor)
173 {
174   mTask.SetSourceActor( actor );
175 }
176
177 void Magnifier::SetSourcePosition(const Vector3& position)
178 {
179   Self().SetProperty(mPropertySourcePosition, position);
180 }
181
182 void Magnifier::Initialize()
183 {
184   Actor self = Self();
185   mPropertySourcePosition = self.RegisterProperty( Toolkit::Magnifier::SOURCE_POSITION_PROPERTY_NAME, Vector3::ZERO );
186   Vector2 stageSize(Stage::GetCurrent().GetSize());
187
188   Layer dummyLayer = Layer::New();
189   Stage().GetCurrent().Add(dummyLayer);
190   dummyLayer.SetParentOrigin(ParentOrigin::CENTER);
191
192   // NOTE:
193   // sourceActor is a dummy delegate actor that takes the source property position,
194   // and generates a WORLD_POSITION, which is 1 frame behind the source property.
195   // This way the constraints for determining the camera position (source) and those
196   // for determining viewport position use the same 1 frame old values.
197   // A simple i) CameraPos = f(B), ii) B = f(A) set of constraints wont suffice as
198   // although CameraPos will use B, which is A's previous value. The constraint will
199   // not realise that B is still dirty as far as constraint (i) is concerned.
200   // Perhaps this is a bug in the way the constraint system factors into what is dirty
201   // and what is not.
202   mSourceActor = Actor::New();
203   dummyLayer.Add(mSourceActor);
204   mSourceActor.SetParentOrigin(ParentOrigin::CENTER);
205   Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
206                                                     Source( self, mPropertySourcePosition ),
207                                                     EqualToConstraint() );
208   mSourceActor.ApplyConstraint(constraint);
209
210   // create the render task this will render content on top of everything
211   // based on camera source position.
212   InitializeRenderTask();
213
214   // set up some constraints to:
215   // i) reposition (dest) frame actor based on magnifier actor's world position (this is 1 frame delayed)
216   // ii) reposition and resize (dest) the render task's viewport based on magnifier actor's world position (1 frame delayed) & size.
217   // iii) reposition (source) camera actor based on magnifier source actor's world position (this is 1 frame delayed)
218
219   // Apply constraint to camera's position
220   // Position our camera at the same distance from its target as the default camera is.
221   // The camera position doesn't affect how we render, just what we render (due to near and far clip planes)
222   // NOTE: We can't interrogate the default camera's position as it is not known initially (takes 1 frame
223   // for value to update).
224   // But we can determine the initial position using the same formula:
225   // distance = stage.height * 0.5 / tan(FOV * 0.5)
226
227   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
228   RenderTask renderTask = taskList.GetTask(0u);
229   float fov = renderTask.GetCameraActor().GetFieldOfView();
230   mDefaultCameraDistance = (stageSize.height * 0.5f) / tanf(fov * 0.5f);
231
232   // Use a 1 frame delayed source position to determine the camera actor's position.
233   // This is necessary as the viewport is determined by the Magnifier's Actor's World position (which is computed
234   // at the end of the update cycle i.e. after constraints have been applied.)
235   //Property::Index propertySourcePositionDelayed = mCameraActor.RegisterProperty("delayed-source-position", Vector3::ZERO);
236
237   constraint = Constraint::New<Vector3>( Actor::POSITION,
238                                                     Source( mSourceActor, Actor::WORLD_POSITION ),
239                                                     CameraActorPositionConstraint(stageSize, mDefaultCameraDistance) );
240   mCameraActor.ApplyConstraint(constraint);
241
242   // Apply constraint to render-task viewport position
243   constraint = Constraint::New<Vector2>( RenderTask::VIEWPORT_POSITION,
244                                          Source( self, Actor::WORLD_POSITION ),//mPropertySourcePosition ),
245                                          Source( self, Actor::SIZE ),
246                                          Source( self, Actor::WORLD_SCALE),
247                                          RenderTaskViewportPositionConstraint(stageSize) );
248   mTask.ApplyConstraint(constraint);
249
250   // Apply constraint to render-task viewport position
251   constraint = Constraint::New<Vector2>( RenderTask::VIEWPORT_SIZE,
252                                          Source( self, Actor::SIZE ),
253                                          Source( self, Actor::WORLD_SCALE),
254                                          RenderTaskViewportSizeConstraint() );
255   mTask.ApplyConstraint(constraint);
256 }
257
258 Magnifier::~Magnifier()
259 {
260
261 }
262
263 void Magnifier::InitializeRenderTask()
264 {
265   Stage stage = Stage::GetCurrent();
266
267   RenderTaskList taskList = stage.GetRenderTaskList();
268
269   mTask = taskList.CreateTask();
270   mTask.SetInputEnabled(false);
271   mTask.SetClearColor(Vector4(0.5f, 0.5f, 0.5f, 1.0f));
272   mTask.SetClearEnabled(true);
273
274   mCameraActor = CameraActor::New();
275   mCameraActor.SetType(Camera::FREE_LOOK);
276   mCameraActor.SetRotation(Quaternion(M_PI, Vector3::YAXIS)); // Look at stage
277
278   stage.Add(mCameraActor);
279   mTask.SetCameraActor( mCameraActor );
280
281   SetFrameVisibility(true);
282 }
283
284 bool Magnifier::GetFrameVisibility() const
285 {
286   return mFrameLayer;
287 }
288
289 void Magnifier::SetFrameVisibility(bool visible)
290 {
291   if(visible && !mFrameLayer)
292   {
293     Actor self(Self());
294
295     Layer mFrameLayer = Layer::New();
296     mFrameLayer.SetParentOrigin( ParentOrigin::CENTER );
297     Stage::GetCurrent().Add(mFrameLayer);
298
299     Image image = Image::New( DEFAULT_FRAME_IMAGE_PATH );
300     ImageActor frame = ImageActor::New( image );
301     frame.SetDrawMode(DrawMode::OVERLAY);
302     frame.SetStyle( ImageActor::STYLE_NINE_PATCH );
303
304     frame.SetNinePatchBorder( Vector4::ONE * IMAGE_BORDER_INDENT );
305     mFrameLayer.Add(frame);
306
307     // Apply position constraint to the frame
308     Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
309                                                       Source( self, Actor::WORLD_POSITION ),
310                                                       EqualToConstraint() );
311     frame.ApplyConstraint(constraint);
312
313     // Apply scale constraint to the frame
314     constraint = Constraint::New<Vector3>( Actor::SCALE,
315                                            Source( self, Actor::SCALE ),
316                                            EqualToConstraint() );
317     frame.ApplyConstraint(constraint);
318
319     Source(self, Actor::SCALE),
320
321     // Apply size constraint to the the frame
322     constraint = Constraint::New<Vector3>(Actor::SIZE,
323                                           Source(self, Actor::SIZE),
324                                           ImageBorderSizeConstraint());
325     frame.ApplyConstraint(constraint);
326   }
327   else if(!visible && mFrameLayer)
328   {
329     Stage::GetCurrent().Remove(mFrameLayer);
330     mFrameLayer.Reset();
331   }
332 }
333
334 void Magnifier::OnControlSizeSet(const Vector3& targetSize)
335 {
336   // TODO: Once Camera/CameraActor properties function as proper animatable properties
337   // this code can disappear.
338   // whenever the size of the magnifier changes, the field of view needs to change
339   // to compensate for the new size of the viewport. this cannot be done within
340   // a constraint yet as Camera/CameraActor properties are not animatable/constrainable.
341   mActorSize = targetSize;
342   Update();
343 }
344
345 float Magnifier::GetMagnificationFactor() const
346 {
347   return mMagnificationFactor;
348 }
349
350 void Magnifier::SetMagnificationFactor(float value)
351 {
352   mMagnificationFactor = value;
353   Update();
354 }
355
356 void Magnifier::Update()
357 {
358   // TODO: Make Camera settings (fieldofview/aspectratio) as animatable constraints.
359
360   // should be updated when:
361   // Magnifier's world size/scale changes.
362   Actor self(Self());
363   Vector3 worldSize = mActorSize * self.GetCurrentWorldScale();
364
365   // Adjust field of view to scale content
366
367   // size.height / 2
368   // |------/
369   // |d    /
370   // |i   /
371   // |s  /
372   // |t /
373   // |./
374   // |/ <--- fov/2 radians.
375   //
376   const float fov = atanf( 0.5f * worldSize.height / mDefaultCameraDistance / mMagnificationFactor) * 2.0f;
377   mCameraActor.SetFieldOfView( fov );
378
379   // Adjust aspect ratio to compensate for rectangular viewports.
380   mCameraActor.SetAspectRatio( worldSize.width / worldSize.height );
381 }
382
383 } // namespace Internal
384
385 } // namespace Toolkit
386
387 } // namespace Dali