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