Add ApplyCustomFragmentPrefix
[platform/core/uifw/dali-demo.git] / examples / native-image-source / native-image-source-example.cpp
1 /*
2  * Copyright (c) 2021 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 // EXTERNAL INCLUDES
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali/dali.h>
21 #include <cstring>
22
23 // INTERNAL INCLUDES
24 #include "generated/native-image-source-texture-frag.h"
25 #include "generated/native-image-source-texture-vert.h"
26 #include "shared/utility.h"
27
28 using namespace Dali;
29 using namespace Toolkit;
30
31 namespace
32 {
33 const float BUTTON_HEIGHT = 100.0f;
34 const float BUTTON_COUNT  = 5.0f;
35
36 const std::string JPG_FILENAME     = DEMO_IMAGE_DIR "gallery-medium-4.jpg";
37 const std::string CAPTURE_FILENAME = DEMO_DATA_PUBLIC_RW_DIR "native-image-capture.png";
38
39 /**
40  * @brief Creates a shader used to render a native image
41  * @param[in] nativeImage The native image
42  * @return A shader to render the native image
43  */
44 Shader CreateShader(NativeImageInterface& nativeImage)
45 {
46   std::string fragmentShader;
47
48   //Get custom fragment shader prefix
49   fragmentShader = SHADER_NATIVE_IMAGE_SOURCE_TEXTURE_FRAG.data();
50   nativeImage.ApplyNativeFragmentShader(fragmentShader);
51
52   return Shader::New(SHADER_NATIVE_IMAGE_SOURCE_TEXTURE_VERT, fragmentShader);
53 }
54
55 } // namespace
56
57 // This example shows how to create and use a NativeImageSource as the target of the render task.
58 //
59 class NativeImageSourceController : public ConnectionTracker
60 {
61 public:
62   NativeImageSourceController(Application& application)
63   : mApplication(application),
64     mRefreshAlways(true)
65   {
66     // Connect to the Application's Init signal
67     mApplication.InitSignal().Connect(this, &NativeImageSourceController::Create);
68   }
69
70   ~NativeImageSourceController()
71   {
72     // Nothing to do here;
73   }
74
75   // The Init signal is received once (only) during the Application lifetime
76   void Create(Application& application)
77   {
78     // Get a handle to the window
79     Window window = application.GetWindow();
80     window.SetBackgroundColor(Color::WHITE);
81
82     window.KeyEventSignal().Connect(this, &NativeImageSourceController::OnKeyEvent);
83
84     CreateButtonArea();
85
86     CreateContentAreas();
87   }
88
89   void CreateButtonArea()
90   {
91     Window  window     = mApplication.GetWindow();
92     Vector2 windowSize = window.GetSize();
93
94     mButtonArea = Layer::New();
95     mButtonArea.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x, BUTTON_HEIGHT));
96     mButtonArea.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
97     mButtonArea.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
98     window.Add(mButtonArea);
99
100     mButtonShow = PushButton::New();
101     mButtonShow.SetProperty(Button::Property::TOGGLABLE, true);
102     mButtonShow.SetProperty(Toolkit::Button::Property::LABEL, "SHOW");
103     mButtonShow.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
104     mButtonShow.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
105     mButtonShow.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
106     mButtonShow.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
107     mButtonArea.Add(mButtonShow);
108
109     mButtonRefreshAlways = PushButton::New();
110     mButtonRefreshAlways.SetProperty(Button::Property::TOGGLABLE, true);
111     mButtonRefreshAlways.SetProperty(Toolkit::Button::Property::LABEL, "ALWAYS");
112     mButtonRefreshAlways.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
113     mButtonRefreshAlways.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
114     mButtonRefreshAlways.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
115     mButtonRefreshAlways.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 1.0f, 0.0f));
116     mButtonRefreshAlways.StateChangedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
117     mButtonArea.Add(mButtonRefreshAlways);
118
119     mButtonRefreshOnce = PushButton::New();
120     mButtonRefreshOnce.SetProperty(Toolkit::Button::Property::LABEL, "ONCE");
121     mButtonRefreshOnce.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
122     mButtonRefreshOnce.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
123     mButtonRefreshOnce.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
124     mButtonRefreshOnce.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 2.0f, 0.0f));
125     mButtonRefreshOnce.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
126     mButtonArea.Add(mButtonRefreshOnce);
127
128     mButtonCapture = PushButton::New();
129     mButtonCapture.SetProperty(Toolkit::Button::Property::LABEL, "CAPTURE");
130     mButtonCapture.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
131     mButtonCapture.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
132     mButtonCapture.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
133     mButtonCapture.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 3.0f, 0.0f));
134     mButtonCapture.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
135     mButtonArea.Add(mButtonCapture);
136
137     mButtonReset = PushButton::New();
138     mButtonReset.SetProperty(Toolkit::Button::Property::LABEL, "RESET");
139     mButtonReset.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
140     mButtonReset.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
141     mButtonReset.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x / BUTTON_COUNT, BUTTON_HEIGHT));
142     mButtonReset.SetProperty(Actor::Property::POSITION, Vector2((windowSize.x / BUTTON_COUNT) * 4.0f, 0.0f));
143     mButtonReset.ClickedSignal().Connect(this, &NativeImageSourceController::OnButtonSelected);
144     mButtonArea.Add(mButtonReset);
145   }
146
147   void CreateContentAreas()
148   {
149     Window  window     = mApplication.GetWindow();
150     Vector2 windowSize = window.GetSize();
151
152     float contentHeight((windowSize.y - BUTTON_HEIGHT) / 2.0f);
153
154     mTopContentArea = Actor::New();
155     mTopContentArea.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x, contentHeight));
156     mTopContentArea.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
157     mTopContentArea.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
158     mTopContentArea.SetProperty(Actor::Property::POSITION_Y, BUTTON_HEIGHT);
159     window.Add(mTopContentArea);
160
161     mBottomContentArea = Actor::New();
162     mBottomContentArea.SetProperty(Actor::Property::SIZE, Vector2(windowSize.x, contentHeight));
163     mBottomContentArea.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
164     mBottomContentArea.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
165     window.Add(mBottomContentArea);
166
167     mSourceActor = ImageView::New(JPG_FILENAME);
168     mSourceActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
169     mSourceActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
170     mTopContentArea.Add(mSourceActor);
171
172     Animation animation = Animation::New(2.f);
173     Degree    relativeRotationDegrees(90.0f);
174     Radian    relativeRotationRadians(relativeRotationDegrees);
175     animation.AnimateTo(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(0.f, 0.5f));
176     animation.AnimateBy(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(0.5f, 0.5f));
177     animation.AnimateBy(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(1.f, 0.5f));
178     animation.AnimateBy(Property(mSourceActor, Actor::Property::ORIENTATION), Quaternion(relativeRotationRadians, Vector3::ZAXIS), AlphaFunction::LINEAR, TimePeriod(1.5f, 0.5f));
179     animation.SetLooping(true);
180     animation.Play();
181
182     TextLabel textLabel1 = TextLabel::New("Image");
183     textLabel1.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
184     textLabel1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
185     mTopContentArea.Add(textLabel1);
186
187     // Wait until button press before creating mOffscreenRenderTask
188
189     TextLabel textLabel2 = TextLabel::New("Native Image");
190     textLabel2.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
191     textLabel2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
192     mBottomContentArea.Add(textLabel2);
193   }
194
195   void SetupNativeImage()
196   {
197     if(!mOffscreenRenderTask)
198     {
199       Window  window     = mApplication.GetWindow();
200       Vector2 windowSize = window.GetSize();
201
202       float   contentHeight((windowSize.y - BUTTON_HEIGHT) / 2.0f);
203       Vector2 imageSize(windowSize.x, contentHeight);
204
205       mNativeImageSourcePtr = NativeImageSource::New(imageSize.width, imageSize.height, NativeImageSource::COLOR_DEPTH_DEFAULT);
206       mNativeTexture        = Texture::New(*mNativeImageSourcePtr);
207
208       mFrameBuffer = FrameBuffer::New(mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), FrameBuffer::Attachment::NONE);
209       mFrameBuffer.AttachColorTexture(mNativeTexture);
210
211       mCameraActor = CameraActor::New(imageSize);
212       mCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
213       mCameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
214       mTopContentArea.Add(mCameraActor);
215
216       RenderTaskList taskList = window.GetRenderTaskList();
217       mOffscreenRenderTask    = taskList.CreateTask();
218       mOffscreenRenderTask.SetSourceActor(mSourceActor);
219       mOffscreenRenderTask.SetClearColor(Color::WHITE);
220       mOffscreenRenderTask.SetClearEnabled(true);
221       mOffscreenRenderTask.SetCameraActor(mCameraActor);
222       mOffscreenRenderTask.GetCameraActor().SetInvertYAxis(true);
223       mOffscreenRenderTask.SetFrameBuffer(mFrameBuffer);
224     }
225
226     if(mRefreshAlways)
227     {
228       mOffscreenRenderTask.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
229     }
230     else
231     {
232       mOffscreenRenderTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
233     }
234   }
235
236   void SetupDisplayActor(bool show)
237   {
238     if(show)
239     {
240       if(!mDisplayActor)
241       {
242         // Make sure we have something to display
243         SetupNativeImage();
244
245         mDisplayActor = Actor::New();
246         mDisplayActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
247         mDisplayActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
248
249         Geometry geometry = DemoHelper::CreateTexturedQuad();
250
251         Shader shader = CreateShader(*mNativeImageSourcePtr);
252
253         Renderer renderer = Renderer::New(geometry, shader);
254
255         TextureSet textureSet = TextureSet::New();
256         textureSet.SetTexture(0u, mNativeTexture);
257         renderer.SetTextures(textureSet);
258
259         mDisplayActor.AddRenderer(renderer);
260         mDisplayActor.SetProperty(Actor::Property::SIZE, Vector2(mNativeTexture.GetWidth(), mNativeTexture.GetHeight()));
261
262         mBottomContentArea.Add(mDisplayActor);
263       }
264     }
265     else
266     {
267       UnparentAndReset(mDisplayActor);
268     }
269   }
270
271   void Capture()
272   {
273     mRefreshAlways = false;
274     SetupNativeImage();
275
276     mOffscreenRenderTask.FinishedSignal().Connect(this, &NativeImageSourceController::DoCapture);
277   }
278
279   void DoCapture(RenderTask& task)
280   {
281     task.FinishedSignal().Disconnect(this, &NativeImageSourceController::DoCapture);
282
283     mNativeImageSourcePtr->EncodeToFile(CAPTURE_FILENAME);
284   }
285
286   void Reset()
287   {
288     SetupDisplayActor(false);
289
290     Window         window   = mApplication.GetWindow();
291     RenderTaskList taskList = window.GetRenderTaskList();
292     taskList.RemoveTask(mOffscreenRenderTask);
293     mOffscreenRenderTask.Reset();
294     mCameraActor.Reset();
295
296     mFrameBuffer.Reset();
297     mNativeTexture.Reset();
298     mNativeImageSourcePtr.Reset();
299   }
300
301   bool OnButtonSelected(Toolkit::Button button)
302   {
303     Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast(button);
304
305     if(pushButton == mButtonShow)
306     {
307       bool isSelected = mButtonShow.GetProperty(Toolkit::Button::Property::SELECTED).Get<bool>();
308
309       SetupDisplayActor(isSelected);
310     }
311     else if(pushButton == mButtonRefreshAlways)
312     {
313       bool isSelected = mButtonRefreshAlways.GetProperty(Toolkit::Button::Property::SELECTED).Get<bool>();
314
315       mRefreshAlways = isSelected;
316       SetupNativeImage();
317     }
318     else if(pushButton == mButtonRefreshOnce)
319     {
320       bool isSelected = mButtonRefreshAlways.GetProperty(Toolkit::Button::Property::SELECTED).Get<bool>();
321
322       if(isSelected)
323       {
324         mButtonRefreshAlways.SetProperty(Button::Property::SELECTED, false);
325       }
326
327       mRefreshAlways = false;
328       SetupNativeImage();
329     }
330     else if(pushButton == mButtonCapture)
331     {
332       Capture();
333     }
334     else if(pushButton == mButtonReset)
335     {
336       Reset();
337     }
338
339     return true;
340   }
341
342   void OnKeyEvent(const KeyEvent& event)
343   {
344     if(event.GetState() == KeyEvent::DOWN)
345     {
346       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
347       {
348         mApplication.Quit();
349       }
350     }
351   }
352
353 private:
354   Application& mApplication;
355
356   Layer mButtonArea;
357   Actor mTopContentArea;
358   Actor mBottomContentArea;
359
360   PushButton mButtonShow;
361   PushButton mButtonRefreshAlways;
362   PushButton mButtonRefreshOnce;
363   PushButton mButtonCapture;
364   PushButton mButtonReset;
365
366   Actor mSourceActor;
367
368   NativeImageSourcePtr mNativeImageSourcePtr;
369   Texture              mNativeTexture;
370   FrameBuffer          mFrameBuffer;
371
372   RenderTask  mOffscreenRenderTask;
373   CameraActor mCameraActor;
374
375   Actor mDisplayActor;
376
377   bool mRefreshAlways;
378 };
379
380 int DALI_EXPORT_API main(int argc, char** argv)
381 {
382   Application                 application = Application::New(&argc, &argv);
383   NativeImageSourceController test(application);
384   application.MainLoop();
385   return 0;
386 }