[dali_2.1.20] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / drawable-actor / native-renderer.cpp
1 //
2 // Created by adam.b on 15/03/2022.
3 //
4 #include "native-renderer.h"
5
6 /**
7  * Set of math helper functions
8  */
9 namespace
10 {
11
12 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};
13
14 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};
15
16 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};
17
18 float matrixDegreesToRadians(float degrees)
19 {
20   return M_PI * degrees / 180.0f;
21 }
22
23 [[maybe_unused]] void matrixIdentityFunction(float* matrix)
24 {
25   if(matrix == NULL)
26   {
27     return;
28   }
29   matrix[0]  = 1.0f;
30   matrix[1]  = 0.0f;
31   matrix[2]  = 0.0f;
32   matrix[3]  = 0.0f;
33   matrix[4]  = 0.0f;
34   matrix[5]  = 1.0f;
35   matrix[6]  = 0.0f;
36   matrix[7]  = 0.0f;
37   matrix[8]  = 0.0f;
38   matrix[9]  = 0.0f;
39   matrix[10] = 1.0f;
40   matrix[11] = 0.0f;
41   matrix[12] = 0.0f;
42   matrix[13] = 0.0f;
43   matrix[14] = 0.0f;
44   matrix[15] = 1.0f;
45 }
46
47 [[maybe_unused]] void matrixMultiply(float* destination, float* operand1, float* operand2)
48 {
49   float theResult[16];
50   int   i, j = 0;
51   for(i = 0; i < 4; i++)
52   {
53     for(j = 0; j < 4; j++)
54     {
55       theResult[4 * i + j] = operand1[j] * operand2[4 * i] + operand1[4 + j] * operand2[4 * i + 1] +
56                              operand1[8 + j] * operand2[4 * i + 2] + operand1[12 + j] * operand2[4 * i + 3];
57     }
58   }
59   for(int i = 0; i < 16; i++)
60   {
61     destination[i] = theResult[i];
62   }
63 }
64
65 [[maybe_unused]] void matrixTranslate(float* matrix, float x, float y, float z)
66 {
67   float temporaryMatrix[16];
68   matrixIdentityFunction(temporaryMatrix);
69   temporaryMatrix[12] = x;
70   temporaryMatrix[13] = y;
71   temporaryMatrix[14] = z;
72   matrixMultiply(matrix, temporaryMatrix, matrix);
73 }
74
75 [[maybe_unused]] void matrixScale(float* matrix, float x, float y, float z)
76 {
77   float tempMatrix[16];
78   matrixIdentityFunction(tempMatrix);
79   tempMatrix[0]  = x;
80   tempMatrix[5]  = y;
81   tempMatrix[10] = z;
82   matrixMultiply(matrix, tempMatrix, matrix);
83 }
84
85 [[maybe_unused]] void matrixRotateX(float* matrix, float angle)
86 {
87   float tempMatrix[16];
88   matrixIdentityFunction(tempMatrix);
89   tempMatrix[5]  = cos(matrixDegreesToRadians(angle));
90   tempMatrix[9]  = -sin(matrixDegreesToRadians(angle));
91   tempMatrix[6]  = sin(matrixDegreesToRadians(angle));
92   tempMatrix[10] = cos(matrixDegreesToRadians(angle));
93   matrixMultiply(matrix, tempMatrix, matrix);
94 }
95 [[maybe_unused]] void matrixRotateY(float* matrix, float angle)
96 {
97   float tempMatrix[16];
98   matrixIdentityFunction(tempMatrix);
99   tempMatrix[0]  = cos(matrixDegreesToRadians(angle));
100   tempMatrix[8]  = sin(matrixDegreesToRadians(angle));
101   tempMatrix[2]  = -sin(matrixDegreesToRadians(angle));
102   tempMatrix[10] = cos(matrixDegreesToRadians(angle));
103   matrixMultiply(matrix, tempMatrix, matrix);
104 }
105 [[maybe_unused]] void matrixRotateZ(float* matrix, float angle)
106 {
107   float tempMatrix[16];
108   matrixIdentityFunction(tempMatrix);
109   tempMatrix[0] = cos(matrixDegreesToRadians(angle));
110   tempMatrix[4] = -sin(matrixDegreesToRadians(angle));
111   tempMatrix[1] = sin(matrixDegreesToRadians(angle));
112   tempMatrix[5] = cos(matrixDegreesToRadians(angle));
113   matrixMultiply(matrix, tempMatrix, matrix);
114 }
115
116 void matrixFrustum(float* matrix, float left, float right, float bottom, float top, float zNear, float zFar)
117 {
118   float temp, xDistance, yDistance, zDistance;
119   temp      = 2.0 * zNear;
120   xDistance = right - left;
121   yDistance = top - bottom;
122   zDistance = zFar - zNear;
123   matrixIdentityFunction(matrix);
124   matrix[0]  = temp / xDistance;
125   matrix[5]  = temp / yDistance;
126   matrix[8]  = (right + left) / xDistance;
127   matrix[9]  = (top + bottom) / yDistance;
128   matrix[10] = (-zFar - zNear) / zDistance;
129   matrix[11] = -1.0f;
130   matrix[14] = (-temp * zFar) / zDistance;
131   matrix[15] = 0.0f;
132 }
133
134 [[maybe_unused]] void matrixPerspective(float* matrix, float fieldOfView, float aspectRatio, float zNear, float zFar)
135 {
136   float ymax, xmax;
137   ymax = zNear * tanf(fieldOfView * M_PI / 360.0);
138   xmax = ymax * aspectRatio;
139   matrixFrustum(matrix, -xmax, xmax, -ymax, ymax, zNear, zFar);
140 }
141
142 } // namespace
143
144 NativeRenderer::NativeRenderer(uint32_t width, uint32_t height)
145 : mWidth(width),
146   mHeight(height)
147 {
148 }
149
150 bool NativeRenderer::OnRender(const Dali::RenderCallbackInput& input)
151 {
152   if(mState == State::INIT)
153   {
154     Setup(mWidth, mHeight);
155     mState = State::RENDER;
156   }
157
158   RenderCube(input);
159
160   return false;
161 }
162
163 void NativeRenderer::PrepareShader()
164 {
165   static const char glVertexShader[] =
166     "attribute vec4 vertexPosition;\n"
167     "attribute vec3 vertexColour;\n"
168     "varying vec3 fragColour;\n"
169     "uniform mat4 projection;\n"
170     "uniform mat4 modelView;\n"
171     "void main()\n"
172     "{\n"
173     "    gl_Position = projection * modelView * vertexPosition;\n"
174     "    fragColour = vertexColour;\n"
175     "}\n";
176
177   static const char glFragmentShader[] =
178     "precision mediump float;\n"
179     "varying vec3 fragColour;\n"
180     "void main()\n"
181     "{\n"
182     "    gl_FragColor = vec4(fragColour, 1.0);\n"
183     "}\n";
184
185   mProgramId = CreateProgram(glVertexShader, glFragmentShader);
186 }
187
188 void NativeRenderer::Setup(int width, int height)
189 {
190   PrepareShader();
191
192   mVertexLocation       = glGetAttribLocation(mProgramId, "vertexPosition");
193   mVertexColourLocation = glGetAttribLocation(mProgramId, "vertexColour");
194   mProjectionLocation   = glGetUniformLocation(mProgramId, "projection");
195   mModelViewLocation    = glGetUniformLocation(mProgramId, "modelView");
196
197   glEnable(GL_DEPTH_TEST);
198   glViewport(0, 0, width, height);
199 }
200
201 GLuint NativeRenderer::CreateProgram(const char* vertexSource, const char* fragmentSource)
202 {
203   GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertexSource);
204   if(!vertexShader)
205   {
206     return 0;
207   }
208   GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentSource);
209   if(!fragmentShader)
210   {
211     return 0;
212   }
213   GLuint program = glCreateProgram();
214   if(program)
215   {
216     glAttachShader(program, vertexShader);
217     glAttachShader(program, fragmentShader);
218     glLinkProgram(program);
219     GLint linkStatus = GL_FALSE;
220     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
221     if(linkStatus != GL_TRUE)
222     {
223       GLint bufLength = 0;
224       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
225       if(bufLength)
226       {
227         char* buf = (char*)malloc(bufLength);
228         if(buf)
229         {
230           glGetProgramInfoLog(program, bufLength, NULL, buf);
231           free(buf);
232         }
233       }
234       glDeleteProgram(program);
235       program = 0;
236     }
237   }
238   return program;
239 }
240
241 GLuint NativeRenderer::LoadShader(GLenum shaderType, const char* shaderSource)
242 {
243   GLuint shader = glCreateShader(shaderType);
244   if(shader != 0)
245   {
246     glShaderSource(shader, 1, &shaderSource, NULL);
247     glCompileShader(shader);
248     GLint compiled = 0;
249     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
250     if(compiled != GL_TRUE)
251     {
252       GLint infoLen = 0;
253       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
254
255       if(infoLen > 0)
256       {
257         char* logBuffer = (char*)malloc(infoLen);
258
259         if(logBuffer != NULL)
260         {
261           glGetShaderInfoLog(shader, infoLen, NULL, logBuffer);
262           free(logBuffer);
263           logBuffer = NULL;
264         }
265
266         glDeleteShader(shader);
267         shader = 0;
268       }
269     }
270   }
271
272   return shader;
273 }
274
275 void NativeRenderer::RenderCube(const Dali::RenderCallbackInput& input)
276 {
277   static float angle = 0.0f;
278
279   auto x = float(mWidth - input.size.width) * 0.5f;
280   auto y = float(mHeight - input.size.height) * 0.5f;
281   auto w = input.size.width;
282   auto h = input.size.height;
283
284   matrixPerspective(mProjectionMatrix, 45, (float)w / (float)h, 0.1f, 100);
285
286   glEnable(GL_SCISSOR_TEST);
287   glScissor(x, y, w, h);
288   glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
289   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
290   matrixIdentityFunction(mModelViewMatrix);
291   matrixScale(mModelViewMatrix, 0.5f, 0.5f, 0.5f);
292   matrixRotateX(mModelViewMatrix, angle);
293   matrixRotateY(mModelViewMatrix, angle);
294   matrixTranslate(mModelViewMatrix, 0.0f, 0.0f, -10.0f);
295   glUseProgram(mProgramId);
296   glVertexAttribPointer(mVertexLocation, 3, GL_FLOAT, GL_FALSE, 0, CUBE_VERTICES);
297   glEnableVertexAttribArray(mVertexLocation);
298   glVertexAttribPointer(mVertexColourLocation, 3, GL_FLOAT, GL_FALSE, 0, CUBE_COLOURS);
299   glEnableVertexAttribArray(mVertexColourLocation);
300   glUniformMatrix4fv(mProjectionLocation, 1, GL_FALSE, mProjectionMatrix);
301   glUniformMatrix4fv(mModelViewLocation, 1, GL_FALSE, mModelViewMatrix);
302   glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, CUBE_INDICES);
303   angle += 1;
304   if(angle > 360)
305   {
306     angle -= 360;
307   }
308 }