Using migrated Public Visual API
[platform/core/uifw/dali-demo.git] / examples / native-image-source / native-image-source-example.cpp
1 /*
2  * Copyright (c) 2017 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     // Hide the indicator bar
134     application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
135
136     stage.KeyEventSignal().Connect(this, &NativeImageSourceController::OnKeyEvent);
137
138     CreateButtonArea();
139
140     CreateContentAreas();
141   }
142
143   void CreateButtonArea()
144   {
145     Stage stage = Stage::GetCurrent();
146     Vector2 stageSize = stage.GetSize();
147
148     mButtonArea = Layer::New();
149     mButtonArea.SetSize( stageSize.x, BUTTON_HEIGHT );
150     mButtonArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
151     mButtonArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
152     stage.Add( mButtonArea );
153
154     mButtonShow = PushButton::New();
155     mButtonShow.SetProperty( Button::Property::TOGGLABLE, true );
156     mButtonShow.SetProperty( Toolkit::Button::Property::LABEL, "SHOW" );
157     mButtonShow.SetParentOrigin( ParentOrigin::TOP_LEFT );
158     mButtonShow.SetAnchorPoint( AnchorPoint::TOP_LEFT );
159     mButtonShow.SetSize( stageSize.x / BUTTON_COUNT, BUTTON_HEIGHT );
160     mButtonShow.ClickedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
161     mButtonArea.Add( mButtonShow );
162
163     mButtonRefreshAlways = PushButton::New();
164     mButtonRefreshAlways.SetProperty( Button::Property::TOGGLABLE, true );
165     mButtonRefreshAlways.SetProperty( Toolkit::Button::Property::LABEL, "ALWAYS" );
166     mButtonRefreshAlways.SetParentOrigin( ParentOrigin::TOP_LEFT );
167     mButtonRefreshAlways.SetAnchorPoint( AnchorPoint::TOP_LEFT );
168     mButtonRefreshAlways.SetSize( stageSize.x / BUTTON_COUNT, BUTTON_HEIGHT );
169     mButtonRefreshAlways.SetPosition( (stageSize.x / BUTTON_COUNT)*1.0f, 0.0f );
170     mButtonRefreshAlways.StateChangedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
171     mButtonArea.Add( mButtonRefreshAlways );
172
173     mButtonRefreshOnce = PushButton::New();
174     mButtonRefreshOnce.SetProperty( Toolkit::Button::Property::LABEL, "ONCE" );
175     mButtonRefreshOnce.SetParentOrigin( ParentOrigin::TOP_LEFT );
176     mButtonRefreshOnce.SetAnchorPoint( AnchorPoint::TOP_LEFT );
177     mButtonRefreshOnce.SetSize( stageSize.x / BUTTON_COUNT, BUTTON_HEIGHT );
178     mButtonRefreshOnce.SetPosition( (stageSize.x / BUTTON_COUNT)*2.0f, 0.0f );
179     mButtonRefreshOnce.ClickedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
180     mButtonArea.Add( mButtonRefreshOnce );
181
182     mButtonCapture = PushButton::New();
183     mButtonCapture.SetProperty( Toolkit::Button::Property::LABEL, "CAPTURE" );
184     mButtonCapture.SetParentOrigin( ParentOrigin::TOP_LEFT );
185     mButtonCapture.SetAnchorPoint( AnchorPoint::TOP_LEFT );
186     mButtonCapture.SetSize( stageSize.x / BUTTON_COUNT, BUTTON_HEIGHT );
187     mButtonCapture.SetPosition( (stageSize.x / BUTTON_COUNT)*3.0f, 0.0f );
188     mButtonCapture.ClickedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
189     mButtonArea.Add( mButtonCapture );
190
191     mButtonReset = PushButton::New();
192     mButtonReset.SetProperty( Toolkit::Button::Property::LABEL, "RESET" );
193     mButtonReset.SetParentOrigin( ParentOrigin::TOP_LEFT );
194     mButtonReset.SetAnchorPoint( AnchorPoint::TOP_LEFT );
195     mButtonReset.SetSize( stageSize.x / BUTTON_COUNT, BUTTON_HEIGHT );
196     mButtonReset.SetPosition( (stageSize.x / BUTTON_COUNT)*4.0f, 0.0f );
197     mButtonReset.ClickedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
198     mButtonArea.Add( mButtonReset );
199   }
200
201   void CreateContentAreas()
202   {
203     Stage stage = Stage::GetCurrent();
204     Vector2 stageSize = stage.GetSize();
205
206     float contentHeight( (stageSize.y - BUTTON_HEIGHT)/2.0f );
207
208     mTopContentArea = Actor::New();
209     mTopContentArea.SetSize( stageSize.x, contentHeight );
210     mTopContentArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
211     mTopContentArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
212     mTopContentArea.SetY( BUTTON_HEIGHT );
213     stage.Add( mTopContentArea );
214
215     mBottomContentArea = Actor::New();
216     mBottomContentArea.SetSize( stageSize.x, contentHeight );
217     mBottomContentArea.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
218     mBottomContentArea.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
219     stage.Add( mBottomContentArea );
220
221     mSourceActor = ImageView::New(JPG_FILENAME);
222     mSourceActor.SetParentOrigin( ParentOrigin::CENTER);
223     mSourceActor.SetAnchorPoint( AnchorPoint::CENTER );
224     mTopContentArea.Add( mSourceActor );
225
226     Animation animation = Animation::New(2.f);
227     Degree relativeRotationDegrees(90.0f);
228     Radian relativeRotationRadians(relativeRotationDegrees);
229     animation.AnimateTo( Property( mSourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(0.f, 0.5f));
230     animation.AnimateBy( Property( mSourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(0.5f, 0.5f));
231     animation.AnimateBy( Property( mSourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(1.f, 0.5f));
232     animation.AnimateBy( Property( mSourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(1.5f, 0.5f));
233     animation.SetLooping(true);
234     animation.Play();
235
236     TextLabel textLabel1 = TextLabel::New( "Image" );
237     textLabel1.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
238     textLabel1.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
239     mTopContentArea.Add( textLabel1 );
240
241     // Wait until button press before creating mOffscreenRenderTask
242
243     TextLabel textLabel2 = TextLabel::New( "Native Image" );
244     textLabel2.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
245     textLabel2.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
246     mBottomContentArea.Add( textLabel2 );
247   }
248
249   void SetupNativeImage()
250   {
251     if( ! mOffscreenRenderTask )
252     {
253       Stage stage = Stage::GetCurrent();
254       Vector2 stageSize = stage.GetSize();
255
256       float contentHeight( (stageSize.y - BUTTON_HEIGHT)/2.0f );
257       Vector2 imageSize( stageSize.x, contentHeight );
258
259       mNativeImageSourcePtr = NativeImageSource::New( imageSize.width, imageSize.height, NativeImageSource::COLOR_DEPTH_DEFAULT );
260       mNativeTexture = Texture::New( *mNativeImageSourcePtr );
261
262       mFrameBuffer = FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), FrameBuffer::Attachment::NONE );
263       mFrameBuffer.AttachColorTexture( mNativeTexture );
264
265       mCameraActor = CameraActor::New( imageSize );
266       mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
267       mCameraActor.SetParentOrigin( AnchorPoint::CENTER );
268       mTopContentArea.Add( mCameraActor );
269
270       RenderTaskList taskList = stage.GetRenderTaskList();
271       mOffscreenRenderTask = taskList.CreateTask();
272       mOffscreenRenderTask.SetSourceActor( mSourceActor );
273       mOffscreenRenderTask.SetClearColor( Color::WHITE );
274       mOffscreenRenderTask.SetClearEnabled( true );
275       mOffscreenRenderTask.SetCameraActor( mCameraActor );
276       mOffscreenRenderTask.GetCameraActor().SetInvertYAxis( true );
277       mOffscreenRenderTask.SetFrameBuffer( mFrameBuffer );
278     }
279
280     if( mRefreshAlways )
281     {
282       mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
283     }
284     else
285     {
286       mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
287     }
288   }
289
290   void SetupDisplayActor( bool show )
291   {
292     if( show )
293     {
294       if( ! mDisplayActor )
295       {
296         // Make sure we have something to display
297         SetupNativeImage();
298
299         mDisplayActor = Actor::New();
300         mDisplayActor.SetParentOrigin( ParentOrigin::CENTER );
301         mDisplayActor.SetAnchorPoint( AnchorPoint::CENTER );
302
303         Geometry geometry = DemoHelper::CreateTexturedQuad();
304
305         Shader shader = CreateShader( *mNativeImageSourcePtr );
306
307         Renderer renderer = Renderer::New( geometry, shader );
308
309         TextureSet textureSet = TextureSet::New();
310         textureSet.SetTexture( 0u, mNativeTexture );
311         renderer.SetTextures( textureSet );
312
313         mDisplayActor.AddRenderer( renderer );
314         mDisplayActor.SetSize( mNativeTexture.GetWidth(), mNativeTexture.GetHeight() );
315
316         mBottomContentArea.Add( mDisplayActor );
317       }
318     }
319     else
320     {
321       UnparentAndReset( mDisplayActor );
322     }
323   }
324
325   void Capture()
326   {
327     mRefreshAlways = false;
328     SetupNativeImage();
329
330     mOffscreenRenderTask.FinishedSignal().Connect( this, &NativeImageSourceController::DoCapture );
331   }
332
333   void DoCapture(RenderTask& task)
334   {
335     task.FinishedSignal().Disconnect( this, &NativeImageSourceController::DoCapture );
336
337     mNativeImageSourcePtr->EncodeToFile( CAPTURE_FILENAME );
338   }
339
340   void Reset()
341   {
342     SetupDisplayActor( false );
343
344     Stage stage = Stage::GetCurrent();
345     RenderTaskList taskList = stage.GetRenderTaskList();
346     taskList.RemoveTask( mOffscreenRenderTask );
347     mOffscreenRenderTask.Reset();
348     mCameraActor.Reset();
349
350     mFrameBuffer.Reset();
351     mNativeTexture.Reset();
352     mNativeImageSourcePtr.Reset();
353   }
354
355   bool OnButtonSelected( Toolkit::Button button )
356   {
357     Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( button );
358
359     if( pushButton == mButtonShow )
360     {
361       bool isSelected = mButtonShow.GetProperty( Toolkit::Button::Property::SELECTED ).Get<bool>();
362
363       SetupDisplayActor( isSelected );
364     }
365     else if( pushButton == mButtonRefreshAlways )
366     {
367       bool isSelected = mButtonRefreshAlways.GetProperty( Toolkit::Button::Property::SELECTED ).Get<bool>();
368
369       mRefreshAlways = isSelected;
370       SetupNativeImage();
371     }
372     else if( pushButton == mButtonRefreshOnce )
373     {
374       bool isSelected = mButtonRefreshAlways.GetProperty( Toolkit::Button::Property::SELECTED ).Get<bool>();
375
376       if( isSelected )
377       {
378         mButtonRefreshAlways.SetProperty( Button::Property::SELECTED, false );
379       }
380
381       mRefreshAlways = false;
382       SetupNativeImage();
383     }
384     else if( pushButton == mButtonCapture )
385     {
386       Capture();
387     }
388     else if( pushButton == mButtonReset )
389     {
390       Reset();
391     }
392
393     return true;
394   }
395
396   void OnKeyEvent(const KeyEvent& event)
397   {
398     if(event.state == KeyEvent::Down)
399     {
400       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
401       {
402         mApplication.Quit();
403       }
404     }
405   }
406
407 private:
408
409   Application&  mApplication;
410
411   Layer mButtonArea;
412   Actor mTopContentArea;
413   Actor mBottomContentArea;
414
415   PushButton mButtonShow;
416   PushButton mButtonRefreshAlways;
417   PushButton mButtonRefreshOnce;
418   PushButton mButtonCapture;
419   PushButton mButtonReset;
420
421   Actor mSourceActor;
422
423   NativeImageSourcePtr mNativeImageSourcePtr;
424   Texture              mNativeTexture;
425   FrameBuffer          mFrameBuffer;
426
427   RenderTask mOffscreenRenderTask;
428   CameraActor mCameraActor;
429
430   Actor mDisplayActor;
431
432   bool mRefreshAlways;
433 };
434
435 void RunTest( Application& application )
436 {
437   NativeImageSourceController test( application );
438
439   application.MainLoop();
440 }
441
442 // Entry point for Linux & Tizen applications
443 //
444 int DALI_EXPORT_API main( int argc, char **argv )
445 {
446   Application application = Application::New( &argc, &argv );
447
448   RunTest( application );
449
450   return 0;
451 }