OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Skybox.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2014-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "Image.h"
22 #include "Quaternions.h"
23 #include "Text.h"
24 #include "Skybox.h"
25 
26 #include <jni.h>
27 #include <GLES3/gl3.h>
28 #include <cstdio>
29 #include <cstdlib>
30 #include <cmath>
31 
32 /* Window resolution. */
33 unsigned int window_width = 0;
34 unsigned int window_height = 0;
35 
36 using namespace Skybox;
37 
38 /* Location of a 'viewMat' uniform variable. */
39 GLint location_viewMat = 0;
40 
41 /* ID of a program object. */
43 
44 /* Quaternions representing rotations around X, Y and Z axes. */
45 Quaternion Q_X = { 0.0f, 0.0f, 0.0f, 0.0f };
46 Quaternion Q_Y = { 0.0f, 0.0f, 0.0f, 0.0f };
47 Quaternion Q_Z = { 0.0f, 0.0f, 0.0f, 0.0f };
48 
49 /* Quaternions to store resultant products. */
50 Quaternion Q_XY = { 0.0f, 0.0f, 0.0f, 0.0f };
51 Quaternion Q_XYZ = { 0.0f, 0.0f, 0.0f, 0.0f };
52 
53 /* Used to hold cube-map texture face data when initializing skybox cube-map texture. */
54 ImageFile cubemap_image = { 0, 0, NULL };
55 
56 /* Instance of text renderer. */
57 Text* text = NULL;
58 
59 /* Texture cubemap name. */
61 
62 /* Number of degrees to rotate counterclockwise around X, Y and Z axes respectively. */
63 float roll = 0.0f, pitch = 0.0f, yaw = 0.0f;
64 
65 /* 4x4 matrix that transforms the skybox's vertices from model space to world space. */
66 float model_view_matrix[16] = {0.0f};
67 
68 /* Please see header for specification. */
69 GLuint load_shader(GLenum shader_type, const char* shader_source)
70 {
71  GLuint shader = GL_CHECK(glCreateShader(shader_type));
72 
73  if (shader != 0)
74  {
75  GL_CHECK(glShaderSource(shader, 1, &shader_source, NULL));
76  GL_CHECK(glCompileShader(shader));
77 
78  GLint compiled = 0;
79 
80  GL_CHECK(glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
81 
82  if (compiled != GL_TRUE)
83  {
84  GLint info_len = 0;
85 
86  GL_CHECK(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len));
87 
88  if (info_len > 0)
89  {
90  char* log_buffer = NULL;
91 
92  MALLOC_CHECK(char*, log_buffer, info_len);
93 
94  GL_CHECK(glGetShaderInfoLog(shader, info_len, NULL, log_buffer));
95  LOGE("Could not compile shader 0x%x:\n%s\n", shader_type, log_buffer);
96  FREE_CHECK(log_buffer);
97 
98  GL_CHECK(glDeleteShader(shader));
99  shader = 0;
100 
101  exit(EXIT_FAILURE);
102  }
103  }
104  }
105 
106  return shader;
107 }
108 
109 /* Please see header for specification. */
110 GLuint create_program(const char* vertex_source, const char* fragment_source)
111 {
112  GLuint vertexShader = load_shader(GL_VERTEX_SHADER, vertex_source);
113  GLuint fragmentShader = load_shader(GL_FRAGMENT_SHADER, fragment_source);
114  GLuint program = GL_CHECK(glCreateProgram());
115 
116  if (program != 0)
117  {
118  GL_CHECK(glAttachShader(program, vertexShader));
119  GL_CHECK(glAttachShader(program, fragmentShader));
120  GL_CHECK(glLinkProgram(program));
121 
122  GLint linkStatus = GL_FALSE;
123 
124  GL_CHECK(glGetProgramiv(program, GL_LINK_STATUS, &linkStatus));
125 
126  if (linkStatus != GL_TRUE)
127  {
128  GLint buf_length = 0;
129 
130  GL_CHECK(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &buf_length));
131 
132  if (buf_length > 0)
133  {
134  char* log_buffer = NULL;
135 
136  MALLOC_CHECK(char*, log_buffer, buf_length);
137  GL_CHECK(glGetProgramInfoLog(program, buf_length, NULL, log_buffer));
138  LOGE("Could not link program:\n%s\n", log_buffer);
139  FREE_CHECK(log_buffer);
140  }
141 
142  GL_CHECK(glDeleteProgram(program));
143  program = 0;
144 
145  exit(EXIT_FAILURE);
146  }
147  }
148  else
149  {
150  LOGE("Error creating program object.");
151  exit(EXIT_FAILURE);
152  }
153 
154  return program;
155 }
156 
158 {
161 
162  /* Path to resource directory. */
163  const char resource_directory[] = "/data/data/com.arm.malideveloper.openglessdk.skybox/files/";
164 
165  /* Path to cubemap texture. */
166  char file_name[] = "/data/data/com.arm.malideveloper.openglessdk.skybox/files/greenhouse_skybox-0.ppm";
167 
168  /* Texture cubemap targets. */
169  GLenum cubemap_faces[] =
170  {
171  GL_TEXTURE_CUBE_MAP_POSITIVE_X,
172  GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
173  GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
174  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
175  GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
176  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
177  };
178 
179  /* Generate texture name and bind it to the texture cubemap target. */
180  GL_CHECK(glGenTextures(1, &cubemap_texture));
181  GL_CHECK(glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap_texture));
182 
183  /* Set up texture parameters. */
184  GL_CHECK(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
185  GL_CHECK(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
186  GL_CHECK(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
187  GL_CHECK(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
188  GL_CHECK(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
189 
190  /* Load cubemap texture. */
191  cubemap_image = load_ppm_file(file_name);
192 
193  /* Specify storage for all levels of a cubemap texture. */
194  GL_CHECK(glTexStorage2D(GL_TEXTURE_CUBE_MAP, /* Texture target */
195  1, /* Number of texture levels */
196  GL_RGB8, /* Internal format for texture storage */
197  cubemap_image.width, /* Width of the texture image */
198  cubemap_image.height)); /* Height of the texture image */
199 
200  for (int n_face = 0; n_face < sizeof(cubemap_faces) / sizeof(cubemap_faces[0]); n_face++)
201  {
202  if (n_face != 0)
203  {
204  sprintf(file_name, "/data/data/com.arm.malideveloper.openglessdk.skybox/files/greenhouse_skybox-%d.ppm", n_face);
205 
206  cubemap_image = load_ppm_file(file_name);
207  }
208 
209  GL_CHECK(glTexSubImage2D(cubemap_faces[n_face], /* Texture target. */
210  0, /* Level-of-detail number. */
211  0, /* Texel offset in the x direction. */
212  0, /* Texel offset in the y direction. */
213  cubemap_image.width, /* Width of the texture image. */
214  cubemap_image.height, /* Height of the texture image. */
215  GL_RGB, /* Format of the pixel data. */
216  GL_UNSIGNED_BYTE, /* Type of the pixel data. */
217  (const GLvoid*) cubemap_image.pixels)); /* Pointer to the image data. */
218 
220  }
221 
222  /* Create a program object that we will attach the fragment and vertex shader to. */
224 
225  /* The program object has been successfully linked. Let's use it. */
226  GL_CHECK(glUseProgram(program_id));
227 
228  /* Retrieve uniform location for "viewMat" uniform defined in vertex shader. */
229  location_viewMat = GL_CHECK(glGetUniformLocation(program_id, "viewMat"));
230 
231  GL_CHECK(glEnable(GL_BLEND));
232  GL_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
233 
234  text = new Text(resource_directory, window_width, window_height);
235  text->clear();
236  text->addString(0, 0, "Skybox Sample", 255, 255, 0, 255);
237 }
238 
242 void render_frame(void)
243 {
244  /* Construct quaternions for X, Y and Z axes. */
245  Q_X = construct_quaternion(1.0f, 0.0f, 0.0f, roll);
246  Q_Y = construct_quaternion(0.0f, 1.0f, 0.0f, pitch);
247  Q_Z = construct_quaternion(0.0f, 0.0f, 1.0f, yaw);
248 
249  /* Obtain the resultant quaternion. */
252 
253  /* Compute a modelview matrix. Model matrix is a unit matrix. */
255 
256  /* In this demo, we do not need to provide the vertex shader with any mesh data, because a predefined set
257  of 4 vertices is embedded within the shader. These vertices, expressed in Normalized Device Coordinates,
258  correspond to four corners of the visible screen space. By using this vertices to form a triangle strip,
259  we end up with a full-screen quad that is later used for rasterization stage. */
260 
261  /* Restore the cubemap program object, because it has been changed by text rendering call. */
262  GL_CHECK(glUseProgram(program_id));
263 
264  /* Upload the matrix to view matrix uniform so that it can be used for vertex shader stage. */
265  GL_CHECK(glUniformMatrix4fv(location_viewMat, 1, GL_FALSE, (const GLfloat*) model_view_matrix));
266 
267  /* The angles can be decremented too to reverse the direction of rotation. */
268  roll += 0.2f;
269  pitch += 0.4f;
270  yaw += 0.2f;
271 
272  /* Rotating the skybox by more than 360 or less than 0 degrees is not permitted, in order to avoid problems. */
273  if (fabs(roll) >= 360.0f)
274  {
275  if (roll < 0.0f)
276  {
277  roll += 360.0f;
278  }
279  else
280  {
281  roll -= 360.0f;
282  }
283  }
284 
285  if (fabs(pitch) >= 360.0f)
286  {
287  if (pitch < 0.0f)
288  {
289  pitch += 360.0f;
290  }
291  else
292  {
293  pitch -= 360.0f;
294  }
295  }
296 
297  if (fabs(yaw) >= 360.0f)
298  {
299  if (yaw < 0.0f)
300  {
301  yaw += 360.0f;
302  }
303  else
304  {
305  yaw -= 360.0f;
306  }
307  }
308 
309  /* Render a full-screen quad, as described above.
310  Note that the actual content of the quad is drawn within the fragment shader. */
311  GL_CHECK(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
312 
313  text->draw();
314 }
315 
320 {
321  /* Delete the cube map texture. */
322  GL_CHECK(glDeleteTextures(1, &cubemap_texture));
323 
324  /* Release shaders. */
325  GL_CHECK(glUseProgram(0));
326  GL_CHECK(glDeleteProgram(program_id));
327 }
328 
329 extern "C"
330 {
331  JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_init(JNIEnv*, jobject, jint width, jint height);
332  JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_step(JNIEnv*, jobject);
333  JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_uninit(JNIEnv*, jobject);
334 };
335 
336 JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_init(JNIEnv*, jobject, jint width, jint height)
337 {
338  setup_graphics(width, height);
339 }
340 
342 {
343  render_frame();
344 }
345 
347 {
349 }
float roll
Definition: Skybox.cpp:63
void cleanup_graphics(void)
Perform graphics clean-up actions.
Definition: Skybox.cpp:319
Quaternion Q_Z
Definition: Skybox.cpp:47
void setup_graphics(int width, int height)
Definition: Skybox.cpp:157
#define MALLOC_CHECK(ptr_type, ptr, size)
Definition: AstcTextures.h:33
Functions for drawing text in OpenGL ES.
Definition: Text.h:107
ImageFile load_ppm_file(const char *ppm_file_name)
Definition: Image.cpp:29
GLuint load_shader(GLenum shader_type, const char *shader_source)
Create shader object and compile its source code.
Definition: Skybox.cpp:69
void clear(void)
Removes the current string from the class.
Definition: Text.cpp:170
GLint GLsizei GLsizei height
Definition: gl2ext.h:179
ImageFile cubemap_image
Definition: Skybox.cpp:54
float yaw
Definition: Skybox.cpp:63
void draw(void)
Draw the text to the screen.
Definition: Text.cpp:285
unsigned int window_width
Definition: Skybox.cpp:33
Text * text
Definition: Skybox.cpp:57
const string resource_directory("/data/data/com.arm.malideveloper.openglessdk.astctextures/files/")
const char skybox_vertex_shader_source[]
Definition: Skybox.h:71
Quaternion multiply_quaternions(Quaternion a, Quaternion b)
Definition: Quaternions.cpp:71
JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_init(JNIEnv *, jobject, jint width, jint height)
Definition: Skybox.cpp:336
const char skybox_fragment_shader_source[]
Definition: Skybox.h:87
int width
Definition: Image.h:30
float pitch
Definition: Skybox.cpp:63
GLuint program_id
Definition: Skybox.cpp:42
Quaternion Q_Y
Definition: Skybox.cpp:46
Quaternion Q_XYZ
Definition: Skybox.cpp:51
JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_uninit(JNIEnv *, jobject)
Definition: Skybox.cpp:346
Quaternion construct_quaternion(float x, float y, float z, float degs)
Definition: Quaternions.cpp:27
Quaternion Q_XY
Definition: Skybox.cpp:50
Struct representing texture image.
Definition: Image.h:27
char * pixels
Definition: Image.h:34
Quaternion Q_X
Definition: Skybox.cpp:45
JNIEXPORT void JNICALL Java_com_arm_malideveloper_openglessdk_skybox_NativeLibrary_step(JNIEnv *, jobject)
Definition: Skybox.cpp:341
float model_view_matrix[16]
Definition: Skybox.cpp:66
GLfloat GLfloat f
Definition: gl2ext.h:2707
void render_frame(void)
Renders a single frame.
Definition: Skybox.cpp:242
#define GL_CHECK(x)
Definition: AstcTextures.h:59
int height
Definition: Image.h:32
void construct_modelview_matrix(Quaternion quaternion, float *mat)
Definition: Quaternions.cpp:43
GLuint create_program(const char *vertex_source, const char *fragment_source)
Create program object, attach vertex and fragment shader to it. Link program object and check whether...
Definition: Skybox.cpp:110
#define LOGE(...)
Definition: AstcTextures.h:30
GLint location_viewMat
Definition: Skybox.cpp:39
GLint GLsizei width
Definition: gl2ext.h:179
typedef GLfloat(GL_APIENTRYP PFNGLGETPATHLENGTHNVPROC)(GLuint path
#define FREE_CHECK(ptr)
Definition: AstcTextures.h:53
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLuint cubemap_texture
Definition: Skybox.cpp:60
GLuint program
Definition: gl2ext.h:1475
unsigned int window_height
Definition: Skybox.cpp:34
typedef GLuint(GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGKHRPROC)(GLuint count
void addString(int xPosition, int yPosition, const char *string, int red, int green, int blue, int alpha)
Add a std::string to be drawn to the screen.
Definition: Text.cpp:181