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