Use dali-scene3d.h instead of partial includes
[platform/core/uifw/dali-demo.git] / examples / direct-rendering / native-renderer.cpp
1 /*
2  * Copyright (c) 2022 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 "native-renderer.h"
19 #include <iostream>
20
21 /**
22  * Set of math helper functions
23  */
24 namespace
25 {
26
27 [[maybe_unused]] std::vector<std::string> split(const std::string& s, char seperator)
28 {
29   std::vector<std::string> output;
30   std::string::size_type prev_pos = 0, pos = 0;
31   while((pos = s.find(seperator, pos)) != std::string::npos)
32   {
33     std::string substring( s.substr(prev_pos, pos-prev_pos) );
34     output.push_back(substring);
35     prev_pos = ++pos;
36   }
37   output.push_back(s.substr(prev_pos, pos-prev_pos)); // Last word
38   return output;
39 }
40
41 int GetEnvInt(const char* name, int def)
42 {
43   auto v = getenv(name);
44   return v ? atoi(v) : def;
45 }
46
47 [[maybe_unused]] std::string GetEnvString(const char* name, std::string def = "")
48 {
49   auto v = getenv(name);
50   return v ? std::string(v) : def;
51 }
52
53 const uint32_t MAX_CUBES = GetEnvInt("MAX_CUBES", 200);
54
55 #define GL(x) {glGetError();{x;};auto err = glGetError();if(err){ \
56 printf("%p:%d: ERROR: 0x%X\n", this, __LINE__, int(err));} }
57
58 constexpr GLfloat CUBE_VERTICES[] = {-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
59
60 constexpr GLfloat CUBE_COLOURS[] = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
61
62 constexpr GLushort CUBE_INDICES[] = {0, 2, 3, 0, 1, 3, 4, 6, 7, 4, 5, 7, 8, 9, 10, 11, 8, 10, 12, 13, 14, 15, 12, 14, 16, 17, 18, 16, 19, 18, 20, 21, 22, 20, 23, 22};
63
64 constexpr float QUAD_VERTS[] = {
65   // positions          // colors           // texture coords
66   1.0f,  1.0f,
67   1.0f, -1.0f,
68   -1.0f, -1.0f,
69   -1.0f,  1.0f,
70 };
71
72 constexpr unsigned short QUAD_INDICES[] = {
73   0, 1, 2,
74   3, 0, 2
75 };
76
77 constexpr float QUAD_UV[] = {
78   // positions          // colors           // texture coords
79   1.0f, 1.0f,   // top right
80   1.0f, 0.0f,   // bottom right
81   0.0f, 0.0f,   // bottom left
82   0.0f, 1.0f    // top left
83 };
84
85 float matrixDegreesToRadians(float degrees)
86 {
87   return M_PI * degrees / 180.0f;
88 }
89
90 [[maybe_unused]] void matrixIdentityFunction(float* matrix)
91 {
92   if(matrix == NULL)
93   {
94     return;
95   }
96   matrix[0]  = 1.0f;
97   matrix[1]  = 0.0f;
98   matrix[2]  = 0.0f;
99   matrix[3]  = 0.0f;
100   matrix[4]  = 0.0f;
101   matrix[5]  = 1.0f;
102   matrix[6]  = 0.0f;
103   matrix[7]  = 0.0f;
104   matrix[8]  = 0.0f;
105   matrix[9]  = 0.0f;
106   matrix[10] = 1.0f;
107   matrix[11] = 0.0f;
108   matrix[12] = 0.0f;
109   matrix[13] = 0.0f;
110   matrix[14] = 0.0f;
111   matrix[15] = 1.0f;
112 }
113
114 [[maybe_unused]] void matrixMultiply(float* destination, float* operand1, float* operand2)
115 {
116   float theResult[16];
117   int   i, j = 0;
118   for(i = 0; i < 4; i++)
119   {
120     for(j = 0; j < 4; j++)
121     {
122       theResult[4 * i + j] = operand1[j] * operand2[4 * i] + operand1[4 + j] * operand2[4 * i + 1] +
123                              operand1[8 + j] * operand2[4 * i + 2] + operand1[12 + j] * operand2[4 * i + 3];
124     }
125   }
126   for(int i = 0; i < 16; i++)
127   {
128     destination[i] = theResult[i];
129   }
130 }
131
132 [[maybe_unused]] void matrixTranslate(float* matrix, float x, float y, float z)
133 {
134   float temporaryMatrix[16];
135   matrixIdentityFunction(temporaryMatrix);
136   temporaryMatrix[12] = x;
137   temporaryMatrix[13] = y;
138   temporaryMatrix[14] = z;
139   matrixMultiply(matrix, temporaryMatrix, matrix);
140 }
141
142 [[maybe_unused]] void matrixScale(float* matrix, float x, float y, float z)
143 {
144   float tempMatrix[16];
145   matrixIdentityFunction(tempMatrix);
146   tempMatrix[0]  = x;
147   tempMatrix[5]  = y;
148   tempMatrix[10] = z;
149   matrixMultiply(matrix, tempMatrix, matrix);
150 }
151
152 [[maybe_unused]] void matrixRotateX(float* matrix, float angle)
153 {
154   float tempMatrix[16];
155   matrixIdentityFunction(tempMatrix);
156   tempMatrix[5]  = cos(matrixDegreesToRadians(angle));
157   tempMatrix[9]  = -sin(matrixDegreesToRadians(angle));
158   tempMatrix[6]  = sin(matrixDegreesToRadians(angle));
159   tempMatrix[10] = cos(matrixDegreesToRadians(angle));
160   matrixMultiply(matrix, tempMatrix, matrix);
161 }
162 [[maybe_unused]] void matrixRotateY(float* matrix, float angle)
163 {
164   float tempMatrix[16];
165   matrixIdentityFunction(tempMatrix);
166   tempMatrix[0]  = cos(matrixDegreesToRadians(angle));
167   tempMatrix[8]  = sin(matrixDegreesToRadians(angle));
168   tempMatrix[2]  = -sin(matrixDegreesToRadians(angle));
169   tempMatrix[10] = cos(matrixDegreesToRadians(angle));
170   matrixMultiply(matrix, tempMatrix, matrix);
171 }
172 [[maybe_unused]] void matrixRotateZ(float* matrix, float angle)
173 {
174   float tempMatrix[16];
175   matrixIdentityFunction(tempMatrix);
176   tempMatrix[0] = cos(matrixDegreesToRadians(angle));
177   tempMatrix[4] = -sin(matrixDegreesToRadians(angle));
178   tempMatrix[1] = sin(matrixDegreesToRadians(angle));
179   tempMatrix[5] = cos(matrixDegreesToRadians(angle));
180   matrixMultiply(matrix, tempMatrix, matrix);
181 }
182
183 void matrixFrustum(float* matrix, float left, float right, float bottom, float top, float zNear, float zFar)
184 {
185   float temp, xDistance, yDistance, zDistance;
186   temp      = 2.0 * zNear;
187   xDistance = right - left;
188   yDistance = top - bottom;
189   zDistance = zFar - zNear;
190   matrixIdentityFunction(matrix);
191   matrix[0]  = temp / xDistance;
192   matrix[5]  = temp / yDistance;
193   matrix[8]  = (right + left) / xDistance;
194   matrix[9]  = (top + bottom) / yDistance;
195   matrix[10] = (-zFar - zNear) / zDistance;
196   matrix[11] = -1.0f;
197   matrix[14] = (-temp * zFar) / zDistance;
198   matrix[15] = 0.0f;
199 }
200
201 [[maybe_unused]] void matrixPerspective(float* matrix, float fieldOfView, float aspectRatio, float zNear, float zFar)
202 {
203   float ymax, xmax;
204   ymax = zNear * tanf(fieldOfView * M_PI / 360.0);
205   xmax = ymax * aspectRatio;
206   matrixFrustum(matrix, -xmax, xmax, -ymax, ymax, zNear, zFar);
207 }
208
209 } // namespace
210
211 NativeRenderer::~NativeRenderer() = default;
212
213 NativeRenderer::NativeRenderer(const CreateInfo& info )
214 : mWidth(info.width),
215   mHeight(info.height),
216   mCreateInfo(info)
217 {
218 }
219
220 void NativeRenderer::PrepareShader()
221 {
222   static const char glVertexShader[] =
223     "attribute vec4 vertexPosition;\n"
224     "attribute vec3 vertexColour;\n"
225     "varying vec3 fragColour;\n"
226     "uniform mat4 projection;\n"
227     "uniform mat4 modelView;\n"
228     "void main()\n"
229     "{\n"
230     "    gl_Position = projection * modelView * vertexPosition;\n"
231     "    fragColour = vertexColour;\n"
232     "}\n";
233
234   static const char glFragmentShader[] =
235     "precision mediump float;\n"
236     "varying vec3 fragColour;\n"
237     "void main()\n"
238     "{\n"
239     "    gl_FragColor = vec4(fragColour, 1.0);\n"
240     "}\n";
241
242   mProgramId = CreateProgram(glVertexShader, glFragmentShader);
243 }
244
245 void NativeRenderer::Setup(int width, int height)
246 {
247   PrepareShader();
248
249   mVertexLocation       = glGetAttribLocation(mProgramId, "vertexPosition");
250   mVertexColourLocation = glGetAttribLocation(mProgramId, "vertexColour");
251   mProjectionLocation   = glGetUniformLocation(mProgramId, "projection");
252   mModelViewLocation    = glGetUniformLocation(mProgramId, "modelView");
253
254   GL(glEnable(GL_DEPTH_TEST));
255 }
256
257 GLuint NativeRenderer::CreateProgram(const char* vertexSource, const char* fragmentSource)
258 {
259   GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertexSource);
260   if(!vertexShader)
261   {
262     return 0;
263   }
264   GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentSource);
265   if(!fragmentShader)
266   {
267     return 0;
268   }
269   GLuint program = glCreateProgram();
270   if(program)
271   {
272     GL(glAttachShader(program, vertexShader));
273     GL(glAttachShader(program, fragmentShader));
274     GL(glLinkProgram(program));
275     GLint linkStatus = GL_FALSE;
276     GL(glGetProgramiv(program, GL_LINK_STATUS, &linkStatus));
277     if(linkStatus != GL_TRUE)
278     {
279       GLint bufLength = 0;
280       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
281       if(bufLength)
282       {
283         char* buf = (char*)malloc(bufLength);
284         if(buf)
285         {
286           glGetProgramInfoLog(program, bufLength, NULL, buf);
287           free(buf);
288         }
289       }
290       glDeleteProgram(program);
291       program = 0;
292     }
293   }
294   return program;
295 }
296
297 GLuint NativeRenderer::LoadShader(GLenum shaderType, const char* shaderSource)
298 {
299   GLuint shader = glCreateShader(shaderType);
300   if(shader != 0)
301   {
302     GL(glShaderSource(shader, 1, &shaderSource, NULL));
303     GL(glCompileShader(shader));
304     GLint compiled = 0;
305     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
306     if(compiled != GL_TRUE)
307     {
308       GLint infoLen = 0;
309       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
310
311       if(infoLen > 0)
312       {
313         char* logBuffer = (char*)malloc(infoLen);
314
315         if(logBuffer != NULL)
316         {
317           glGetShaderInfoLog(shader, infoLen, NULL, logBuffer);
318           free(logBuffer);
319           logBuffer = NULL;
320         }
321
322         glDeleteShader(shader);
323         shader = 0;
324       }
325     }
326   }
327
328   return shader;
329 }
330
331 void NativeRenderer::RenderCube(const Dali::RenderCallbackInput& input)
332 {
333   uint32_t drawCount = 0;
334
335   float& angle = mAngle;
336
337   [[maybe_unused]] auto x = mCreateInfo.viewportX; // float(mWidth - input.size.width) * 0.5f;
338   [[maybe_unused]] auto y = mCreateInfo.viewportY; // float(mHeight - input.size.height) * 0.5f;
339   auto                  w = mCreateInfo.width;
340   auto                  h = mCreateInfo.height;
341   
342   matrixPerspective(mProjectionMatrix, 45, (float)w / (float)h, 0.1f, 100);
343
344   GL(glViewport(x, y, w, h));
345   GL(glEnable(GL_DEPTH_TEST));
346   if(!mCreateInfo.offscreen)
347   {
348     GL(glEnable(GL_SCISSOR_TEST));
349     GL(glScissor(x, y, w, h));
350   }
351   else
352   {
353     GL(glDisable(GL_SCISSOR_TEST));
354   }
355   GL(glClearColor(mCreateInfo.clearColor[0],
356                   mCreateInfo.clearColor[1],
357                   mCreateInfo.clearColor[2],
358                   mCreateInfo.clearColor[3]
359                   ));
360   {
361     GL(glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
362   }
363   GL(glUseProgram(mProgramId));
364   GL(glVertexAttribPointer(mVertexLocation, 3, GL_FLOAT, GL_FALSE, 0, CUBE_VERTICES));
365   GL(glEnableVertexAttribArray(mVertexLocation));
366   GL(glVertexAttribPointer(mVertexColourLocation, 3, GL_FLOAT, GL_FALSE, 0, CUBE_COLOURS));
367   GL(glEnableVertexAttribArray(mVertexColourLocation));
368
369   srand(10);
370
371   const auto maxCubes = int(MAX_CUBES);
372
373   for( int i = 0; i < int(maxCubes); ++i)
374   {
375     GL(matrixIdentityFunction(mModelViewMatrix));
376     matrixScale(mModelViewMatrix, 0.2f, 0.2f, 0.2f);
377     matrixRotateX(mModelViewMatrix, angle);
378     matrixRotateY(mModelViewMatrix, angle);
379     auto max = 7000;
380     if(mPosX.size() == uint32_t(i))
381     {
382       auto x = float((rand() % max) - (max / 2)) / 1000.0f;
383       auto y = float((rand() % max) - (max / 2)) / 1000.0f;
384       mPosX.emplace_back(x);
385       mPosY.emplace_back(y);
386     }
387     matrixTranslate(mModelViewMatrix, mPosX[i], mPosY[i], -5.0f);
388     GL(glUniformMatrix4fv(mProjectionLocation, 1, GL_FALSE, mProjectionMatrix));
389     GL(glUniformMatrix4fv(mModelViewLocation, 1, GL_FALSE, mModelViewMatrix));
390     GL(glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, CUBE_INDICES));
391     drawCount++;
392   }
393   angle += 1;
394   if(angle > 360)
395   {
396     angle -= 360;
397   }
398 }
399
400 void NativeRenderer::GlViewInitCallback(const Dali::RenderCallbackInput& input)
401 {
402   Setup(mWidth, mHeight);
403   mState = State::RENDER;
404 }
405
406 int NativeRenderer::GlViewRenderCallback(const Dali::RenderCallbackInput& input)
407 {
408   RenderCube(input);
409   return true;
410 }
411
412 void NativeRenderer::GlViewTerminateCallback(const Dali::RenderCallbackInput& input)
413 {
414   // Nothing to do here
415 }