3aa55dac0441cc35b9f8dd37bdfbe037545886d5
[platform/core/uifw/dali-demo.git] / examples / rendering-textured-cube / rendering-textured-cube.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 #include <dali/dali.h>
19 #include <dali-toolkit/dali-toolkit.h>
20
21 using namespace Dali;
22 using namespace Toolkit;
23
24 namespace
25 {
26
27 /*
28  * Vertex shader
29  */
30 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
31 attribute mediump vec3 aPosition;\n // DALi shader builtin
32 attribute mediump vec2 aTexCoord;\n // DALi shader builtin
33 uniform   mediump mat4 uMvpMatrix;\n // DALi shader builtin
34 uniform   mediump vec3 uSize;\n // DALi shader builtin
35 \n
36 varying mediump vec2 vTexCoord;\n
37 void main()\n
38 {\n
39   mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n
40   vertexPosition.xyz *= uSize;\n
41   vTexCoord = aTexCoord;\n
42   gl_Position = uMvpMatrix * vertexPosition;\n
43 }\n
44 );
45
46 /*
47  * Fragment shader
48  */
49 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
50 uniform sampler2D uTexture;\n
51 \n
52 varying mediump vec2 vTexCoord;\n
53 void main()\n
54 {\n
55   mediump vec4 texColor = texture2D( uTexture, vTexCoord );\n
56   gl_FragColor = texColor;\n
57 }\n
58 );
59
60 const char* TEXTURE_URL = DEMO_IMAGE_DIR "wood.png";
61
62 }
63
64 // This example shows how to create textured cube
65 //
66 class TexturedCubeController : public ConnectionTracker
67 {
68 public:
69
70   TexturedCubeController( Application& application )
71   : mApplication( application )
72   {
73     // Connect to the Application's Init signal
74     mApplication.InitSignal().Connect( this, &TexturedCubeController::Create );
75   }
76
77   ~TexturedCubeController()
78   {
79     // Nothing to do here;
80   }
81
82   // The Init signal is received once (only) during the Application lifetime
83   void Create( Application& application )
84   {
85     // Get a handle to the window
86     Window window = application.GetWindow();
87     window.SetBackgroundColor( Color::WHITE );
88
89     // Step 1. Create shader
90     CreateCubeShader();
91
92     // Step 2. Load a texture
93     CreateTexture();
94
95     // Step 3. Prepare geometry
96     CreateCubeGeometry();
97
98     // Step 4. Create a renderer
99     CreateRenderer();
100
101     // Step 5. Create an Actor
102     CreateActor();
103
104     // Step 6. Play animation to rotate the cube
105     PlayAnimation();
106
107     // Respond to a click anywhere on the window
108     window.GetRootLayer().TouchSignal().Connect( this, &TexturedCubeController::OnTouch );
109
110     // Respond to key events
111     window.KeyEventSignal().Connect( this, &TexturedCubeController::OnKeyEvent );
112   }
113
114   bool OnTouch( Actor actor, const TouchEvent& touch )
115   {
116     // quit the application
117     mApplication.Quit();
118     return true;
119   }
120
121   /**
122    * @brief Called when any key event is received
123    *
124    * Will use this to quit the application if Back or the Escape key is received
125    * @param[in] event The key event information
126    */
127   void OnKeyEvent( const KeyEvent& event )
128   {
129     if( event.state == KeyEvent::Down )
130     {
131       if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
132       {
133         mApplication.Quit();
134       }
135     }
136   }
137
138   /**
139    * @brief CreateCubeGeometry
140    * This function creates a cube geometry including texture coordinates.
141    * Also it demonstrates using the indexed draw feature by setting an index array.
142    */
143   void CreateCubeGeometry()
144   {
145     struct Vertex
146     {
147       Vector3 aPosition;
148       Vector2 aTexCoord;
149     };
150
151     Vertex vertices[] = {
152       { Vector3(  1.0f,-1.0f,-1.0f ), Vector2( 1.0, 1.0 ) },
153       { Vector3( -1.0f, 1.0f,-1.0f ), Vector2( 0.0, 0.0 ) },
154       { Vector3(  1.0f, 1.0f,-1.0f ), Vector2( 0.0, 1.0 ) },
155       { Vector3( -1.0f, 1.0f, 1.0f ), Vector2( 1.0, 1.0 ) },
156       { Vector3(  1.0f,-1.0f, 1.0f ), Vector2( 0.0, 0.0 ) },
157       { Vector3(  1.0f, 1.0f, 1.0f ), Vector2( 0.0, 1.0 ) },
158       { Vector3(  1.0f, 1.0f, 1.0f ), Vector2( 1.0, 1.0 ) },
159       { Vector3(  1.0f,-1.0f,-1.0f ), Vector2( 0.0, 0.0 ) },
160       { Vector3(  1.0f, 1.0f,-1.0f ), Vector2( 0.0, 1.0 ) },
161       { Vector3(  1.0f,-1.0f, 1.0f ), Vector2( 1.0, 1.0 ) },
162       { Vector3( -1.0f,-1.0f,-1.0f ), Vector2( 0.0, 0.0 ) },
163       { Vector3(  1.0f,-1.0f,-1.0f ), Vector2( 0.0, 1.0 ) },
164       { Vector3( -1.0f,-1.0f,-1.0f ), Vector2( 1.0, 1.0 ) },
165       { Vector3( -1.0f, 1.0f, 1.0f ), Vector2( 0.0, 0.0 ) },
166       { Vector3( -1.0f, 1.0f,-1.0f ), Vector2( 0.0, 1.0 ) },
167       { Vector3(  1.0f, 1.0f,-1.0f ), Vector2( 1.0, 1.0 ) },
168       { Vector3( -1.0f, 1.0f, 1.0f ), Vector2( 0.0, 0.0 ) },
169       { Vector3(  1.0f, 1.0f, 1.0f ), Vector2( 0.0, 1.0 ) },
170       { Vector3(  1.0f,-1.0f,-1.0f ), Vector2( 1.0, 1.0 ) },
171       { Vector3( -1.0f,-1.0f,-1.0f ), Vector2( 1.0, 0.0 ) },
172       { Vector3( -1.0f, 1.0f,-1.0f ), Vector2( 0.0, 0.0 ) },
173       { Vector3( -1.0f, 1.0f, 1.0f ), Vector2( 1.0, 1.0 ) },
174       { Vector3( -1.0f,-1.0f, 1.0f ), Vector2( 1.0, 0.0 ) },
175       { Vector3(  1.0f,-1.0f, 1.0f ), Vector2( 0.0, 0.0 ) },
176       { Vector3(  1.0f, 1.0f, 1.0f ), Vector2( 1.0, 1.0 ) },
177       { Vector3(  1.0f,-1.0f, 1.0f ), Vector2( 1.0, 0.0 ) },
178       { Vector3(  1.0f,-1.0f,-1.0f ), Vector2( 0.0, 0.0 ) },
179       { Vector3(  1.0f,-1.0f, 1.0f ), Vector2( 1.0, 1.0 ) },
180       { Vector3( -1.0f,-1.0f, 1.0f ), Vector2( 1.0, 0.0 ) },
181       { Vector3( -1.0f,-1.0f,-1.0f ), Vector2( 0.0, 0.0 ) },
182       { Vector3( -1.0f,-1.0f,-1.0f ), Vector2( 1.0, 1.0 ) },
183       { Vector3( -1.0f,-1.0f, 1.0f ), Vector2( 1.0, 0.0 ) },
184       { Vector3( -1.0f, 1.0f, 1.0f ), Vector2( 0.0, 0.0 ) },
185       { Vector3(  1.0f, 1.0f,-1.0f ), Vector2( 1.0, 1.0 ) },
186       { Vector3( -1.0f, 1.0f,-1.0f ), Vector2( 1.0, 0.0 ) },
187       { Vector3( -1.0f, 1.0f, 1.0f ), Vector2( 0.0, 0.0 ) },
188     };
189
190     VertexBuffer vertexBuffer = VertexBuffer::New( Property::Map()
191                                                    .Add( "aPosition", Property::VECTOR3 )
192                                                    .Add( "aTexCoord", Property::VECTOR2 ) );
193     vertexBuffer.SetData( vertices, sizeof(vertices) / sizeof(Vertex) );
194
195     // create indices
196     const unsigned short INDEX_CUBE[] = {
197       2, 1, 0,
198       5, 4, 3,
199       8, 7, 6,
200       11, 10, 9,
201       14, 13, 12,
202       17, 16, 15,
203       20, 19, 18,
204       23, 22, 21,
205       26, 25, 24,
206       29, 28, 27,
207       32, 31, 30,
208       35, 34, 33
209     };
210     mGeometry = Geometry::New();
211     mGeometry.AddVertexBuffer( vertexBuffer );
212     mGeometry.SetIndexBuffer( INDEX_CUBE,
213                               sizeof(INDEX_CUBE)/sizeof(INDEX_CUBE[0]) );
214     mGeometry.SetType( Geometry::TRIANGLES );
215   }
216
217   /**
218    * Creates a shader using inlined variable VERTEX_SHADER and FRAGMENT_SHADER
219    *
220    * Shaders are very basic and all they do is transforming vertices and sampling
221    * a texture.
222    */
223   void CreateCubeShader()
224   {
225     mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
226   }
227
228   /**
229    * This function loads a pixel data from a file. In order to load it we use SyncImageLoader utility.
230    * If loading succeeds returned PixelData object can be used to create a texture.
231    * Texture must be uploaded. In the end the texture must be set on the TextureSet object.
232    */
233   void CreateTexture()
234   {
235     // Load image from file
236     PixelData pixels = SyncImageLoader::Load( TEXTURE_URL );
237
238     Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
239     texture.Upload( pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight() );
240
241     // create TextureSet
242     mTextureSet = TextureSet::New();
243     mTextureSet.SetTexture( 0, texture );
244   }
245
246   /**
247    * Function creates renderer. It turns on depth test and depth write.
248    */
249   void CreateRenderer()
250   {
251     mRenderer = Renderer::New( mGeometry, mShader );
252     mRenderer.SetTextures( mTextureSet );
253
254     // Face culling is enabled to hide the backwards facing sides of the cube
255     // This is sufficient to render a single object; for more complex scenes depth-testing might be required
256     mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
257   }
258
259   /**
260    * Creates new actor and attaches renderer.
261    */
262   void CreateActor()
263   {
264     Window window = mApplication.GetWindow();
265
266     float quarterWindowWidth = window.GetSize().GetWidth() * 0.25f;
267     mActor = Actor::New();
268     mActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
269     mActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
270     mActor.SetProperty( Actor::Property::POSITION, Vector3( 0.0f, 0.0f, 0.0f ) );
271     mActor.SetProperty( Actor::Property::SIZE, Vector3( quarterWindowWidth, quarterWindowWidth, quarterWindowWidth ) );
272     mActor.AddRenderer( mRenderer );
273     window.Add( mActor );
274   }
275
276   /**
277    * Plays animation
278    */
279   void PlayAnimation()
280   {
281     mAnimation = Animation::New( 5.0f );
282     mAnimation.SetLooping( true );
283     mAnimation.AnimateBy( Property( mActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 )), Vector3::ZAXIS ) );
284     mAnimation.AnimateBy( Property( mActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 )), Vector3::YAXIS ) );
285     mAnimation.AnimateBy( Property( mActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 )), Vector3::XAXIS ) );
286     mAnimation.Play();
287   }
288
289 private:
290   Application&  mApplication;
291
292   Renderer mRenderer;
293   Shader mShader;
294   Geometry mGeometry;
295   TextureSet mTextureSet;
296   Actor mActor;
297   Animation mAnimation;
298 };
299
300 int DALI_EXPORT_API main( int argc, char **argv )
301 {
302   Application application = Application::New( &argc, &argv );
303   TexturedCubeController test( application );
304   application.MainLoop();
305   return 0;
306 }