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