From: David Steele Date: Tue, 15 Mar 2022 18:21:17 +0000 (+0000) Subject: Camera Test X-Git-Tag: dali_2.1.17~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F91%2F272391%2F9;p=platform%2Fcore%2Fuifw%2Fdali-demo.git Camera Test Adding an interactive test where the camera parameters and viewport can be modified. Updating to go wide & add actor rotation sliders Change-Id: I81364553ff52563f439ae5e4232314be75b985d3 --- diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index fa0f9ee..7e36ba1 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -61,6 +61,9 @@ + + + diff --git a/examples/camera-test/camera-test-example.cpp b/examples/camera-test/camera-test-example.cpp new file mode 100644 index 0000000..166d960 --- /dev/null +++ b/examples/camera-test/camera-test-example.cpp @@ -0,0 +1,624 @@ +#include +#include +#include + +using namespace Dali; +using namespace Dali::Toolkit; + +namespace +{ +const char* DEMO_THEME_TWO_PATH(DEMO_STYLE_DIR "style-example-theme-two.json"); + +const std::string images[5] = + { + DEMO_IMAGE_DIR "application-icon-97.png", + DEMO_IMAGE_DIR "application-icon-84.png", + DEMO_IMAGE_DIR "application-icon-76.png", + DEMO_IMAGE_DIR "application-icon-69.png", + DEMO_IMAGE_DIR "application-icon-72.png", +}; + +const char* BORDER_IMAGE(DEMO_IMAGE_DIR "border-4px.9.png"); +const char* RESIZE_HANDLE_IMAGE(DEMO_IMAGE_DIR "resize-handle.png"); +const char* CIRCLE_POINT(DEMO_IMAGE_DIR "circle_point.png"); +const char* CIRCLE_STROKE(DEMO_IMAGE_DIR "circle_stroke_point.png"); + +const int BORDER_WIDTH(4); + +} // namespace + +struct CameraPosConstraint +{ + CameraPosConstraint() = default; + + void operator()(Vector3& current, const PropertyInputContainer& inputs) + { + auto& newPos = inputs[0]->GetVector3(); + current.x = newPos.x; + current.y = newPos.y; + } +}; + +struct BoundaryConstraint +{ + BoundaryConstraint(std::string name, Vector2 size, bool centered) + : name(name), + boundarySize(size), + centered(centered) + { + } + void operator()(Vector3& current, const PropertyInputContainer& inputs) + { + Vector3 curPos = inputs[0]->GetVector3(); + Vector3 curSize = inputs[1]->GetVector3(); + + if(centered) + { + // AnchorPoint is center of actor + current.x = std::clamp(curPos.x, 0.0f, boundarySize.x); + current.y = std::clamp(curPos.y, 0.0f, boundarySize.y); + } + else + { + // Anchor point is top left of actor. + current.x = std::clamp(curPos.x, 0.0f, boundarySize.x - curSize.x); + current.y = std::clamp(curPos.y, 0.0f, boundarySize.y - curSize.y); + } + } + + std::string name; + Vector2 boundarySize; + bool centered; +}; + +struct ViewportPositionConstraint +{ + ViewportPositionConstraint(Vector2 windowOrigin) + : origin(windowOrigin) + { + } + void operator()(Vector2& current, const PropertyInputContainer& inputs) + { + Vector3 framePos = inputs[0]->GetVector3(); + current.x = framePos.x + origin.x; + current.y = framePos.y + origin.y; + } + Vector2 origin; +}; + +struct ViewportSizeConstraint +{ + ViewportSizeConstraint() = default; + + void operator()(Vector2& current, const PropertyInputContainer& inputs) + { + Vector3 frameSize = inputs[0]->GetVector3(); + current.x = frameSize.x; + current.y = frameSize.y; + } +}; + +class CameraTestExample : public ConnectionTracker +{ +public: + CameraTestExample(Application app) + : mApp(app) + { + mApp.InitSignal().Connect(this, &CameraTestExample::OnCreate); + } + + void OnCreate(Application& app) + { + // Use default camera. + Window window = app.GetWindow(); + Vector2 windowSize(1280, 800); + if(window.GetSize().GetWidth() < 1280) + { + window.SetSize(Uint16Pair(windowSize.x, windowSize.y)); // 1280 divides into 427, 427, 426 + } + else + { + windowSize.x = window.GetSize().GetWidth(); + windowSize.y = window.GetSize().GetHeight(); + } + + window.KeyEventSignal().Connect(this, &CameraTestExample::OnKeyEvent); + + // Divide the screen up into 3 regions: + // left: the scene + camera outline + // mid: the viewport + // right: actor / camera controls + + // Viewport frame position is constrained to the mid third, but is actually drawn into full screen overlay. + // Camera frame position is constrained to the left third, but is actually drawn into full screen overlay. + + Vector2 sceneSize = Vector2(ceilf(windowSize.x / 3.0f), 720); + Vector2 panelSize = Vector2(ceilf(windowSize.x / 3.0f), windowSize.y); + + viewLayer = CreateScene(window, Vector2::ZERO, sceneSize); + + sceneRenderTask = CreateSceneRenderTask(window, viewLayer, sceneSize); + + Layer overlayLayer = Layer::New(); // Will be drawn last by separate render tasks + window.Add(overlayLayer); + overlayLayer.SetProperty(Actor::Property::POSITION, Vector3::ZERO); + overlayLayer.SetProperty(Actor::Property::SIZE, windowSize); + overlayLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + overlayLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + overlayRenderTask = CreateOverlayRenderTask(window, windowSize, overlayLayer); + + // Create camera frame + initialCameraSize = Vector3(windowSize.x / 3.0f, windowSize.y, 1); + initialCameraPosition = Vector3(windowSize.x / 6.0f, windowSize.y * 0.5f, 0); + + cameraFrame = CreateFrame(Vector2(initialCameraSize), sceneSize, "Camera"); + cameraFrame.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + cameraFrame.SetProperty(Actor::Property::POSITION, initialCameraPosition); + + cameraGrabHandle = CreateCornerHandle(cameraFrame); + cameraGrabCenter = CreateCenterHandle(cameraFrame); + + // Create viewport frame + initialViewportSize = sceneSize * 0.75f; // Maintain aspect ratio + initialViewportPosition = Vector3(100, 100, 0); + + viewportFrame = CreateFrame(Vector2(initialViewportPosition), Vector2(initialViewportSize), "Viewport"); + viewportFrame.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0f / 3.0f, 0.0f, 0.5f)); // TL of 2nd third of screen + viewportFrame.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + + viewportGrabHandle = CreateCornerHandle(viewportFrame); + viewportGrabCenter = CreateCenterHandle(viewportFrame); + + Vector2 viewportOrigin(windowSize.x / 3.0f, 0.0f); // Viewport origin in window coords (to match frame) + ConstrainSceneViewportCamera(sceneRenderTask, viewportOrigin); + + Constraint constraint = Constraint::New(cameraFrame, Actor::Property::POSITION, BoundaryConstraint("cameraFrame", panelSize, true)); + constraint.AddSource(LocalSource(Actor::Property::POSITION)); + constraint.AddSource(LocalSource(Actor::Property::SIZE)); + constraint.Apply(); + + constraint = Constraint::New(viewportFrame, Actor::Property::POSITION, BoundaryConstraint("viewportFrame", panelSize, false)); + constraint.AddSource(LocalSource(Actor::Property::POSITION)); + constraint.AddSource(LocalSource(Actor::Property::SIZE)); + constraint.Apply(); + + overlayLayer.Add(viewportFrame); + overlayLayer.Add(cameraFrame); + + CreateActorControls(overlayLayer, panelSize); + + mPanGestureDetector = PanGestureDetector::New(); + mPanGestureDetector.Attach(viewportGrabHandle); + mPanGestureDetector.Attach(viewportGrabCenter); + mPanGestureDetector.Attach(cameraGrabHandle); + mPanGestureDetector.Attach(cameraGrabCenter); + mPanGestureDetector.DetectedSignal().Connect(this, &CameraTestExample::OnPan); + + mTapGestureDetector = TapGestureDetector::New(2); + mTapGestureDetector.Attach(viewportGrabHandle); + mTapGestureDetector.Attach(viewportGrabCenter); + mTapGestureDetector.Attach(cameraGrabHandle); + mTapGestureDetector.Attach(cameraGrabCenter); + mTapGestureDetector.DetectedSignal().Connect(this, &CameraTestExample::OnDoubleTap); + } + + Layer CreateScene(Window window, Vector2 position, Vector2 size) + { + const Vector3 offsets[] = + { + Dali::ParentOrigin::TOP_LEFT, + Dali::ParentOrigin::TOP_RIGHT, + Dali::ParentOrigin::BOTTOM_LEFT, + Dali::ParentOrigin::BOTTOM_RIGHT, + Dali::ParentOrigin::CENTER, + }; + + Layer viewLayer = Layer::New(); + window.Add(viewLayer); + + viewLayer.SetProperty(Actor::Property::POSITION, Vector3(position)); + viewLayer.SetProperty(Actor::Property::SIZE, size); + viewLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER_LEFT); + viewLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER_LEFT); + + auto bg = Control::New(); + bg.SetBackgroundColor(Vector4(0.1, 0.0, 0.1, 0.5)); + bg.SetProperty(Actor::Property::SIZE, size); + bg.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + bg.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + viewLayer.Add(bg); + + auto label = TextLabel::New("Scene"); + label[TextLabel::Property::POINT_SIZE] = 12; + label[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER; + label[TextLabel::Property::TEXT_COLOR] = Color::WHITE; + label[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_CENTER; + label[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_CENTER; + viewLayer.Add(label); + + int i = 0; + for(auto& image : images) + { + auto imageView = ImageView::New(image); + imageViews.push_back(imageView); + viewLayer.Add(imageView); + + printf("ActorId: %d\n", imageView.GetProperty(Actor::Property::ID)); + + imageView.SetProperty(Actor::Property::PARENT_ORIGIN, offsets[i]); + imageView.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + imageView.SetProperty(Actor::Property::POSITION, Vector3((0.5f - offsets[i].x) * 50.0f, (0.5f - offsets[i].y) * 50.0f, 0.0f)); + imageView.SetProperty(Actor::Property::SIZE, Vector2(97.0f, 97.0f)); + ++i; + } + return viewLayer; + } + + void CreateActorControls(Layer parent, Vector2 sceneSize) + { + // Create a container that sits on the rightmost third of the window + Actor layoutContainer = Actor::New(); + layoutContainer[Actor::Property::SIZE] = Vector3(sceneSize.x, sceneSize.y, sceneSize.x); + layoutContainer[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_RIGHT; + layoutContainer[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_RIGHT; + + auto bg = Control::New(); + bg.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS); + bg[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER; + bg.SetBackgroundColor(Vector4(0.05f, 0.05f, 0.1f, 1.0f)); + layoutContainer.Add(bg); + + parent.Add(layoutContainer); + + // Add a table for actor rotations + TableView actorProps = TableView::New(7, 2); + actorProps.SetProperty(Actor::Property::NAME, "ActorSliderLayout"); + actorProps.SetProperty(Actor::Property::SIZE, Vector3(sceneSize.x, sceneSize.y, sceneSize.x)); + actorProps.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + actorProps.SetFitWidth(0); + actorProps.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT); + + int i = 0; + for(auto& image : images) + { + actorProps.SetFitHeight(i); + + auto icon = ImageView::New(image); + icon.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + // I would like 50% of natural size... + icon.SetProperty(Actor::Property::SIZE, Vector3(50, 50, 50)); + actorProps.AddChild(icon, TableView::CellPosition(i, 0)); + actorProps.SetCellAlignment(TableView::CellPosition(i, 0), HorizontalAlignment::CENTER, VerticalAlignment::CENTER); + auto slider = Slider::New(); + std::ostringstream sliderStyleName; + sliderStyleName << "RotationSlider" << i + 1; + slider.SetProperty(Actor::Property::NAME, sliderStyleName.str()); + slider.SetStyleName("ThinSlider"); + slider.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + slider.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + slider.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH); + slider.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT); + slider.SetProperty(Slider::Property::LOWER_BOUND, -180.0f); + slider.SetProperty(Slider::Property::UPPER_BOUND, 180.0f); + slider.SetProperty(Slider::Property::VALUE_PRECISION, 0); + slider.SetProperty(Slider::Property::VALUE, 0.0f); + slider.SetProperty(Slider::Property::SHOW_POPUP, true); + slider.RegisterProperty("actorId", i, Property::READ_ONLY); // imageViews[i].GetId() + + actorProps.AddChild(slider, TableView::CellPosition(i, 1)); + actorProps.SetCellAlignment(TableView::CellPosition(i, 1), HorizontalAlignment::RIGHT, VerticalAlignment::CENTER); + slider.ValueChangedSignal().Connect(this, &CameraTestExample::OnRotationSliderChanged); + i++; + } + + auto fovLabel = TextLabel::New("FOV"); + fovLabel.SetProperty(TextLabel::Property::POINT_SIZE, 12); + fovLabel.SetProperty(TextLabel::Property::TEXT_COLOR, Color::WHITE); + fovLabel[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER; + fovLabel[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER; + fovLabel[Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER; + actorProps.AddChild(fovLabel, TableView::CellPosition(i, 0)); + + auto slider = Slider::New(); + slider.SetProperty(Actor::Property::NAME, "FOVSlider"); + slider.SetStyleName("ThinSlider"); + slider.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + slider.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + slider.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH); + slider.SetResizePolicy(ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT); + slider.SetProperty(Slider::Property::LOWER_BOUND, 1.0f); + slider.SetProperty(Slider::Property::UPPER_BOUND, 160.0f); + slider.SetProperty(Slider::Property::VALUE_PRECISION, 0); + slider.SetProperty(Slider::Property::VALUE, Degree(Radian(cameraActor.GetFieldOfView())).degree); + slider.SetProperty(Slider::Property::SHOW_POPUP, true); + slider.ValueChangedSignal().Connect(this, &CameraTestExample::OnFOVChanged); + actorProps.AddChild(slider, TableView::CellPosition(i, 1)); + + layoutContainer.Add(actorProps); + + cameraDetail = TextLabel::New(); + cameraDetail[TextLabel::Property::POINT_SIZE] = 10; + cameraDetail[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER; + cameraDetail[TextLabel::Property::MULTI_LINE] = true; + cameraDetail[TextLabel::Property::TEXT_COLOR] = Color::WHITE; + cameraDetail[Actor::Property::PARENT_ORIGIN] = ParentOrigin::BOTTOM_CENTER; + cameraDetail[Actor::Property::ANCHOR_POINT] = AnchorPoint::BOTTOM_CENTER; + + cameraDetail[Actor::Property::POSITION] = Vector3(0.0f, -15.0f, 0.0f); + cameraDetail.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH); + cameraDetail.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT); + layoutContainer.Add(cameraDetail); + + SetCameraDetailString(); + } + + RenderTask CreateSceneRenderTask(Window window, Layer source, Vector2 sceneSize) + { + // Create a render task with moveable viewport and camera + RenderTask renderTask = window.GetRenderTaskList().CreateTask(); + + cameraActor = CameraActor::New(); + cameraActor.SetType(Camera::FREE_LOOK); + cameraActor.SetPerspectiveProjection(sceneSize); + window.Add(cameraActor); + + renderTask.SetCameraActor(cameraActor); + renderTask.SetInputEnabled(false); + renderTask.SetClearColor(Vector4(0.05f, 0.05f, 0.05f, 1.0f)); + renderTask.SetClearEnabled(true); + renderTask.SetSourceActor(source); + + return renderTask; + } + + void ConstrainSceneViewportCamera(RenderTask sceneRenderTask, Vector2 viewportOrigin) + { + Constraint constraint = Constraint::New(cameraActor, Actor::Property::POSITION, CameraPosConstraint()); + constraint.AddSource(Source(cameraFrame, Actor::Property::POSITION)); + constraint.Apply(); + + constraint = Constraint::New(cameraActor, Actor::Property::SIZE, EqualToConstraint()); + constraint.AddSource(Source(cameraFrame, Actor::Property::SIZE)); + constraint.Apply(); + + constraint = Constraint::New(sceneRenderTask, RenderTask::Property::VIEWPORT_POSITION, ViewportPositionConstraint(viewportOrigin)); + constraint.AddSource(Source(viewportFrame, Actor::Property::POSITION)); + constraint.Apply(); + + constraint = Constraint::New(sceneRenderTask, RenderTask::Property::VIEWPORT_SIZE, ViewportSizeConstraint()); + constraint.AddSource(Source(viewportFrame, Actor::Property::SIZE)); + constraint.Apply(); + } + + RenderTask CreateOverlayRenderTask(Window window, Vector2 windowSize, Layer source) + { + // Create a separate camera / render task to visualize the input frames above the 2nd rendered layer above. + CameraActor overlayCameraActor = CameraActor::New(); + overlayCameraActor.SetType(Camera::FREE_LOOK); + overlayCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + overlayCameraActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + overlayCameraActor.SetProperty(Actor::Property::POSITION, Vector2::ZERO); + overlayCameraActor.SetProperty(Actor::Property::SIZE, windowSize); + overlayCameraActor.SetPerspectiveProjection(windowSize); + window.Add(overlayCameraActor); + + RenderTask overlayRenderTask = window.GetRenderTaskList().CreateTask(); + + overlayRenderTask.SetCameraActor(overlayCameraActor); + overlayRenderTask.SetInputEnabled(true); + overlayRenderTask.SetClearEnabled(false); + overlayRenderTask.SetSourceActor(source); + overlayRenderTask.SetExclusive(true); + + overlayRenderTask.SetViewportPosition(Vector2(0, 0)); + overlayRenderTask.SetViewportSize(windowSize); + + overlayRenderTask.SetCullMode(false); + + return overlayRenderTask; + } + + Actor CreateFrame(Vector2 position, Vector2 size, std::string label) + { + Actor frame = Toolkit::ImageView::New(BORDER_IMAGE); + frame.SetProperty(Dali::Actor::Property::NAME, "ContentFrame"); + frame.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + frame.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + frame.SetProperty(Actor::Property::SIZE, size); + frame.SetProperty(Actor::Property::POSITION, position); + + auto frameLabel = TextLabel::New(label); + frameLabel[TextLabel::Property::POINT_SIZE] = 12; + frameLabel[TextLabel::Property::HORIZONTAL_ALIGNMENT] = HorizontalAlignment::CENTER; + frameLabel[TextLabel::Property::TEXT_COLOR] = Color::YELLOW; + frameLabel[Actor::Property::PARENT_ORIGIN] = ParentOrigin::BOTTOM_CENTER; + frameLabel[Actor::Property::ANCHOR_POINT] = AnchorPoint::BOTTOM_CENTER; + frameLabel[Actor::Property::POSITION] = Vector3(0.0f, 15.0f, 0.0f); + frame.Add(frameLabel); + + return frame; + } + + Actor CreateCornerHandle(Actor parent) + { + Actor cornerHandle = Toolkit::ImageView::New(RESIZE_HANDLE_IMAGE); + cornerHandle.SetProperty(Dali::Actor::Property::NAME, "GrabHandle"); + cornerHandle.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS); + cornerHandle.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_RIGHT); + cornerHandle.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_RIGHT); + cornerHandle.SetProperty(Actor::Property::POSITION, Vector2(-BORDER_WIDTH, -BORDER_WIDTH)); + cornerHandle.SetProperty(Actor::Property::OPACITY, 0.6f); + parent.Add(cornerHandle); + return cornerHandle; + } + + Actor CreateCenterHandle(Actor parent) + { + Actor grabCenter = Toolkit::ImageView::New(CIRCLE_STROKE); + grabCenter.SetProperty(Dali::Actor::Property::NAME, "GrabCenter"); + grabCenter.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS); + grabCenter.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + grabCenter.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + Toolkit::ImageView grabCenter2 = Toolkit::ImageView::New(CIRCLE_POINT); + grabCenter2.SetProperty(Dali::Actor::Property::NAME, "GrabCenter2"); + grabCenter2.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS); + grabCenter2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + grabCenter2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + grabCenter.Add(grabCenter2); + grabCenter.SetProperty(Actor::Property::OPACITY, 0.6f); + parent.Add(grabCenter); + return grabCenter; + } + + void SetCameraDetailString() + { + std::ostringstream oss; + + auto pos = cameraActor.GetCurrentProperty(Actor::Property::POSITION); + auto size = cameraFrame.GetTargetSize(); + + oss << "Camera Detail: Pos: (" << pos.x << ", " << pos.y << ")" << std::endl; + oss << " Frame size: (" << size.x << ", " << size.y << ")" << std::endl; + + // Really, just need a box that represents the screen plane at z=0 from MVP. + + cameraDetail.SetProperty(TextLabel::Property::TEXT, oss.str()); + } + + void OnPan(Actor actor, const PanGesture& gesture) + { + if(actor == viewportGrabHandle) + { + auto size = viewportFrame.GetTargetSize(); + auto newSize = Vector2(size.GetVectorXY() + gesture.GetDisplacement() * 2.0f); + viewportFrame.SetProperty(Actor::Property::SIZE, newSize); + } + else if(actor == viewportGrabCenter) + { + Vector3 pos; + if(gesture.GetState() == GestureState::FINISHED) + { + pos = viewportFrame.GetCurrentProperty(Actor::Property::POSITION); + } + else + { + pos = viewportFrame.GetProperty(Actor::Property::POSITION); + } + pos = Vector2(pos.GetVectorXY() + gesture.GetDisplacement()); + viewportFrame.SetProperty(Actor::Property::POSITION, pos); + } + else if(actor == cameraGrabHandle) + { + auto size = cameraFrame.GetTargetSize(); + auto newSize = Vector2(size.GetVectorXY() + gesture.GetDisplacement() * 2.0f); + cameraFrame.SetProperty(Actor::Property::SIZE, newSize); + cameraActor.SetPerspectiveProjection(newSize); + } + else if(actor == cameraGrabCenter) + { + Vector3 pos; + if(gesture.GetState() == GestureState::FINISHED) + { + pos = cameraFrame.GetCurrentProperty(Actor::Property::POSITION); + } + else + { + pos = cameraFrame.GetProperty(Actor::Property::POSITION); + } + pos = Vector2(pos.GetVectorXY() + gesture.GetDisplacement()); + cameraFrame.SetProperty(Actor::Property::POSITION, pos); + } + + SetCameraDetailString(); + } + + void OnDoubleTap(Actor actor, const TapGesture& gesture) + { + if(actor == viewportGrabHandle) + { + viewportFrame.SetProperty(Actor::Property::SIZE, initialViewportSize); + } + else if(actor == viewportGrabCenter) + { + viewportFrame.SetProperty(Actor::Property::POSITION, initialViewportPosition); + } + else if(actor == cameraGrabHandle) + { + cameraFrame.SetProperty(Actor::Property::SIZE, initialCameraSize); + cameraActor.SetProperty(Actor::Property::SIZE, initialCameraSize); + cameraActor.SetPerspectiveProjection(Vector2(initialCameraSize)); + } + else if(actor == cameraGrabCenter) + { + cameraFrame.SetProperty(Actor::Property::POSITION, initialCameraPosition); + } + } + + bool OnFOVChanged(Slider slider, float value) + { + cameraActor.SetProperty(CameraActor::Property::FIELD_OF_VIEW, (float)Radian(Degree(value))); + return true; + } + + bool OnRotationSliderChanged(Slider slider, float value) + { + auto actorIdIndex = slider.GetPropertyIndex("actorId"); + if(actorIdIndex != Property::INVALID_INDEX) + { + int actorIndex = slider["actorId"]; + float value = slider["value"]; + imageViews[actorIndex].SetProperty(Actor::Property::ORIENTATION, AngleAxis(Degree(value), Vector3::ZAXIS)); + } + return true; + } + + /** + * Main key event handler + */ + void OnKeyEvent(const KeyEvent& event) + { + if(event.GetState() == KeyEvent::DOWN) + { + if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK)) + { + mApp.Quit(); + } + } + } + + RenderTask sceneRenderTask; + RenderTask overlayRenderTask; + + PanGestureDetector mPanGestureDetector; + TapGestureDetector mTapGestureDetector; + + Application mApp; + std::vector imageViews; + + Layer viewLayer; // The "scene" + + Vector3 initialCameraPosition; + Vector3 initialCameraSize; + Vector3 initialViewportPosition; + Vector3 initialViewportSize; + + Actor viewportFrame; + Actor viewportGrabCenter; + Actor viewportGrabHandle; + + Actor cameraFrame; + Actor cameraGrabCenter; + Actor cameraGrabHandle; + + CameraActor cameraActor; + TextLabel cameraDetail; +}; + +int DALI_EXPORT_API main(int argc, char** argv) +{ + Application application = Application::New(&argc, &argv, DEMO_THEME_TWO_PATH); + CameraTestExample test(application); + application.MainLoop(); + return 0; +} diff --git a/resources/po/en_US.po b/resources/po/en_US.po index cda3cf6..1896dec 100755 --- a/resources/po/en_US.po +++ b/resources/po/en_US.po @@ -31,6 +31,9 @@ msgstr "Bubbles" msgid "DALI_DEMO_STR_TITLE_BUTTONS" msgstr "Buttons" +msgid "DALI_DEMO_STR_TITLE_CAMERA_TEST" +msgstr "Camera Test" + msgid "DALI_DEMO_STR_TITLE_CANVAS_VIEW" msgstr "Canvas view" diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index b9b283f..d6b0b9c 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,7 @@ extern "C" #define DALI_DEMO_STR_TITLE_BLOOM_VIEW dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_BLOOM_VIEW") #define DALI_DEMO_STR_TITLE_BUBBLES dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_BUBBLES") #define DALI_DEMO_STR_TITLE_BUTTONS dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_BUTTONS") +#define DALI_DEMO_STR_TITLE_CAMERA_TEST dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CAMERA_TEST") #define DALI_DEMO_STR_TITLE_CANVAS_VIEW dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CANVAS_VIEW") #define DALI_DEMO_STR_TITLE_CALL_ACTIVE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CALL_ACTIVE") #define DALI_DEMO_STR_TITLE_CARD_ACTIVE dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_CARD_ACTIVE") @@ -155,6 +156,7 @@ extern "C" #define DALI_DEMO_STR_TITLE_BLOOM_VIEW "Bloom" #define DALI_DEMO_STR_TITLE_BUBBLES "Bubbles" #define DALI_DEMO_STR_TITLE_BUTTONS "Buttons" +#define DALI_DEMO_STR_TITLE_CAMERA_TEST "Camera Test" #define DALI_DEMO_STR_TITLE_CANVAS_VIEW "Canvas View" #define DALI_DEMO_STR_TITLE_CALL_ACTIVE "Call Active" #define DALI_DEMO_STR_TITLE_CARD_ACTIVE "Card Active" diff --git a/tests-reel/dali-tests-reel.cpp b/tests-reel/dali-tests-reel.cpp index 0cf9935..b53a239 100644 --- a/tests-reel/dali-tests-reel.cpp +++ b/tests-reel/dali-tests-reel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,6 +38,7 @@ int DALI_EXPORT_API main(int argc, char** argv) DaliTableView demo(app); demo.AddExample(Example("benchmark.example", DALI_DEMO_STR_TITLE_BENCHMARK)); + demo.AddExample(Example("camera-test.example", DALI_DEMO_STR_TITLE_CAMERA_TEST)); demo.AddExample(Example("compressed-texture-formats.example", DALI_DEMO_STR_TITLE_COMPRESSED_TEXTURE_FORMATS)); demo.AddExample(Example("homescreen-benchmark.example", DALI_DEMO_STR_TITLE_HOMESCREEN)); demo.AddExample(Example("pre-render-callback.example", DALI_DEMO_STR_TITLE_PRE_RENDER_CALLBACK));