/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
*
*/
-#include <dali/dali.h>
+// EXTERNAL INCLUDES
#include <dali-toolkit/dali-toolkit.h>
+#include <dali/dali.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include "generated/native-image-source-texture-frag.h"
+#include "generated/native-image-source-texture-vert.h"
+#include "shared/utility.h"
using namespace Dali;
using namespace Toolkit;
namespace
{
- const std::string JPG_FILENAME = DEMO_IMAGE_DIR "gallery-medium-4.jpg";
+const float BUTTON_HEIGHT = 100.0f;
+const float BUTTON_COUNT = 5.0f;
+
+const std::string JPG_FILENAME = DEMO_IMAGE_DIR "gallery-medium-4.jpg";
+const std::string CAPTURE_FILENAME = DEMO_DATA_PUBLIC_RW_DIR "native-image-capture.png";
+
+/**
+ * @brief Creates a shader used to render a native image
+ * @param[in] nativeImage The native image
+ * @return A shader to render the native image
+ */
+Shader CreateShader(NativeImageInterface& nativeImage)
+{
+ std::string fragmentShader;
+
+ //Get custom fragment shader prefix
+ fragmentShader = SHADER_NATIVE_IMAGE_SOURCE_TEXTURE_FRAG.data();
+ nativeImage.ApplyNativeFragmentShader(fragmentShader);
+
+ return Shader::New(SHADER_NATIVE_IMAGE_SOURCE_TEXTURE_VERT, fragmentShader);
}
+} // namespace
+
// This example shows how to create and use a NativeImageSource as the target of the render task.
//
class NativeImageSourceController : public ConnectionTracker
{
public:
-
- NativeImageSourceController( Application& application )
- : mApplication( application )
+ NativeImageSourceController(Application& application)
+ : mApplication(application),
+ mRefreshAlways(true)
{
// Connect to the Application's Init signal
- mApplication.InitSignal().Connect( this, &NativeImageSourceController::Create );
+ mApplication.InitSignal().Connect(this, &NativeImageSourceController::Create);
}
~NativeImageSourceController()
}
// The Init signal is received once (only) during the Application lifetime
- void Create( Application& application )
+ void Create(Application& application)
{
- // Get a handle to the stage
- Stage stage = Stage::GetCurrent();
- stage.SetBackgroundColor( Color::WHITE );
- stage.KeyEventSignal().Connect(this, &NativeImageSourceController::OnKeyEvent);
+ // Get a handle to the window
+ Window window = application.GetWindow();
+ window.SetBackgroundColor(Color::WHITE);
+
+ window.KeyEventSignal().Connect(this, &NativeImageSourceController::OnKeyEvent);
+
+ CreateButtonArea();
+
+ CreateContentAreas();
+ }
+
+ void CreateButtonArea()
+ {
+ Window window = mApplication.GetWindow();
+ Vector2 windowSize = window.GetSize();
+
+ mButtonArea = Layer::New();
+ mButtonArea.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x, BUTTON_HEIGHT));
+ mButtonArea.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
+ mButtonArea.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
+ window.Add(mButtonArea);
+
+ mButtonShow = PushButton::New();
+ mButtonShow.SetProperty(Button::Property::TOGGLABLE, true);
+ mButtonShow.SetProperty(Toolkit::Button::Property::LABEL, "SHOW");
+ mButtonShow.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ mButtonShow.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ mButtonShow.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
+ mButtonShow.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
+ mButtonArea.Add(mButtonShow);
mButtonRefreshAlways = PushButton::New();
- mButtonRefreshAlways.SetTogglableButton( true );
- mButtonRefreshAlways.SetSelected( true );
- mButtonRefreshAlways.SetLabelText( "Refresh ALWAYS" );
- mButtonRefreshAlways.SetParentOrigin( ParentOrigin::TOP_LEFT );
- mButtonRefreshAlways.SetAnchorPoint( AnchorPoint::TOP_LEFT );
- mButtonRefreshAlways.StateChangedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
- stage.Add( mButtonRefreshAlways );
+ mButtonRefreshAlways.SetProperty(Button::Property::TOGGLABLE, true);
+ mButtonRefreshAlways.SetProperty(Toolkit::Button::Property::LABEL, "ALWAYS");
+ mButtonRefreshAlways.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ mButtonRefreshAlways.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ mButtonRefreshAlways.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
+ mButtonRefreshAlways.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 1.0f, 0.0f));
+ mButtonRefreshAlways.StateChangedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
+ mButtonArea.Add(mButtonRefreshAlways);
mButtonRefreshOnce = PushButton::New();
- mButtonRefreshOnce.SetLabelText( "Refresh ONCE" );
- mButtonRefreshOnce.SetParentOrigin( ParentOrigin::TOP_RIGHT );
- mButtonRefreshOnce.SetAnchorPoint( AnchorPoint::TOP_RIGHT );
- mButtonRefreshOnce.ClickedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
- stage.Add( mButtonRefreshOnce);
-
- CreateScene();
+ mButtonRefreshOnce.SetProperty(Toolkit::Button::Property::LABEL, "ONCE");
+ mButtonRefreshOnce.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ mButtonRefreshOnce.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ mButtonRefreshOnce.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
+ mButtonRefreshOnce.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 2.0f, 0.0f));
+ mButtonRefreshOnce.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
+ mButtonArea.Add(mButtonRefreshOnce);
+
+ mButtonCapture = PushButton::New();
+ mButtonCapture.SetProperty(Toolkit::Button::Property::LABEL, "CAPTURE");
+ mButtonCapture.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ mButtonCapture.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ mButtonCapture.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
+ mButtonCapture.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 3.0f, 0.0f));
+ mButtonCapture.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
+ mButtonArea.Add(mButtonCapture);
+
+ mButtonReset = PushButton::New();
+ mButtonReset.SetProperty(Toolkit::Button::Property::LABEL, "RESET");
+ mButtonReset.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ mButtonReset.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ mButtonReset.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
+ mButtonReset.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 4.0f, 0.0f));
+ mButtonReset.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
+ mButtonArea.Add(mButtonReset);
}
- bool CreateScene()
+ void CreateContentAreas()
{
- Stage stage = Stage::GetCurrent();
- Vector2 stageSize = stage.GetSize();
+ Window window = mApplication.GetWindow();
+ Vector2 windowSize = window.GetSize();
- float buttonHeight = 100.f;
- mButtonRefreshAlways.SetSize( stageSize.x / 2.f, buttonHeight );
- mButtonRefreshOnce.SetSize( stageSize.x / 2.f, buttonHeight );
+ float contentHeight((windowSize.y - BUTTON_HEIGHT) / 2.0f);
- Vector2 imageSize( stageSize.x, (stageSize.y-buttonHeight)/2.f );
+ mTopContentArea = Actor::New();
+ mTopContentArea.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x, contentHeight));
+ mTopContentArea.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
+ mTopContentArea.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
+ mTopContentArea.SetProperty(Actor::Property::POSITION_Y, BUTTON_HEIGHT);
+ window.Add(mTopContentArea);
- // Create the native image source
- NativeImageSourcePtr nativeImageSourcePtr = NativeImageSource::New( imageSize.width, imageSize.height, NativeImageSource::COLOR_DEPTH_DEFAULT );
+ mBottomContentArea = Actor::New();
+ mBottomContentArea.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x, contentHeight));
+ mBottomContentArea.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
+ mBottomContentArea.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
+ window.Add(mBottomContentArea);
- // Create a image view as source actor to be renderer to the native image source
- Actor sourceActor = ImageView::New(JPG_FILENAME);
- sourceActor.SetParentOrigin( ParentOrigin::CENTER);
- sourceActor.SetAnchorPoint( AnchorPoint::CENTER );
- sourceActor.SetY( - (imageSize.height-buttonHeight)/2.f );
- stage.Add( sourceActor );
+ mSourceActor = ImageView::New(JPG_FILENAME);
+ mSourceActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ mSourceActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ mTopContentArea.Add(mSourceActor);
Animation animation = Animation::New(2.f);
- Degree relativeRotationDegrees(90.0f);
- Radian relativeRotationRadians(relativeRotationDegrees);
- animation.AnimateTo( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(0.f, 0.5f));
- animation.AnimateBy( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(0.5f, 0.5f));
- animation.AnimateBy( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(1.f, 0.5f));
- animation.AnimateBy( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(1.5f, 0.5f));
+ Degree relativeRotationDegrees(90.0f);
+ Radian relativeRotationRadians(relativeRotationDegrees);
+ animation.AnimateTo(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(0.f, 0.5f));
+ animation.AnimateBy(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(0.5f, 0.5f));
+ animation.AnimateBy(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(1.f, 0.5f));
+ animation.AnimateBy(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(1.5f, 0.5f));
animation.SetLooping(true);
animation.Play();
- // create a offscreen renderer task to render content into the native image source
- FrameBufferImage targetBuffer = FrameBufferImage::New( *nativeImageSourcePtr );
-
- CameraActor cameraActor = CameraActor::New(imageSize);
- cameraActor.SetParentOrigin(ParentOrigin::TOP_CENTER);
- cameraActor.SetParentOrigin( AnchorPoint::TOP_CENTER );
- cameraActor.SetY( buttonHeight + imageSize.height/2.f );
- stage.Add(cameraActor);
-
- RenderTaskList taskList = stage.GetRenderTaskList();
- mOffscreenRenderTask = taskList.CreateTask();
- mOffscreenRenderTask.SetSourceActor( sourceActor );
- mOffscreenRenderTask.SetClearColor( Color::WHITE );
- mOffscreenRenderTask.SetClearEnabled(true);
- mOffscreenRenderTask.SetCameraActor(cameraActor);
- mOffscreenRenderTask.GetCameraActor().SetInvertYAxis(true);
- mOffscreenRenderTask.SetTargetFrameBuffer( targetBuffer );
- mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
-
- // Display the native image on the screen
- NativeImage nativeImage = NativeImage::New( *nativeImageSourcePtr );
- ImageView nativeImageView = ImageView::New( nativeImage );
- nativeImageView.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
- nativeImageView.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
- stage.Add( nativeImageView );
-
- TextLabel textLabel1 = TextLabel::New( "Resource Image" );
- textLabel1.SetParentOrigin( ParentOrigin::TOP_CENTER );
- textLabel1.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
- nativeImageView.Add( textLabel1 );
-
- TextLabel textLabel2 = TextLabel::New( "Native Image" );
- textLabel2.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
- textLabel2.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
- nativeImageView.Add( textLabel2 );
-
- return false;
+ TextLabel textLabel1 = TextLabel::New("Image");
+ textLabel1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
+ textLabel1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
+ mTopContentArea.Add(textLabel1);
+
+ // Wait until button press before creating mOffscreenRenderTask
+
+ TextLabel textLabel2 = TextLabel::New("Native Image");
+ textLabel2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
+ textLabel2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
+ mBottomContentArea.Add(textLabel2);
}
- bool OnButtonSelected( Toolkit::Button button )
+ void SetupNativeImage()
{
- Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( button );
- if( pushButton == mButtonRefreshAlways )
+ if(!mOffscreenRenderTask)
{
- if( mButtonRefreshAlways.IsSelected() )
- {
- mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
- }
- else
+ Window window = mApplication.GetWindow();
+ Vector2 windowSize = window.GetSize();
+
+ float contentHeight((windowSize.y - BUTTON_HEIGHT) / 2.0f);
+ Vector2 imageSize(windowSize.x, contentHeight);
+
+ mNativeImageSourcePtr = NativeImageSource::New(imageSize.width, imageSize.height, NativeImageSource::COLOR_DEPTH_DEFAULT);
+ mNativeTexture = Texture::New(*mNativeImageSourcePtr);
+
+ mFrameBuffer = FrameBuffer::New(mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), FrameBuffer::Attachment::NONE);
+ mFrameBuffer.AttachColorTexture(mNativeTexture);
+
+ mCameraActor = CameraActor::New(imageSize);
+ mCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ mCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+ mTopContentArea.Add(mCameraActor);
+
+ RenderTaskList taskList = window.GetRenderTaskList();
+ mOffscreenRenderTask = taskList.CreateTask();
+ mOffscreenRenderTask.SetSourceActor(mSourceActor);
+ mOffscreenRenderTask.SetClearColor(Color::WHITE);
+ mOffscreenRenderTask.SetClearEnabled(true);
+ mOffscreenRenderTask.SetCameraActor(mCameraActor);
+ mOffscreenRenderTask.GetCameraActor().SetInvertYAxis(true);
+ mOffscreenRenderTask.SetFrameBuffer(mFrameBuffer);
+ }
+
+ if(mRefreshAlways)
+ {
+ mOffscreenRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
+ }
+ else
+ {
+ mOffscreenRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+ }
+ }
+
+ void SetupDisplayActor(bool show)
+ {
+ if(show)
+ {
+ if(!mDisplayActor)
{
- mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
+ // Make sure we have something to display
+ SetupNativeImage();
+
+ mDisplayActor = Actor::New();
+ mDisplayActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ mDisplayActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+
+ Geometry geometry = DemoHelper::CreateTexturedQuad();
+
+ Shader shader = CreateShader(*mNativeImageSourcePtr);
+
+ Renderer renderer = Renderer::New(geometry, shader);
+
+ TextureSet textureSet = TextureSet::New();
+ textureSet.SetTexture(0u, mNativeTexture);
+ renderer.SetTextures(textureSet);
+
+ mDisplayActor.AddRenderer(renderer);
+ mDisplayActor.SetProperty(Actor::Property::SIZE, Vector2(mNativeTexture.GetWidth(), mNativeTexture.GetHeight()));
+
+ mBottomContentArea.Add(mDisplayActor);
}
}
- else if( pushButton == mButtonRefreshOnce )
+ else
{
- if( mButtonRefreshAlways.IsSelected() )
+ UnparentAndReset(mDisplayActor);
+ }
+ }
+
+ void Capture()
+ {
+ mRefreshAlways = false;
+ SetupNativeImage();
+
+ mOffscreenRenderTask.FinishedSignal().Connect(this, &NativeImageSourceController::DoCapture);
+ }
+
+ void DoCapture(RenderTask& task)
+ {
+ task.FinishedSignal().Disconnect(this, &NativeImageSourceController::DoCapture);
+
+ mNativeImageSourcePtr->EncodeToFile(CAPTURE_FILENAME);
+ }
+
+ void Reset()
+ {
+ SetupDisplayActor(false);
+
+ Window window = mApplication.GetWindow();
+ RenderTaskList taskList = window.GetRenderTaskList();
+ taskList.RemoveTask(mOffscreenRenderTask);
+ mOffscreenRenderTask.Reset();
+ mCameraActor.Reset();
+
+ mFrameBuffer.Reset();
+ mNativeTexture.Reset();
+ mNativeImageSourcePtr.Reset();
+ }
+
+ bool OnButtonSelected(Toolkit::Button button)
+ {
+ Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast(button);
+
+ if(pushButton == mButtonShow)
+ {
+ bool isSelected = mButtonShow.GetProperty(Toolkit::Button::Property::SELECTED).Get<bool>();
+
+ SetupDisplayActor(isSelected);
+ }
+ else if(pushButton == mButtonRefreshAlways)
+ {
+ bool isSelected = mButtonRefreshAlways.GetProperty(Toolkit::Button::Property::SELECTED).Get<bool>();
+
+ mRefreshAlways = isSelected;
+ SetupNativeImage();
+ }
+ else if(pushButton == mButtonRefreshOnce)
+ {
+ bool isSelected = mButtonRefreshAlways.GetProperty(Toolkit::Button::Property::SELECTED).Get<bool>();
+
+ if(isSelected)
{
- mButtonRefreshAlways.SetSelected( false );
+ mButtonRefreshAlways.SetProperty(Button::Property::SELECTED, false);
}
- mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
+
+ mRefreshAlways = false;
+ SetupNativeImage();
+ }
+ else if(pushButton == mButtonCapture)
+ {
+ Capture();
+ }
+ else if(pushButton == mButtonReset)
+ {
+ Reset();
}
return true;
void OnKeyEvent(const KeyEvent& event)
{
- if(event.state == KeyEvent::Down)
+ if(event.GetState() == KeyEvent::DOWN)
{
- if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
+ if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
{
mApplication.Quit();
}
}
private:
- Application& mApplication;
- RenderTask mOffscreenRenderTask;
+ Application& mApplication;
+
+ Layer mButtonArea;
+ Actor mTopContentArea;
+ Actor mBottomContentArea;
+
+ PushButton mButtonShow;
PushButton mButtonRefreshAlways;
PushButton mButtonRefreshOnce;
+ PushButton mButtonCapture;
+ PushButton mButtonReset;
-};
+ Actor mSourceActor;
-void RunTest( Application& application )
-{
- NativeImageSourceController test( application );
+ NativeImageSourcePtr mNativeImageSourcePtr;
+ Texture mNativeTexture;
+ FrameBuffer mFrameBuffer;
- application.MainLoop();
-}
+ RenderTask mOffscreenRenderTask;
+ CameraActor mCameraActor;
-// Entry point for Linux & Tizen applications
-//
-int DALI_EXPORT_API main( int argc, char **argv )
-{
- Application application = Application::New( &argc, &argv );
+ Actor mDisplayActor;
- RunTest( application );
+ bool mRefreshAlways;
+};
+int DALI_EXPORT_API main(int argc, char** argv)
+{
+ Application application = Application::New(&argc, &argv);
+ NativeImageSourceController test(application);
+ application.MainLoop();
return 0;
}