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