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