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