828bef1c8bdd71bc571fc3a0b2756f5e87f7c790
[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 /**
36  * @brief Creates a shader used to render a native image
37  * @param[in] nativeImageInterface The native image interface
38  * @return A shader to render the native image
39  */
40 Shader CreateShader( NativeImageInterface& nativeImageInterface )
41 {
42   static const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
43
44   static const char* VERTEX_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
45       attribute mediump vec2 aPosition;\n
46       attribute mediump vec2 aTexCoord;\n
47       uniform mediump mat4 uMvpMatrix;\n
48       uniform mediump vec3 uSize;\n
49       varying mediump vec2 vTexCoord;\n
50       void main()\n
51       {\n
52         vec4 position = vec4(aPosition,0.0,1.0)*vec4(uSize,1.0);\n
53         gl_Position = uMvpMatrix * position;\n
54         vTexCoord = aTexCoord;\n
55       }\n
56   );
57
58   static const char* FRAGMENT_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
59       uniform lowp vec4 uColor;\n
60       uniform sampler2D sTexture;\n
61       varying mediump vec2 vTexCoord;\n
62
63       void main()\n
64       {\n
65         gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
66       }\n
67   );
68
69   NativeImageInterface::Extension* extension( nativeImageInterface.GetExtension() );
70   if( extension )
71   {
72     std::string fragmentShader;
73
74     //Get custom fragment shader prefix
75     const char* fragmentPreFix = extension->GetCustomFragmentPreFix();
76     if( fragmentPreFix )
77     {
78       fragmentShader = fragmentPreFix;
79       fragmentShader += FRAGMENT_SHADER_TEXTURE;
80     }
81     else
82     {
83       fragmentShader = FRAGMENT_SHADER_TEXTURE;
84     }
85
86     //Get custom sampler type name
87     const char* customSamplerTypename = extension->GetCustomSamplerTypename();
88     if( customSamplerTypename )
89     {
90       fragmentShader.replace( fragmentShader.find( DEFAULT_SAMPLER_TYPENAME ), strlen(DEFAULT_SAMPLER_TYPENAME), customSamplerTypename );
91     }
92
93     return Shader::New( VERTEX_SHADER_TEXTURE, fragmentShader );
94   }
95   else
96   {
97     return Shader::New( VERTEX_SHADER_TEXTURE, FRAGMENT_SHADER_TEXTURE );
98   }
99 }
100
101 /**
102  * @brief Creates an actor to render a native image
103  * @param[in] texture The texture creates from a native image
104  * @param[in] nativeImageInterface The native image interface used to create the texture
105  * @return An actor that renders the texture
106  */
107 Actor CreateNativeActor( Texture texture, NativeImageInterface& nativeImageInterface )
108 {
109   Actor actor = Actor::New();
110   Geometry geometry = DemoHelper::CreateTexturedQuad();
111   Shader shader = CreateShader(nativeImageInterface);
112   Renderer renderer = Renderer::New( geometry, shader );
113   TextureSet textureSet = TextureSet::New();
114   textureSet.SetTexture( 0u, texture );
115   renderer.SetTextures( textureSet );
116
117   actor.AddRenderer( renderer );
118   actor.SetSize( texture.GetWidth(), texture.GetHeight() );
119   return actor;
120 }
121
122 const std::string JPG_FILENAME = DEMO_IMAGE_DIR "gallery-medium-4.jpg";
123 }
124
125 // This example shows how to create and use a NativeImageSource as the target of the render task.
126 //
127 class NativeImageSourceController : public ConnectionTracker
128 {
129 public:
130
131   NativeImageSourceController( Application& application )
132   : mApplication( application )
133   {
134     // Connect to the Application's Init signal
135     mApplication.InitSignal().Connect( this, &NativeImageSourceController::Create );
136   }
137
138   ~NativeImageSourceController()
139   {
140     // Nothing to do here;
141   }
142
143   // The Init signal is received once (only) during the Application lifetime
144   void Create( Application& application )
145   {
146     // Get a handle to the stage
147     Stage stage = Stage::GetCurrent();
148     stage.SetBackgroundColor( Color::WHITE );
149
150     // Hide the indicator bar
151     application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
152
153     stage.KeyEventSignal().Connect(this, &NativeImageSourceController::OnKeyEvent);
154
155     mButtonRefreshAlways = PushButton::New();
156     mButtonRefreshAlways.SetProperty( Button::Property::TOGGLABLE, true );
157     mButtonRefreshAlways.SetProperty( Button::Property::SELECTED, true );
158     mButtonRefreshAlways.SetLabelText( "Refresh ALWAYS" );
159     mButtonRefreshAlways.SetParentOrigin( ParentOrigin::TOP_LEFT );
160     mButtonRefreshAlways.SetAnchorPoint( AnchorPoint::TOP_LEFT );
161     mButtonRefreshAlways.StateChangedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
162     stage.Add( mButtonRefreshAlways );
163
164     mButtonRefreshOnce = PushButton::New();
165     mButtonRefreshOnce.SetLabelText( "Refresh ONCE" );
166     mButtonRefreshOnce.SetParentOrigin( ParentOrigin::TOP_RIGHT );
167     mButtonRefreshOnce.SetAnchorPoint( AnchorPoint::TOP_RIGHT );
168     mButtonRefreshOnce.ClickedSignal().Connect( this, &NativeImageSourceController::OnButtonSelected );
169     stage.Add( mButtonRefreshOnce);
170
171     CreateScene();
172   }
173
174   bool CreateScene()
175   {
176     Stage stage = Stage::GetCurrent();
177     Vector2 stageSize = stage.GetSize();
178
179     float buttonHeight = 100.f;
180     mButtonRefreshAlways.SetSize( stageSize.x / 2.f, buttonHeight );
181     mButtonRefreshOnce.SetSize( stageSize.x / 2.f, buttonHeight );
182
183     Vector2 imageSize( stageSize.x, (stageSize.y-buttonHeight)/2.f );
184
185     // Create the native image source
186     NativeImageSourcePtr nativeImageSourcePtr = NativeImageSource::New( imageSize.width, imageSize.height, NativeImageSource::COLOR_DEPTH_DEFAULT );
187
188     // Create a image view as source actor to be renderer to the native image source
189     Actor sourceActor = ImageView::New(JPG_FILENAME);
190     sourceActor.SetParentOrigin( ParentOrigin::CENTER);
191     sourceActor.SetAnchorPoint( AnchorPoint::CENTER );
192     sourceActor.SetY( - (imageSize.height-buttonHeight)/2.f );
193     stage.Add( sourceActor );
194
195     Animation animation = Animation::New(2.f);
196     Degree relativeRotationDegrees(90.0f);
197     Radian relativeRotationRadians(relativeRotationDegrees);
198     animation.AnimateTo( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(0.f, 0.5f));
199     animation.AnimateBy( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(0.5f, 0.5f));
200     animation.AnimateBy( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(1.f, 0.5f));
201     animation.AnimateBy( Property( sourceActor, Actor::Property::ORIENTATION ), Quaternion( relativeRotationRadians, Vector3::ZAXIS ), AlphaFunction::LINEAR, TimePeriod(1.5f, 0.5f));
202     animation.SetLooping(true);
203     animation.Play();
204
205     // create a offscreen renderer task to render content into the native image source
206     Texture nativeTexture = Texture::New( *nativeImageSourcePtr );
207     // Create a FrameBuffer object with no default attachments.
208     FrameBuffer targetBuffer = FrameBuffer::New( nativeTexture.GetWidth(), nativeTexture.GetHeight(), FrameBuffer::Attachment::NONE );
209     // Add a color attachment to the FrameBuffer object.
210     targetBuffer.AttachColorTexture( nativeTexture );
211
212     CameraActor cameraActor = CameraActor::New(imageSize);
213     cameraActor.SetParentOrigin(ParentOrigin::TOP_CENTER);
214     cameraActor.SetParentOrigin( AnchorPoint::TOP_CENTER );
215     cameraActor.SetY( buttonHeight + imageSize.height/2.f );
216     stage.Add(cameraActor);
217
218     RenderTaskList taskList = stage.GetRenderTaskList();
219     mOffscreenRenderTask = taskList.CreateTask();
220     mOffscreenRenderTask.SetSourceActor( sourceActor );
221     mOffscreenRenderTask.SetClearColor( Color::WHITE );
222     mOffscreenRenderTask.SetClearEnabled(true);
223     mOffscreenRenderTask.SetCameraActor(cameraActor);
224     mOffscreenRenderTask.GetCameraActor().SetInvertYAxis(true);
225     mOffscreenRenderTask.SetFrameBuffer( targetBuffer );
226     mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
227
228     // Display the native image on the screen
229     Actor nativeImageActor = CreateNativeActor( nativeTexture, *nativeImageSourcePtr );
230     nativeImageActor.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
231     nativeImageActor.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
232     stage.Add( nativeImageActor );
233
234     TextLabel textLabel1 = TextLabel::New( "Resource Image" );
235     textLabel1.SetParentOrigin( ParentOrigin::TOP_CENTER );
236     textLabel1.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
237     nativeImageActor.Add( textLabel1 );
238
239     TextLabel textLabel2 = TextLabel::New( "Native Image" );
240     textLabel2.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
241     textLabel2.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
242     nativeImageActor.Add( textLabel2 );
243
244     return false;
245   }
246
247   bool OnButtonSelected( Toolkit::Button button )
248   {
249     bool isSelected = mButtonRefreshAlways.GetProperty( Toolkit::Button::Property::SELECTED ).Get<bool>();
250
251     Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( button );
252     if( pushButton == mButtonRefreshAlways )
253     {
254       if( isSelected )
255       {
256         mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
257       }
258       else
259       {
260         mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
261       }
262     }
263     else if( pushButton == mButtonRefreshOnce )
264     {
265       if( isSelected )
266       {
267         mButtonRefreshAlways.SetProperty( Button::Property::SELECTED, false );
268       }
269       mOffscreenRenderTask.SetRefreshRate( RenderTask::REFRESH_ONCE );
270     }
271
272     return true;
273   }
274
275   void OnKeyEvent(const KeyEvent& event)
276   {
277     if(event.state == KeyEvent::Down)
278     {
279       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
280       {
281         mApplication.Quit();
282       }
283     }
284   }
285
286 private:
287   Application&  mApplication;
288   RenderTask mOffscreenRenderTask;
289   PushButton mButtonRefreshAlways;
290   PushButton mButtonRefreshOnce;
291
292 };
293
294 void RunTest( Application& application )
295 {
296   NativeImageSourceController test( application );
297
298   application.MainLoop();
299 }
300
301 // Entry point for Linux & Tizen applications
302 //
303 int DALI_EXPORT_API main( int argc, char **argv )
304 {
305   Application application = Application::New( &argc, &argv );
306
307   RunTest( application );
308
309   return 0;
310 }