Book Image

OpenGL ES 3.0 Cookbook

By : Parminder Singh
Book Image

OpenGL ES 3.0 Cookbook

By: Parminder Singh

Overview of this book

<p>"Write once, use anywhere" is truly the power behind OpenGL ES and has made it an embedded industry standard. The library provides cutting-edge, easy-to-use features to build a wide range of applications in the gaming, simulation, augmented-reality, image-processing, and geospatial domains.</p> <p>The book starts by providing you with all the necessary OpenGL ES 3.0 setup guidelines on iOS and Android platforms. You'll go on to master the fundamentals of modern 3D graphics, such as drawing APIs, transformations, buffer objects, the model-view-project analogy, and much more. The book goes on to deal with advanced topics and offers a wide range of recipes on the light shading, real-time rendering techniques with static and procedure textures to create stunning visualizations and runtime effects.</p>
Table of Contents (21 chapters)
OpenGL ES 3.0 Cookbook
Credits
About the Author
Acknowledgments
About the Reviewers
www.PacktPub.com
Preface
Index

Loading and compiling a shader program


The shader program created in the previous recipe needs to be loaded and compiled into a binary form. This recipe will be helpful in understanding the procedure of loading and compiling a shader program.

Getting ready

Compiling and linking a shader is necessary so that these programs are understandable and executable by the underlying graphics hardware/platform (that is, the vertex and fragment processors).

The following figure provides an overview of the complete process of creating a shader executable. The different number labels help us understand the order of flow in the build process. Each stage within the build process is marked with the respective OpenGL ES APIs responsible for it.

How to do it...

In order to load and compile the shader source, use the following steps:

  1. Create a NativeTemplate.h/NativeTemplate.cpp and define a function named loadAndCompileShader in it. Use the following code, and proceed to the next step for detailed information about this function:

    GLuint loadAndCompileShader(GLenum shaderType, const char* sourceCode) {
         // Create the shader
      GLuint shader = glCreateShader(shaderType);
      if ( shader ) {
         // Pass the shader source code
         glShaderSource(shader, 1, &sourceCode, NULL);
    
         // Compile the shader source code
         glCompileShader(shader);
         
         // Check the status of compilation
         GLint compiled = 0;
         glGetShaderiv(shader,GL_COMPILE_STATUS,&compiled);
         if (!compiled) {
       
          // Get the info log for compilation failure
           GLint infoLen = 0;
           glGetShaderiv(shader,GL_INFO_LOG_LENGTH, &infoLen);
           if (infoLen) {
              char* buf = (char*) malloc(infoLen);
              if (buf) {
                glGetShaderInfoLog(shader, infoLen, NULL, buf);
                printf("Could not compile shader %s:" buf);
                free(buf);
              }
    
          // Delete the shader program
              glDeleteShader(shader);
              shader = 0;
           }
        }
      }
      return shader;
    }

    This function is responsible for loading and compiling a shader source. The argument shaderType accepts the type of shader that needs to be loaded and compiled; it can be GL_VERTEX_SHADER or GL_FRAGMENT_SHADER. The sourceCode specifies the source program of the corresponding shader.

  2. Create an empty shader object using the glCreateShader OpenGL ES 3.0 API. This shader object is responsible for loading the vertex or fragment source code depending on the specified shaderType parameter:

    • Syntax:

      GLuint glCreateShader(  Glenum shaderType);

      This API returns a non-zero value if the object is successfully created. This value is used as a handle to reference this object. On failure, this function returns 0. The shaderType argument specifies the type of the shader to be created. It must be either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER:

      // Create the shader object
      GLuint shader = glCreateShader(shaderType);

      Note

      Unlike in C++, where object creation is transparent, in OpenGL ES, the objects are created behind the curtains. You can access, use, and delete the objects as and when required. All the objects are identified by a unique identifier, which can be used for programming purposes.

      The created empty shader object (shader) needs to be bound first with the shader source in order to compile it. This binding is performed by using the glShaderSource API:

      // Load the shader source code
      glShaderSource(shader, 1, &sourceCode, NULL);

      The API sets the shader code string in the shader object, shader. The source string is simply copied in the shader object; it is not parsed or scanned.

    • Syntax:

      void glShaderSource(GLuint shader, GLsizei count, const GLchar * const *string, const GLint *length);

      Variable

      Description

      shader

      This is the handle of the shader object whose source code needs to bind

      count

      This is the number of elements in the string and length arrays

      string

      This specifies the array of pointers to strings containing source code that needs to be loaded

      length

      This specifies the array of string lengths

    The count specifies the number of strings in the array. If the length array is NULL, this means that all the strings are null terminated. If the values inside in this array are non-zero, it specifies the length of the corresponding string. Any value less than 0 is assumed it to be a null-terminated string.

  3. Compile the shader using the glCompileShader API. It accepts a shader object handle shader:

           glCompileShader(shader);    // Compile the shader
    • Syntax:

      void glCompileShader (GLuint shader);

      Variable

      Description

      shader

      This is the handle of the shader object that needs to be compiled

  4. The compilation status of the shader is stored as a state of the shader object. This state can be retrieved using the glGetShaderiv OpenGL ES API:

         GLint compiled = 0;    // Check compilation status
         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);

    The glGetShaderiv API accepts the handle of the shader and GL_COMPILE_STATUS as an argument to check the status of the compilation. It retrieves the status in params. The params returns GL_TRUE if the last compilation was successful. Otherwise, it returns GL_FALSE.

    • Syntax:

      void glGetShaderiv(GLuint shader, GLenum pname, GLint *params);

      Variable

      Description

      shader

      This is the handle of the shader object whose compilation status needs to be checked.

      pname

      This specifies the object's state parameter. The symbolic names accepted are GL_SHADER_TYPE, GL_DELETE_STATUS, GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, and GL_SHADER_SOURCE_LENGTH.

      params

      This returns the requested object parameter state.

      In the case of compilation failure, the glGetShaderiv API can also be used to retrieve the information log from the OpenGL ES state machine by passing GL_INFO_LOG_LENGTH as the parameter. The infoLen returns the length of the information log. If the returned value is 0, it means there is no information log. If the infoLen value is greater than 0, then the information log message can be retrieved using glGetShaderInfoLog:

             if (!compiled) {      // Handle Errors
                GLint infoLen = 0; // Check error string length
                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
                . . . . .
             }
  5. Use glGetShaderInfoLog to get the error report:

    • Syntax:

      void glGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei*length, GLchar* infoLog);

      Variable

      Description

      shader

      This is the handle of the shader object whose information log is required

      maxLength

      This is the size of the character buffer to store the returned information log

      length

      This is the length of the string returned by the information length

      infoLog

      This specifies array of characters

  6. The shader is deleted if the shader source cannot be compiled. Delete the shader object using the glDeleteShader API.

    • Syntax:

      void glDeleteShader(GLuint shader);

      Variable

      Description

      shader

      This is the handle of the shader object that needs to be deleted

  7. Return the shader object ID if the shader is compiled successfully:

    return shader; // Return the shader object ID

How it works...

The loadAndCompileShader function first creates an empty shader object. This empty object is referenced by the shader variable. This object is bound with the source code of the corresponding shader. The source code is compiled through a shader object using the glCompileShader API. If the compilation is successful, the shader object handle is returned successfully. Otherwise, the shader object returns 0 and needs to be deleted explicitly using glDeleteShader. The status of the compilation can be checked using glGetShaderiv with GL_COMPILE_STATUS.

There's more...

In order to differentiate among various versions of OpenGL ES and GL Shading Language, it is useful to get this information from the current driver of your device. This will be helpful to make the program robust and manageable by avoiding errors caused by version upgrade or application being installed on older versions of OpenGL ES and GLSL. The other vital information can be queried from the current driver, such as the vendor, renderer, and available extensions supported by the device driver. This information can be queried using the glGetString API. This API accepts a symbolic constant and returns the queried system metrics in the string form. The printGLString wrapper function in our program helps in printing device metrics:

static void printGLString(const char *name, GLenum s) {
    printf("GL %s = %s\n", name, (const char *) glGetString(s));
}
// Print the OpenGL ES system metrics
void printOpenGLESInfo(){
   printGLString("Version",    GL_VERSION);
   printGLString("Vendor",    GL_VENDOR);
   printGLString("Renderer",    GL_RENDERER);
   printGLString("Extensions",    GL_EXTENSIONS);
   printGLString("GLSL version",  GL_SHADING_LANGUAGE_VERSION);
}

See also

  • Linking a shader program