DALi Version 2.1.20
[platform/core/uifw/dali-demo.git] / examples / camera-test / camera-test-example.cpp
1 #include <dali-toolkit/dali-toolkit.h>
2 #include <dali-toolkit/devel-api/controls/table-view/table-view.h>
3 #include <string>
4
5 using namespace Dali;
6 using namespace Dali::Toolkit;
7
8 namespace
9 {
10 const char* DEMO_THEME_TWO_PATH(DEMO_STYLE_DIR "style-example-theme-two.json");
11
12 const std::string images[5] =
13   {
14     DEMO_IMAGE_DIR "application-icon-97.png",
15     DEMO_IMAGE_DIR "application-icon-84.png",
16     DEMO_IMAGE_DIR "application-icon-76.png",
17     DEMO_IMAGE_DIR "application-icon-69.png",
18     DEMO_IMAGE_DIR "application-icon-72.png",
19 };
20
21 const char* BORDER_IMAGE(DEMO_IMAGE_DIR "border-4px.9.png");
22 const char* RESIZE_HANDLE_IMAGE(DEMO_IMAGE_DIR "resize-handle.png");
23 const char* CIRCLE_POINT(DEMO_IMAGE_DIR "circle_point.png");
24 const char* CIRCLE_STROKE(DEMO_IMAGE_DIR "circle_stroke_point.png");
25
26 const int BORDER_WIDTH(4);
27
28 } // namespace
29
30 struct CameraPosConstraint
31 {
32   CameraPosConstraint() = default;
33
34   void operator()(Vector3& current, const PropertyInputContainer& inputs)
35   {
36     auto& newPos = inputs[0]->GetVector3();
37     current.x    = newPos.x;
38     current.y    = newPos.y;
39   }
40 };
41
42 struct BoundaryConstraint
43 {
44   BoundaryConstraint(std::string name, Vector2 size, bool centered)
45   : name(name),
46     boundarySize(size),
47     centered(centered)
48   {
49   }
50   void operator()(Vector3& current, const PropertyInputContainer& inputs)
51   {
52     Vector3 curPos  = inputs[0]->GetVector3();
53     Vector3 curSize = inputs[1]->GetVector3();
54
55     if(centered)
56     {
57       // AnchorPoint is center of actor
58       current.x = std::clamp(curPos.x, 0.0f, boundarySize.x);
59       current.y = std::clamp(curPos.y, 0.0f, boundarySize.y);
60     }
61     else
62     {
63       // Anchor point is top left of actor.
64       current.x = std::clamp(curPos.x, 0.0f, boundarySize.x - curSize.x);
65       current.y = std::clamp(curPos.y, 0.0f, boundarySize.y - curSize.y);
66     }
67   }
68
69   std::string name;
70   Vector2     boundarySize;
71   bool        centered;
72 };
73
74 struct ViewportPositionConstraint
75 {
76   ViewportPositionConstraint(Vector2 windowOrigin)
77   : origin(windowOrigin)
78   {
79   }
80   void operator()(Vector2& current, const PropertyInputContainer& inputs)
81   {
82     Vector3 framePos = inputs[0]->GetVector3();
83     current.x        = framePos.x + origin.x;
84     current.y        = framePos.y + origin.y;
85   }
86   Vector2 origin;
87 };
88
89 struct ViewportSizeConstraint
90 {
91   ViewportSizeConstraint() = default;
92
93   void operator()(Vector2& current, const PropertyInputContainer& inputs)
94   {
95     Vector3 frameSize = inputs[0]->GetVector3();
96     current.x         = frameSize.x;
97     current.y         = frameSize.y;
98   }
99 };
100
101 class CameraTestExample : public ConnectionTracker
102 {
103 public:
104   CameraTestExample(Application app)
105   : mApp(app)
106   {
107     mApp.InitSignal().Connect(this, &CameraTestExample::OnCreate);
108   }
109
110   void OnCreate(Application& app)
111   {
112     // Use default camera.
113     Window  window = app.GetWindow();
114     Vector2 windowSize(1280, 800);
115     if(window.GetSize().GetWidth() < 1280)
116     {
117       window.SetSize(Uint16Pair(windowSize.x, windowSize.y)); // 1280 divides into 427, 427, 426
118     }
119     else
120     {
121       windowSize.x = window.GetSize().GetWidth();
122       windowSize.y = window.GetSize().GetHeight();
123     }
124
125     window.KeyEventSignal().Connect(this, &CameraTestExample::OnKeyEvent);
126
127     // Divide the screen up into 3 regions:
128     // left: the scene + camera outline
129     // mid: the viewport
130     // right: actor / camera controls
131
132     // Viewport frame position is constrained to the mid third, but is actually drawn into full screen overlay.
133     // Camera frame position is constrained to the left third, but is actually drawn into full screen overlay.
134
135     Vector2 sceneSize = Vector2(ceilf(windowSize.x / 3.0f), 720);
136     Vector2 panelSize = Vector2(ceilf(windowSize.x / 3.0f), windowSize.y);
137
138     viewLayer = CreateScene(window, Vector2::ZERO, sceneSize);
139
140     sceneRenderTask = CreateSceneRenderTask(window, viewLayer, sceneSize);
141
142     Layer overlayLayer = Layer::New(); // Will be drawn last by separate render tasks
143     window.Add(overlayLayer);
144     overlayLayer.SetProperty(Actor::Property::POSITION, Vector3::ZERO);
145     overlayLayer.SetProperty(Actor::Property::SIZE, windowSize);
146     overlayLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
147     overlayLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
148
149     overlayRenderTask = CreateOverlayRenderTask(window, windowSize, overlayLayer);
150
151     // Create camera frame
152     initialCameraSize     = Vector3(windowSize.x / 3.0f, windowSize.y, 1);
153     initialCameraPosition = Vector3(windowSize.x / 6.0f, windowSize.y * 0.5f, 0);
154
155     cameraFrame = CreateFrame(Vector2(initialCameraSize), sceneSize, "Camera");
156     cameraFrame.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
157     cameraFrame.SetProperty(Actor::Property::POSITION, initialCameraPosition);
158
159     cameraGrabHandle = CreateCornerHandle(cameraFrame);
160     cameraGrabCenter = CreateCenterHandle(cameraFrame);
161
162     // Create viewport frame
163     initialViewportSize     = sceneSize * 0.75f; // Maintain aspect ratio
164     initialViewportPosition = Vector3(100, 100, 0);
165
166     viewportFrame = CreateFrame(Vector2(initialViewportPosition), Vector2(initialViewportSize), "Viewport");
167     viewportFrame.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0f / 3.0f, 0.0f, 0.5f)); // TL of 2nd third of screen
168     viewportFrame.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
169
170     viewportGrabHandle = CreateCornerHandle(viewportFrame);
171     viewportGrabCenter = CreateCenterHandle(viewportFrame);
172
173     Vector2 viewportOrigin(windowSize.x / 3.0f, 0.0f); // Viewport origin in window coords (to match frame)
174     ConstrainSceneViewportCamera(sceneRenderTask, viewportOrigin);
175
176     Constraint constraint = Constraint::New<Vector3>(cameraFrame, Actor::Property::POSITION, BoundaryConstraint("cameraFrame", panelSize, true));
177     constraint.AddSource(LocalSource(Actor::Property::POSITION));
178     constraint.AddSource(LocalSource(Actor::Property::SIZE));
179     constraint.Apply();
180
181     constraint = Constraint::New<Vector3>(viewportFrame, Actor::Property::POSITION, BoundaryConstraint("viewportFrame", panelSize, false));
182     constraint.AddSource(LocalSource(Actor::Property::POSITION));
183     constraint.AddSource(LocalSource(Actor::Property::SIZE));
184     constraint.Apply();
185
186     overlayLayer.Add(viewportFrame);
187     overlayLayer.Add(cameraFrame);
188
189     CreateActorControls(overlayLayer, panelSize);
190
191     mPanGestureDetector = PanGestureDetector::New();
192     mPanGestureDetector.Attach(viewportGrabHandle);
193     mPanGestureDetector.Attach(viewportGrabCenter);
194     mPanGestureDetector.Attach(cameraGrabHandle);
195     mPanGestureDetector.Attach(cameraGrabCenter);
196     mPanGestureDetector.DetectedSignal().Connect(this, &CameraTestExample::OnPan);
197
198     mTapGestureDetector = TapGestureDetector::New(2);
199     mTapGestureDetector.Attach(viewportGrabHandle);
200     mTapGestureDetector.Attach(viewportGrabCenter);
201     mTapGestureDetector.Attach(cameraGrabHandle);
202     mTapGestureDetector.Attach(cameraGrabCenter);
203     mTapGestureDetector.DetectedSignal().Connect(this, &CameraTestExample::OnDoubleTap);
204   }
205
206   Layer CreateScene(Window window, Vector2 position, Vector2 size)
207   {
208     const Vector3 offsets[] =
209       {
210         Dali::ParentOrigin::TOP_LEFT,
211         Dali::ParentOrigin::TOP_RIGHT,
212         Dali::ParentOrigin::BOTTOM_LEFT,
213         Dali::ParentOrigin::BOTTOM_RIGHT,
214         Dali::ParentOrigin::CENTER,
215       };
216
217     Layer viewLayer = Layer::New();
218     window.Add(viewLayer);
219
220     viewLayer.SetProperty(Actor::Property::POSITION, Vector3(position));
221     viewLayer.SetProperty(Actor::Property::SIZE, size);
222     viewLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT);
223     viewLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT);
224
225     auto bg = Control::New();
226     bg.SetBackgroundColor(Vector4(0.1, 0.0, 0.1, 0.5));
227     bg.SetProperty(Actor::Property::SIZE, size);
228     bg.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
229     bg.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
230     viewLayer.Add(bg);
231
232     auto label                                       = TextLabel::New("Scene");
233     label[TextLabel::Property::POINT_SIZE]           = 12;
234     label[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER;
235     label[TextLabel::Property::TEXT_COLOR]           = Color::WHITE;
236     label[Actor::Property::PARENT_ORIGIN]            = ParentOrigin::TOP_CENTER;
237     label[Actor::Property::ANCHOR_POINT]             = AnchorPoint::TOP_CENTER;
238     viewLayer.Add(label);
239
240     int i = 0;
241     for(auto& image : images)
242     {
243       auto imageView = ImageView::New(image);
244       imageViews.push_back(imageView);
245       viewLayer.Add(imageView);
246
247       printf("ActorId: %d\n", imageView.GetProperty<int>(Actor::Property::ID));
248
249       imageView.SetProperty(Actor::Property::PARENT_ORIGIN, offsets[i]);
250       imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
251       imageView.SetProperty(Actor::Property::POSITION, Vector3((0.5f - offsets[i].x) * 50.0f, (0.5f - offsets[i].y) * 50.0f, 0.0f));
252       imageView.SetProperty(Actor::Property::SIZE, Vector2(97.0f, 97.0f));
253       ++i;
254     }
255     return viewLayer;
256   }
257
258   void CreateActorControls(Layer parent, Vector2 sceneSize)
259   {
260     // Create a container that sits on the rightmost third of the window
261     Actor layoutContainer                           = Actor::New();
262     layoutContainer[Actor::Property::SIZE]          = Vector3(sceneSize.x, sceneSize.y, sceneSize.x);
263     layoutContainer[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_RIGHT;
264     layoutContainer[Actor::Property::ANCHOR_POINT]  = AnchorPoint::TOP_RIGHT;
265
266     auto bg = Control::New();
267     bg.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
268     bg[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
269     bg.SetBackgroundColor(Vector4(0.05f, 0.05f, 0.1f, 1.0f));
270     layoutContainer.Add(bg);
271
272     parent.Add(layoutContainer);
273
274     // Add a table for actor rotations
275     TableView actorProps = TableView::New(7, 2);
276     actorProps.SetProperty(Actor::Property::NAME, "ActorSliderLayout");
277     actorProps.SetProperty(Actor::Property::SIZE, Vector3(sceneSize.x, sceneSize.y, sceneSize.x));
278     actorProps.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
279     actorProps.SetFitWidth(0);
280     actorProps.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT);
281
282     int i = 0;
283     for(auto& image : images)
284     {
285       actorProps.SetFitHeight(i);
286
287       auto icon = ImageView::New(image);
288       icon.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
289       // I would like 50% of natural size...
290       icon.SetProperty(Actor::Property::SIZE, Vector3(50, 50, 50));
291       actorProps.AddChild(icon, TableView::CellPosition(i, 0));
292       actorProps.SetCellAlignment(TableView::CellPosition(i, 0), HorizontalAlignment::CENTER, VerticalAlignment::CENTER);
293       auto               slider = Slider::New();
294       std::ostringstream sliderStyleName;
295       sliderStyleName << "RotationSlider" << i + 1;
296       slider.SetProperty(Actor::Property::NAME, sliderStyleName.str());
297       slider.SetStyleName("ThinSlider");
298       slider.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
299       slider.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
300       slider.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
301       slider.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT);
302       slider.SetProperty(Slider::Property::LOWER_BOUND, -180.0f);
303       slider.SetProperty(Slider::Property::UPPER_BOUND, 180.0f);
304       slider.SetProperty(Slider::Property::VALUE_PRECISION, 0);
305       slider.SetProperty(Slider::Property::VALUE, 0.0f);
306       slider.SetProperty(Slider::Property::SHOW_POPUP, true);
307       slider.RegisterProperty("actorId", i, Property::READ_ONLY); // imageViews[i].GetId()
308
309       actorProps.AddChild(slider, TableView::CellPosition(i, 1));
310       actorProps.SetCellAlignment(TableView::CellPosition(i, 1), HorizontalAlignment::RIGHT, VerticalAlignment::CENTER);
311       slider.ValueChangedSignal().Connect(this, &CameraTestExample::OnRotationSliderChanged);
312       i++;
313     }
314
315     auto fovLabel = TextLabel::New("FOV");
316     fovLabel.SetProperty(TextLabel::Property::POINT_SIZE, 12);
317     fovLabel.SetProperty(TextLabel::Property::TEXT_COLOR, Color::WHITE);
318     fovLabel[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER;
319     fovLabel[Actor::Property::PARENT_ORIGIN]            = ParentOrigin::CENTER;
320     fovLabel[Actor::Property::ANCHOR_POINT]             = AnchorPoint::CENTER;
321     actorProps.AddChild(fovLabel, TableView::CellPosition(i, 0));
322
323     auto slider = Slider::New();
324     slider.SetProperty(Actor::Property::NAME, "FOVSlider");
325     slider.SetStyleName("ThinSlider");
326     slider.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
327     slider.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
328     slider.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
329     slider.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT);
330     slider.SetProperty(Slider::Property::LOWER_BOUND, 1.0f);
331     slider.SetProperty(Slider::Property::UPPER_BOUND, 160.0f);
332     slider.SetProperty(Slider::Property::VALUE_PRECISION, 0);
333     slider.SetProperty(Slider::Property::VALUE, Degree(Radian(cameraActor.GetFieldOfView())).degree);
334     slider.SetProperty(Slider::Property::SHOW_POPUP, true);
335     slider.ValueChangedSignal().Connect(this, &CameraTestExample::OnFOVChanged);
336     actorProps.AddChild(slider, TableView::CellPosition(i, 1));
337
338     layoutContainer.Add(actorProps);
339
340     cameraDetail                                            = TextLabel::New();
341     cameraDetail[TextLabel::Property::POINT_SIZE]           = 10;
342     cameraDetail[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER;
343     cameraDetail[TextLabel::Property::MULTI_LINE]           = true;
344     cameraDetail[TextLabel::Property::TEXT_COLOR]           = Color::WHITE;
345     cameraDetail[Actor::Property::PARENT_ORIGIN]            = ParentOrigin::BOTTOM_CENTER;
346     cameraDetail[Actor::Property::ANCHOR_POINT]             = AnchorPoint::BOTTOM_CENTER;
347
348     cameraDetail[Actor::Property::POSITION] = Vector3(0.0f, -15.0f, 0.0f);
349     cameraDetail.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH);
350     cameraDetail.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT);
351     layoutContainer.Add(cameraDetail);
352
353     SetCameraDetailString();
354   }
355
356   RenderTask CreateSceneRenderTask(Window window, Layer source, Vector2 sceneSize)
357   {
358     // Create a render task with moveable viewport and camera
359     RenderTask renderTask = window.GetRenderTaskList().CreateTask();
360
361     cameraActor = CameraActor::New();
362     cameraActor.SetType(Camera::FREE_LOOK);
363     cameraActor.SetPerspectiveProjection(sceneSize);
364     window.Add(cameraActor);
365
366     renderTask.SetCameraActor(cameraActor);
367     renderTask.SetInputEnabled(false);
368     renderTask.SetClearColor(Vector4(0.05f, 0.05f, 0.05f, 1.0f));
369     renderTask.SetClearEnabled(true);
370     renderTask.SetSourceActor(source);
371
372     return renderTask;
373   }
374
375   void ConstrainSceneViewportCamera(RenderTask sceneRenderTask, Vector2 viewportOrigin)
376   {
377     Constraint constraint = Constraint::New<Vector3>(cameraActor, Actor::Property::POSITION, CameraPosConstraint());
378     constraint.AddSource(Source(cameraFrame, Actor::Property::POSITION));
379     constraint.Apply();
380
381     constraint = Constraint::New<Vector2>(cameraActor, Actor::Property::SIZE, EqualToConstraint());
382     constraint.AddSource(Source(cameraFrame, Actor::Property::SIZE));
383     constraint.Apply();
384
385     constraint = Constraint::New<Vector2>(sceneRenderTask, RenderTask::Property::VIEWPORT_POSITION, ViewportPositionConstraint(viewportOrigin));
386     constraint.AddSource(Source(viewportFrame, Actor::Property::POSITION));
387     constraint.Apply();
388
389     constraint = Constraint::New<Vector2>(sceneRenderTask, RenderTask::Property::VIEWPORT_SIZE, ViewportSizeConstraint());
390     constraint.AddSource(Source(viewportFrame, Actor::Property::SIZE));
391     constraint.Apply();
392   }
393
394   RenderTask CreateOverlayRenderTask(Window window, Vector2 windowSize, Layer source)
395   {
396     // Create a separate camera / render task to visualize the input frames above the 2nd rendered layer above.
397     CameraActor overlayCameraActor = CameraActor::New();
398     overlayCameraActor.SetType(Camera::FREE_LOOK);
399     overlayCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
400     overlayCameraActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
401     overlayCameraActor.SetProperty(Actor::Property::POSITION, Vector2::ZERO);
402     overlayCameraActor.SetProperty(Actor::Property::SIZE, windowSize);
403     overlayCameraActor.SetPerspectiveProjection(windowSize);
404     window.Add(overlayCameraActor);
405
406     RenderTask overlayRenderTask = window.GetRenderTaskList().CreateTask();
407
408     overlayRenderTask.SetCameraActor(overlayCameraActor);
409     overlayRenderTask.SetInputEnabled(true);
410     overlayRenderTask.SetClearEnabled(false);
411     overlayRenderTask.SetSourceActor(source);
412     overlayRenderTask.SetExclusive(true);
413
414     overlayRenderTask.SetViewportPosition(Vector2(0, 0));
415     overlayRenderTask.SetViewportSize(windowSize);
416
417     overlayRenderTask.SetCullMode(false);
418
419     return overlayRenderTask;
420   }
421
422   Actor CreateFrame(Vector2 position, Vector2 size, std::string label)
423   {
424     Actor frame = Toolkit::ImageView::New(BORDER_IMAGE);
425     frame.SetProperty(Dali::Actor::Property::NAME, "ContentFrame");
426     frame.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
427     frame.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
428     frame.SetProperty(Actor::Property::SIZE, size);
429     frame.SetProperty(Actor::Property::POSITION, position);
430
431     auto frameLabel                                       = TextLabel::New(label);
432     frameLabel[TextLabel::Property::POINT_SIZE]           = 12;
433     frameLabel[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER;
434     frameLabel[TextLabel::Property::TEXT_COLOR]           = Color::YELLOW;
435     frameLabel[Actor::Property::PARENT_ORIGIN]            = ParentOrigin::BOTTOM_CENTER;
436     frameLabel[Actor::Property::ANCHOR_POINT]             = AnchorPoint::BOTTOM_CENTER;
437     frameLabel[Actor::Property::POSITION]                 = Vector3(0.0f, 15.0f, 0.0f);
438     frame.Add(frameLabel);
439
440     return frame;
441   }
442
443   Actor CreateCornerHandle(Actor parent)
444   {
445     Actor cornerHandle = Toolkit::ImageView::New(RESIZE_HANDLE_IMAGE);
446     cornerHandle.SetProperty(Dali::Actor::Property::NAME, "GrabHandle");
447     cornerHandle.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
448     cornerHandle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_RIGHT);
449     cornerHandle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_RIGHT);
450     cornerHandle.SetProperty(Actor::Property::POSITION, Vector2(-BORDER_WIDTH, -BORDER_WIDTH));
451     cornerHandle.SetProperty(Actor::Property::OPACITY, 0.6f);
452     parent.Add(cornerHandle);
453     return cornerHandle;
454   }
455
456   Actor CreateCenterHandle(Actor parent)
457   {
458     Actor grabCenter = Toolkit::ImageView::New(CIRCLE_STROKE);
459     grabCenter.SetProperty(Dali::Actor::Property::NAME, "GrabCenter");
460     grabCenter.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
461     grabCenter.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
462     grabCenter.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
463     Toolkit::ImageView grabCenter2 = Toolkit::ImageView::New(CIRCLE_POINT);
464     grabCenter2.SetProperty(Dali::Actor::Property::NAME, "GrabCenter2");
465     grabCenter2.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
466     grabCenter2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
467     grabCenter2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
468     grabCenter.Add(grabCenter2);
469     grabCenter.SetProperty(Actor::Property::OPACITY, 0.6f);
470     parent.Add(grabCenter);
471     return grabCenter;
472   }
473
474   void SetCameraDetailString()
475   {
476     std::ostringstream oss;
477
478     auto pos  = cameraActor.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
479     auto size = cameraFrame.GetTargetSize();
480
481     oss << "Camera Detail: Pos: (" << pos.x << ", " << pos.y << ")" << std::endl;
482     oss << "  Frame size: (" << size.x << ", " << size.y << ")" << std::endl;
483
484     // Really, just need a box that represents the screen plane at z=0 from MVP.
485
486     cameraDetail.SetProperty(TextLabel::Property::TEXT, oss.str());
487   }
488
489   void OnPan(Actor actor, const PanGesture& gesture)
490   {
491     if(actor == viewportGrabHandle)
492     {
493       auto size    = viewportFrame.GetTargetSize();
494       auto newSize = Vector2(size.GetVectorXY() + gesture.GetDisplacement() * 2.0f);
495       viewportFrame.SetProperty(Actor::Property::SIZE, newSize);
496     }
497     else if(actor == viewportGrabCenter)
498     {
499       Vector3 pos;
500       if(gesture.GetState() == GestureState::FINISHED)
501       {
502         pos = viewportFrame.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
503       }
504       else
505       {
506         pos = viewportFrame.GetProperty<Vector3>(Actor::Property::POSITION);
507       }
508       pos = Vector2(pos.GetVectorXY() + gesture.GetDisplacement());
509       viewportFrame.SetProperty(Actor::Property::POSITION, pos);
510     }
511     else if(actor == cameraGrabHandle)
512     {
513       auto size    = cameraFrame.GetTargetSize();
514       auto newSize = Vector2(size.GetVectorXY() + gesture.GetDisplacement() * 2.0f);
515       cameraFrame.SetProperty(Actor::Property::SIZE, newSize);
516       cameraActor.SetPerspectiveProjection(newSize);
517     }
518     else if(actor == cameraGrabCenter)
519     {
520       Vector3 pos;
521       if(gesture.GetState() == GestureState::FINISHED)
522       {
523         pos = cameraFrame.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
524       }
525       else
526       {
527         pos = cameraFrame.GetProperty<Vector3>(Actor::Property::POSITION);
528       }
529       pos = Vector2(pos.GetVectorXY() + gesture.GetDisplacement());
530       cameraFrame.SetProperty(Actor::Property::POSITION, pos);
531     }
532
533     SetCameraDetailString();
534   }
535
536   void OnDoubleTap(Actor actor, const TapGesture& gesture)
537   {
538     if(actor == viewportGrabHandle)
539     {
540       viewportFrame.SetProperty(Actor::Property::SIZE, initialViewportSize);
541     }
542     else if(actor == viewportGrabCenter)
543     {
544       viewportFrame.SetProperty(Actor::Property::POSITION, initialViewportPosition);
545     }
546     else if(actor == cameraGrabHandle)
547     {
548       cameraFrame.SetProperty(Actor::Property::SIZE, initialCameraSize);
549       cameraActor.SetProperty(Actor::Property::SIZE, initialCameraSize);
550       cameraActor.SetPerspectiveProjection(Vector2(initialCameraSize));
551     }
552     else if(actor == cameraGrabCenter)
553     {
554       cameraFrame.SetProperty(Actor::Property::POSITION, initialCameraPosition);
555     }
556   }
557
558   bool OnFOVChanged(Slider slider, float value)
559   {
560     cameraActor.SetProperty(CameraActor::Property::FIELD_OF_VIEW, (float)Radian(Degree(value)));
561     return true;
562   }
563
564   bool OnRotationSliderChanged(Slider slider, float value)
565   {
566     auto actorIdIndex = slider.GetPropertyIndex("actorId");
567     if(actorIdIndex != Property::INVALID_INDEX)
568     {
569       int   actorIndex = slider["actorId"];
570       float value      = slider["value"];
571       imageViews[actorIndex].SetProperty(Actor::Property::ORIENTATION, AngleAxis(Degree(value), Vector3::ZAXIS));
572     }
573     return true;
574   }
575
576   /**
577    * Main key event handler
578    */
579   void OnKeyEvent(const KeyEvent& event)
580   {
581     if(event.GetState() == KeyEvent::DOWN)
582     {
583       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
584       {
585         mApp.Quit();
586       }
587     }
588   }
589
590   RenderTask sceneRenderTask;
591   RenderTask overlayRenderTask;
592
593   PanGestureDetector mPanGestureDetector;
594   TapGestureDetector mTapGestureDetector;
595
596   Application            mApp;
597   std::vector<ImageView> imageViews;
598
599   Layer viewLayer; // The "scene"
600
601   Vector3 initialCameraPosition;
602   Vector3 initialCameraSize;
603   Vector3 initialViewportPosition;
604   Vector3 initialViewportSize;
605
606   Actor viewportFrame;
607   Actor viewportGrabCenter;
608   Actor viewportGrabHandle;
609
610   Actor cameraFrame;
611   Actor cameraGrabCenter;
612   Actor cameraGrabHandle;
613
614   CameraActor cameraActor;
615   TextLabel   cameraDetail;
616 };
617
618 int DALI_EXPORT_API main(int argc, char** argv)
619 {
620   Application       application = Application::New(&argc, &argv, DEMO_THEME_TWO_PATH);
621   CameraTestExample test(application);
622   application.MainLoop();
623   return 0;
624 }