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