Convert shaders in dali-demo to use shader compilation tool
[platform/core/uifw/dali-demo.git] / examples / rendering-skybox / rendering-skybox.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 #include "look-camera.h"
22 #include "generated/rendering-skybox-vert.h"
23 #include "generated/rendering-skybox-frag.h"
24 #include "generated/rendering-skybox-cube-vert.h"
25 #include "generated/rendering-skybox-cube-frag.h"
26
27 using namespace Dali;
28 using namespace Toolkit;
29
30 namespace
31 {
32
33 const float   CAMERA_DEFAULT_FOV(60.0f);
34 const float   CAMERA_DEFAULT_NEAR(0.1f);
35 const float   CAMERA_DEFAULT_FAR(1000.0f);
36 const Vector3 CAMERA_DEFAULT_POSITION(0.0f, 0.0f, 100.0f);
37
38 const char* TEXTURE_URL = DEMO_IMAGE_DIR "wood.png";
39
40 const unsigned int SKYBOX_FACE_COUNT  = 6;
41 const unsigned int SKYBOX_FACE_WIDTH  = 2048;
42 const unsigned int SKYBOX_FACE_HEIGHT = 2048;
43
44 /*
45  * Credit to Joey do Vries for the following cubemap images
46  * Take from git://github.com/JoeyDeVries/LearnOpenGL.git
47  * The images are licensed under the terms of the CC BY 4.0 license:
48  * https://creativecommons.org/licenses/by/4.0/
49  */
50 const char* SKYBOX_FACES[SKYBOX_FACE_COUNT] =
51   {
52     DEMO_IMAGE_DIR "lake_right.jpg",
53     DEMO_IMAGE_DIR "lake_left.jpg",
54     DEMO_IMAGE_DIR "lake_top.jpg",
55     DEMO_IMAGE_DIR "lake_bottom.jpg",
56     DEMO_IMAGE_DIR "lake_back.jpg",
57     DEMO_IMAGE_DIR "lake_front.jpg"};
58
59 } // namespace
60
61 // This example shows how to create a skybox
62 //
63 // Recommended screen size on desktop: 1280x720
64 //
65 class TexturedCubeController : public ConnectionTracker
66 {
67 public:
68   TexturedCubeController(Application& application)
69   : mApplication(application)
70   {
71     // Connect to the Application's Init signal
72     mApplication.InitSignal().Connect(this, &TexturedCubeController::Create);
73   }
74
75   ~TexturedCubeController()
76   {
77     // Nothing to do here;
78   }
79
80   // The Init signal is received once (only) during the Application lifetime
81   void Create(Application& application)
82   {
83     // Get a handle to the window
84     Window window = application.GetWindow();
85     window.SetBackgroundColor(Color::WHITE);
86
87     // Step 1. Setup camera
88     SetupCamera();
89
90     // Step 2. Create shaders
91     CreateShaders();
92
93     // Step 3. Create geometry
94     CreateCubeGeometry();
95     CreateSkyboxGeometry();
96
97     // Step 4. Display first a cube at the world origin.
98     //         The write on the depth buffer is enabled.
99     DisplayCube();
100
101     // Step 5. Display last the skybox surrounding the camera.
102     //         The depth test is enabled, the shader sets 1.0, which is the maximum depth and
103     //         the depth function is set to LESS or EQUAL so the fragment shader will run only
104     //         in those pixels that any other object has written on them.
105     DisplaySkybox();
106
107     // Step 6. Play animation to rotate the cube
108     PlayAnimation();
109
110     // Respond to key events
111     window.KeyEventSignal().Connect(this, &TexturedCubeController::OnKeyEvent);
112   }
113
114   /**
115    * @brief Called when any key event is received
116    *
117    * Will use this to quit the application if Back or the Escape key is received
118    * @param[in] event The key event information
119    */
120   void OnKeyEvent(const KeyEvent& event)
121   {
122     if(event.GetState() == KeyEvent::DOWN)
123     {
124       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
125       {
126         mApplication.Quit();
127       }
128     }
129   }
130
131   /**
132    * @brief Setup a perspective camera pointing in the negative Z direction
133    */
134   void SetupCamera()
135   {
136     Window window = mApplication.GetWindow();
137
138     RenderTask renderTask = window.GetRenderTaskList().GetTask(0);
139     renderTask.SetCullMode(false); // avoid frustum culling affecting the skybox
140
141     mCamera.Initialise(window, CAMERA_DEFAULT_POSITION, CAMERA_DEFAULT_FOV, CAMERA_DEFAULT_NEAR, CAMERA_DEFAULT_FAR);
142   }
143
144   /**
145    * Creates a shader using inlined variable VERTEX_SHADER and FRAGMENT_SHADER
146    *
147    * Shaders are very basic and all they do is transforming vertices and sampling
148    * a texture.
149    */
150   void CreateShaders()
151   {
152     mShaderCube   = Shader::New(SHADER_RENDERING_SKYBOX_CUBE_VERT, SHADER_RENDERING_SKYBOX_CUBE_FRAG);
153     mShaderSkybox = Shader::New(SHADER_RENDERING_SKYBOX_CUBE_VERT, SHADER_RENDERING_SKYBOX_CUBE_FRAG);
154   }
155
156   /**
157    * @brief CreateCubeGeometry
158    * This function creates a cube geometry including texture coordinates.
159    * Also it demonstrates using the indexed draw feature by setting an index array.
160    */
161   void CreateCubeGeometry()
162   {
163     struct Vertex
164     {
165       Vector3 aPosition;
166       Vector2 aTexCoord;
167     };
168
169     Vertex vertices[] = {
170       {Vector3(1.0f, -1.0f, -1.0f), Vector2(1.0, 1.0)},
171       {Vector3(-1.0f, 1.0f, -1.0f), Vector2(0.0, 0.0)},
172       {Vector3(1.0f, 1.0f, -1.0f), Vector2(0.0, 1.0)},
173       {Vector3(-1.0f, 1.0f, 1.0f), Vector2(1.0, 1.0)},
174       {Vector3(1.0f, -1.0f, 1.0f), Vector2(0.0, 0.0)},
175       {Vector3(1.0f, 1.0f, 1.0f), Vector2(0.0, 1.0)},
176       {Vector3(1.0f, 1.0f, 1.0f), Vector2(1.0, 1.0)},
177       {Vector3(1.0f, -1.0f, -1.0f), Vector2(0.0, 0.0)},
178       {Vector3(1.0f, 1.0f, -1.0f), Vector2(0.0, 1.0)},
179       {Vector3(1.0f, -1.0f, 1.0f), Vector2(1.0, 1.0)},
180       {Vector3(-1.0f, -1.0f, -1.0f), Vector2(0.0, 0.0)},
181       {Vector3(1.0f, -1.0f, -1.0f), Vector2(0.0, 1.0)},
182       {Vector3(-1.0f, -1.0f, -1.0f), Vector2(1.0, 1.0)},
183       {Vector3(-1.0f, 1.0f, 1.0f), Vector2(0.0, 0.0)},
184       {Vector3(-1.0f, 1.0f, -1.0f), Vector2(0.0, 1.0)},
185       {Vector3(1.0f, 1.0f, -1.0f), Vector2(1.0, 1.0)},
186       {Vector3(-1.0f, 1.0f, 1.0f), Vector2(0.0, 0.0)},
187       {Vector3(1.0f, 1.0f, 1.0f), Vector2(0.0, 1.0)},
188       {Vector3(1.0f, -1.0f, -1.0f), Vector2(1.0, 1.0)},
189       {Vector3(-1.0f, -1.0f, -1.0f), Vector2(1.0, 0.0)},
190       {Vector3(-1.0f, 1.0f, -1.0f), Vector2(0.0, 0.0)},
191       {Vector3(-1.0f, 1.0f, 1.0f), Vector2(1.0, 1.0)},
192       {Vector3(-1.0f, -1.0f, 1.0f), Vector2(1.0, 0.0)},
193       {Vector3(1.0f, -1.0f, 1.0f), Vector2(0.0, 0.0)},
194       {Vector3(1.0f, 1.0f, 1.0f), Vector2(1.0, 1.0)},
195       {Vector3(1.0f, -1.0f, 1.0f), Vector2(1.0, 0.0)},
196       {Vector3(1.0f, -1.0f, -1.0f), Vector2(0.0, 0.0)},
197       {Vector3(1.0f, -1.0f, 1.0f), Vector2(1.0, 1.0)},
198       {Vector3(-1.0f, -1.0f, 1.0f), Vector2(1.0, 0.0)},
199       {Vector3(-1.0f, -1.0f, -1.0f), Vector2(0.0, 0.0)},
200       {Vector3(-1.0f, -1.0f, -1.0f), Vector2(1.0, 1.0)},
201       {Vector3(-1.0f, -1.0f, 1.0f), Vector2(1.0, 0.0)},
202       {Vector3(-1.0f, 1.0f, 1.0f), Vector2(0.0, 0.0)},
203       {Vector3(1.0f, 1.0f, -1.0f), Vector2(1.0, 1.0)},
204       {Vector3(-1.0f, 1.0f, -1.0f), Vector2(1.0, 0.0)},
205       {Vector3(-1.0f, 1.0f, 1.0f), Vector2(0.0, 0.0)},
206     };
207
208     VertexBuffer vertexBuffer = VertexBuffer::New(Property::Map()
209                                                     .Add("aPosition", Property::VECTOR3)
210                                                     .Add("aTexCoord", Property::VECTOR2));
211     vertexBuffer.SetData(vertices, sizeof(vertices) / sizeof(Vertex));
212
213     // create indices
214     const unsigned short INDEX_CUBE[] = {
215       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};
216
217     mGeometry = Geometry::New();
218     mGeometry.AddVertexBuffer(vertexBuffer);
219     mGeometry.SetIndexBuffer(INDEX_CUBE,
220                              sizeof(INDEX_CUBE) / sizeof(INDEX_CUBE[0]));
221     mGeometry.SetType(Geometry::TRIANGLES);
222   }
223
224   /**
225    * @brief CreateCubeGeometry
226    * This function creates a cube geometry including texture coordinates.
227    * Also it demonstrates using the indexed draw feature by setting an index array.
228    */
229   void CreateSkyboxGeometry()
230   {
231     struct Vertex
232     {
233       Vector3 aPosition;
234     };
235
236     Vertex skyboxVertices[] = {
237       // back
238       {Vector3(-1.0f, 1.0f, -1.0f)},
239       {Vector3(-1.0f, -1.0f, -1.0f)},
240       {Vector3(1.0f, -1.0f, -1.0f)},
241       {Vector3(1.0f, -1.0f, -1.0f)},
242       {Vector3(1.0f, 1.0f, -1.0f)},
243       {Vector3(-1.0f, 1.0f, -1.0f)},
244
245       // left
246       {Vector3(-1.0f, -1.0f, 1.0f)},
247       {Vector3(-1.0f, -1.0f, -1.0f)},
248       {Vector3(-1.0f, 1.0f, -1.0f)},
249       {Vector3(-1.0f, 1.0f, -1.0f)},
250       {Vector3(-1.0f, 1.0f, 1.0f)},
251       {Vector3(-1.0f, -1.0f, 1.0f)},
252
253       // right
254       {Vector3(1.0f, -1.0f, -1.0f)},
255       {Vector3(1.0f, -1.0f, 1.0f)},
256       {Vector3(1.0f, 1.0f, 1.0f)},
257       {Vector3(1.0f, 1.0f, 1.0f)},
258       {Vector3(1.0f, 1.0f, -1.0f)},
259       {Vector3(1.0f, -1.0f, -1.0f)},
260
261       // front
262       {Vector3(-1.0f, -1.0f, 1.0f)},
263       {Vector3(-1.0f, 1.0f, 1.0f)},
264       {Vector3(1.0f, 1.0f, 1.0f)},
265       {Vector3(1.0f, 1.0f, 1.0f)},
266       {Vector3(1.0f, -1.0f, 1.0f)},
267       {Vector3(-1.0f, -1.0f, 1.0f)},
268
269       // botton
270       {Vector3(-1.0f, 1.0f, -1.0f)},
271       {Vector3(1.0f, 1.0f, -1.0f)},
272       {Vector3(1.0f, 1.0f, 1.0f)},
273       {Vector3(1.0f, 1.0f, 1.0f)},
274       {Vector3(-1.0f, 1.0f, 1.0f)},
275       {Vector3(-1.0f, 1.0f, -1.0f)},
276
277       // top
278       {Vector3(-1.0f, -1.0f, -1.0f)},
279       {Vector3(-1.0f, -1.0f, 1.0f)},
280       {Vector3(1.0f, -1.0f, -1.0f)},
281       {Vector3(1.0f, -1.0f, -1.0f)},
282       {Vector3(-1.0f, -1.0f, 1.0f)},
283       {Vector3(1.0f, -1.0f, 1.0f)}};
284
285     VertexBuffer vertexBuffer = VertexBuffer::New(Property::Map()
286                                                     .Add("aPosition", Property::VECTOR3));
287     vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
288
289     mSkyboxGeometry = Geometry::New();
290     mSkyboxGeometry.AddVertexBuffer(vertexBuffer);
291     mSkyboxGeometry.SetType(Geometry::TRIANGLES);
292   }
293
294   /**
295    * Display a cube at the world origin
296    */
297   void DisplayCube()
298   {
299     // Load image from file
300     PixelData pixels = SyncImageLoader::Load(TEXTURE_URL);
301
302     Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
303     texture.Upload(pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight());
304
305     // create TextureSet
306     mTextureSet = TextureSet::New();
307     mTextureSet.SetTexture(0, texture);
308
309     mRenderer = Renderer::New(mGeometry, mShaderCube);
310     mRenderer.SetTextures(mTextureSet);
311     mRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 1.0f);
312
313     // A further optimization would be to enable debug testing instead
314     mRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
315
316     // Enables the write on the depth buffer.
317     mRenderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON);
318
319     mActor = Actor::New();
320     mActor.SetProperty(Dali::Actor::Property::NAME, "Cube");
321     mActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
322     mActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
323     mActor.AddRenderer(mRenderer);
324
325     mActor.SetProperty(Actor::Property::SIZE, Vector3(10.f, 10.f, 10.f));
326
327     Window window = mApplication.GetWindow();
328     window.Add(mActor);
329   }
330
331   /**
332    * Display a skybox surrounding the camera
333    */
334   void DisplaySkybox()
335   {
336     // Load skybox faces from file
337     Texture texture = Texture::New(TextureType::TEXTURE_CUBE, Pixel::RGBA8888, SKYBOX_FACE_WIDTH, SKYBOX_FACE_HEIGHT);
338     for(unsigned int i = 0; i < SKYBOX_FACE_COUNT; i++)
339     {
340       PixelData pixels = SyncImageLoader::Load(SKYBOX_FACES[i]);
341       texture.Upload(pixels, CubeMapLayer::POSITIVE_X + i, 0, 0, 0, SKYBOX_FACE_WIDTH, SKYBOX_FACE_HEIGHT);
342     }
343
344     // create TextureSet
345     mSkyboxTextures = TextureSet::New();
346     mSkyboxTextures.SetTexture(0, texture);
347
348     mSkyboxRenderer = Renderer::New(mSkyboxGeometry, mShaderSkybox);
349     mSkyboxRenderer.SetTextures(mSkyboxTextures);
350     mSkyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
351
352     // Enables the depth test.
353     mSkyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
354
355     // The fragment shader will run only is those pixels that have the max depth value.
356     mSkyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
357
358     Window window = mApplication.GetWindow();
359
360     mSkyboxActor = Actor::New();
361     mSkyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
362     mSkyboxActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
363     mSkyboxActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
364     mSkyboxActor.SetProperty(Actor::Property::POSITION, CAMERA_DEFAULT_POSITION);
365     mSkyboxActor.AddRenderer(mSkyboxRenderer);
366     window.Add(mSkyboxActor);
367   }
368
369   /**
370    * Plays animation
371    */
372   void PlayAnimation()
373   {
374     mAnimation = Animation::New(5.0f);
375     mAnimation.SetLooping(true);
376     mAnimation.AnimateBy(Property(mActor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360)), Vector3::ZAXIS));
377     mAnimation.AnimateBy(Property(mActor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360)), Vector3::YAXIS));
378     mAnimation.AnimateBy(Property(mActor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360)), Vector3::XAXIS));
379     mAnimation.Play();
380   }
381
382 private:
383   Application& mApplication;
384
385   LookCamera mCamera;
386
387   Shader mShaderCube;
388   Shader mShaderSkybox;
389
390   Geometry   mGeometry;
391   TextureSet mTextureSet;
392   Renderer   mRenderer;
393   Actor      mActor;
394   Animation  mAnimation;
395
396   Geometry   mSkyboxGeometry;
397   TextureSet mSkyboxTextures;
398   Renderer   mSkyboxRenderer;
399   Actor      mSkyboxActor;
400 };
401
402 int DALI_EXPORT_API main(int argc, char** argv)
403 {
404   Application            application = Application::New(&argc, &argv);
405   TexturedCubeController test(application);
406   application.MainLoop();
407   return 0;
408 }