Example Code

From OpenGL.org
Jump to: navigation, search

This is a list of all of the significant example code used throughout the wiki.

Texture

V · E

This example code shows how to create a 2D array texture.

GLuint texture = 0;
 
GLsizei width = 2;
GLsizei height = 2;
GLsizei layerCount = 2;
GLsizei mipLevelCount = 1;
 
//Read you texels here. In the current example, we have 2*2*2 = 8 texels, with each texel being 4 GLubytes.
GLubyte texels[32] = 
{
     //Texels for first image.
     0,   0,   0,   255,
     255, 0,   0,   255,
     0,   255, 0,   255,
     0,   0,   255, 255,
     //Texels for second image.
     255, 255, 255, 255,
     255, 255,   0, 255,
     0,   255, 255, 255,
     255, 0,   255, 255,
};
 
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D_ARRAY,texture);
//Allocate the storage.
glTexStorage3D(GL_TEXTURE_2D_ARRAY, mipLevelCount, GL_RGBA8, width, height, layerCount);
//Upload pixel data.
//The first 0 refers to the mipmap level (level 0, since there's only 1)
//The following 2 zeroes refers to the x and y offsets in case you only want to specify a subrectangle.
//The final 0 refers to the layer index offset (we start from index 0 and have 2 levels).
//Altogether you can specify a 3D box subset of the overall texture, but only one mip level at a time.
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, layerCount, GL_RGBA, GL_UNSIGNED_BYTE, texels);
 
//Always set reasonable texture parameters
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

GLSL error testing


V · E

Shader compilation error checking.

GLuint shader = glCreateShader(...);
 
//Get strings for glShaderSource.
glShaderSource(shader, ...);
 
glCompileShader(shader);
 
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
        GLint maxLength = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
 
        //The maxLength includes the NULL character
        std::vector<char> errorLog(maxLength);
        glGetShaderInfoLog(vertexshader, maxLength, &maxLength, &errorLog[0]);
 
        //Provide the infolog in whatever manor you deem best.
        //Exit with failure.
        glDeleteShader(shader); //Don't leak the shader.
        return;
}
 
//Shader compilation is successful.


V · E

Program Linking error checking.

GLuint program = glCreateProgram();
 
//Attach shaders as necessary.
glAttachShader(program, ...);
...
 
//Link the program.
glLinkProgram(program);
 
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if(isLinked == GL_FALSE)
{
        GLint maxLength = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
 
        //The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
 
        //The program is useless now. So delete it.
        glDeleteProgram(program);
 
        //Provide the infolog in whatever manor you deem best.
        //Exit with failure.
        return;
}


GLSL shader compilation examples


V · E

Full compile/link of a Vertex and Fragment Shader.

//Read our shaders into the appropriate buffers
std::string vertexSource = //Get source code for vertex shader.
std::string fragmentSource = //Get source code for fragment shader.
 
//Create an empty vertex shader handle
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
 
//Send the vertex shader source code to GL
//Note that std::string's .c_str is NULL character terminated.
const GLchar *source = (const GLchar *)vertexSource.c_str();
glShaderSource(vertexShader, 1, &source, 0);
 
//Compile the vertex shader
glCompileShader(vertexShader);
 
GLint isCompiled = 0;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
        GLint maxLength = 0;
        glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
 
        //The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);
 
        //We don't need the shader anymore.
        glDeleteShader(vertexShader);
 
        //Use the infoLog as you see fit.
 
        //In this simple program, we'll just leave
        return;
}
 
//Create an empty fragment shader handle
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 
//Send the fragment shader source code to GL
//Note that std::string's .c_str is NULL character terminated.
source = (const GLchar *)fragmentSource.c_str();
glShaderSource(fragmentShader, 1, &source, 0);
 
//Compile the fragment shader
glCompileShader(fragmentShader);
 
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
        GLint maxLength = 0;
        glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
 
        //The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);
 
        //We don't need the shader anymore.
        glDeleteShader(fragmentShader);
        //Either of them. Don't leak shaders.
        glDeleteShader(vertexShader);
 
        //Use the infoLog as you see fit.
 
        //In this simple program, we'll just leave
        return;
}
 
//Vertex and fragment shaders are successfully compiled.
//Now time to link them together into a program.
//Get a program object.
GLuint program = glCreateProgram();
 
//Attach our shaders to our program
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
 
//Link our program
glLinkProgram(program);
 
//Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(shaderprogram, GL_LINK_STATUS, (int *)&isLinked);
if(isLinked == GL_FALSE)
{
        GLint maxLength = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
 
        //The maxLength includes the NULL character
        std::vector<GLchar> infoLog(maxLength);
        glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
 
        //We don't need the program anymore.
        glDeleteProgram(program);
        //Don't leak shaders either.
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
 
        //Use the infoLog as you see fit.
 
        //In this simple program, we'll just leave
        return;
}
 
//Always detach shaders after a successful link.
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);


V · E

Creating two separable programs, one with a vertex shader and one with a fragment shader.

//Create two separable program objects from a 
//single source string respectively (vertSrc and fragSrc)
GLuint vertProg = glCreateShaderProgramv(GL_VERTEX_SHADER  , 1, &vertSrc);
GLuint fragProg = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragSrc);
 
//CHECK FOR ERRORS HERE!.
 
//Generate a program pipeline and attach the programs to their respective stages
glGenProgramPipelines(1, &pipeline);
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT  , vertProg);
glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, fragProg);
 
//Query and set any uniforms
GLint colorLoc = glGetUniformLocation(fragProg, "Color");
glProgramUniform4f(fragProg, colorLoc, 1.f, 0.f, 0.f, 1.f);


V · E

Creates a separate program, where some of the stages are directly linked together.

//Create two programs. One with just the vertex shader, and 
//one with both geometry and fragment stages.
GLuint vertexProgram   = glCreateProgram();
GLuint geomFragProgram = glCreateProgram();
 
//Declare that programs are separable - this is crucial!
glProgramParameteri(vertexProgram  , GL_PROGRAM_SEPARABLE, GL_TRUE);
glProgramParameteri(geomFragProgram, GL_PROGRAM_SEPARABLE, GL_TRUE);
 
//Generate and compile shader objects, as normal.
GLuint vertShader  = glCreateShader(GL_VERTEX_SHADER);
GLuint geomShader  = glCreateShader(GL_GEOMETRY_SHADER);
GLuint fragShader  = glCreateShader(GL_FRAGMENT_SHADER);
 
glShaderSource(vertShader, 1, &vertSrc, NULL);
glShaderSource(geomShader, 1, &geomSrc, NULL);
glShaderSource(fragShader, 1, &fragSrc, NULL);
 
glCompileShader(vertShader);
glCompileShader(geomShader);
glCompileShader(fragShader);
 
//Attach the shaders to their respective programs
glAttachShader(vertexProgram  , vertShader);
glAttachShader(geomFragProgram, geomShader);
glAttachShader(geomFragProgram, fragShader);
 
//Perform any pre-linking steps.
glBindAttribLocation(vertexProgram    , 0, "Position");
glBindFragDataLocation(geomFragProgram, 0, "FragColor");
 
//Link the programs
glLinkProgram(vertexProgram);
glLinkProgram(geomFragProgram);
 
//Detach and delete the shader objects
glDetachShader(vertexProgram, vertShader);
glDeleteShader(vertShader);
 
glDetachShader(geomFragProgram, geomShader);
glDetachShader(geomFragProgram, fragShader);
glDeleteShader(geomShader);
glDeleteShader(fragShader);
 
//Generate a program pipeline
glGenProgramPipelines(1, &pipeline);
 
//Attach the first program to the vertex stage, and the second program
//to the geometry and fragment stages
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, vertexProgram);
glUseProgramStages(pipeline, GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, geomFragProgram);


GLSL expression examples

V · E

This example code shows what are and are not dynamically uniform expressions.

in vec3 fromPrevious;
in uvec2 fromRange;
 
const int foo = 5;
const uvec2 range = uvec2(2, 5);
uniform vec2 pairs;
 
uniform sampler2d tex;
 
void main()
{
  foo; //constant expressions are dynamically uniform.
 
  uint value = 21; //value is dynamically uniform.
  value = range.x; //still dynamically uniform.
  value = range.y + fromRange.y; //not dynamically uniform; current value comes from a non-dynamically uniform source.
  value = 4; //dynamically uniform again.
  if(fromPrevious.y < 3.14)
    value = 12;
  value; //NOT dynamically uniform. The value of this variable depends on fromPrevious, an input variable.
 
  float number = abs(pairs.x); //number is dynamically uniform.
  number = sin(pairs.y); //still dynamically uniform.
  number = cos(fromPrevious.x); //not dynamically uniform.
 
  vec4 colors = texture(tex, pairs.xy); //dynamically uniform, even though it comes from a texture.
                                        //It uses the same texture coordinate, thus getting the same texel every time.
  colors = texture(tex, fromPrevious.xy); //not dynamically uniform.
 
  for(int i = range.x; i < range.y; ++i)
  {
       //loop initialized with, compared against, and incremented by dynamically uniform expressions.
    i; //Therefore, it is dynamically uniform.
  }
 
  for(int i = fromRange.x; i < fromRange.y; ++i)
  {
    i; //Not dynamically uniform; `fromRange` is not dynamically uniform.
  }
}


Debug Output


V · E

This example code shows how to get the first X messages from the debug output log.

void GetFirstNMessages(GLuint numMsgs)
{
        GLint maxMsgLen = 0;
        glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &maxMsgLen);
 
        std::vector<GLchar> msgData(numMsgs * maxMsgLen);
        std::vector<GLenum> sources(numMsgs);
        std::vector<GLenum> types(numMsgs);
        std::vector<GLenum> severities(numMsgs);
        std::vector<GLuint> ids(numMsgs);
        std::vector<GLsizei> lengths(numMsgs);
 
        GLuint numFound = glGetDebugMessageLog(numMsgs, msgs.size(), &sources[0], &types[0], &ids[0], &severities[0], &lengths[0], &msgData[0]);
 
        sources.resize(numFound);
        types.resize(numFound);
        severities.resize(numFound);
        ids.resize(numFound);
        lengths.resize(numFound);
 
        std::vector<std::string> messages;
        messages.reserve(numFound);
 
        std::vector<GLchar>::iterator currPos = msgData.begin();
        for(size_t msg = 0; msg < lengths.size(); ++msg)
        {
                messages.push_back(std::string(currPos, currPos + lengths[msg] - 1));
                currPos = currPos + lengths[msg];
        }
}


Program introspection


V · E

Iteration over all non-block uniform variables, fetching their names, types, and locations:

GLint numUniforms = 0;
glGetProgramInterfaceiv(prog, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numUniforms);
const GLenum properties[4] = {GL_BLOCK_INDEX​, GL_TYPE​, GL_NAME_LENGTH​, GL_LOCATION};
 
for(int unif = 0; unif < numUniforms; ++unif)
{
  GLint values[4];
  glGetProgramResourceiv(prog, GL_UNIFORM, unif, 4, properties, 4, NULL, values);
 
  //Skip any uniforms that are in a block.
  if(properties[0] != -1)
    continue;
 
  //Get the name. Must use a std::vector rather than a std::string for C++03 standards issues.
  //C++11 would let you use a std::string directly.
  std::vector<char> nameData(values[2]);
  glGetProgramResourceName(prog, GL_UNIFORM, unif, nameData.size(), NULL, &nameData[0]);
  std::string name(nameData.begin(), nameData.end() - 1);
}


V · E

Iteration over all uniforms within each uniform block.

GLint numBlocks = 0;
glGetProgramInterfaceiv(prog, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numBlocks );
const GLenum blockProperties[1] = {GL_NUM_ACTIVE_VARIABLES}
const GLenum activeUnifProp[1] = {GL_ACTIVE_VARIABLES}
const GLenum unifProperties[3] = {GL_NAME_LENGTH​, GL_TYPE​, GL_LOCATION};
 
for(int blockIx = 0; blockIx < numBlocks; ++numBlocks)
{
  GLint numActiveUnifs = 0;
  glGetProgramResourceiv(prog, GL_UNIFORM_BLOCK, blockIx, 1, blockProperties, 1, NULL, numActiveUnifs);
 
  if(!numActiveUnifs)
    continue;
 
  std::vector<GLint> blockUnifs(numActiveUnifs);
  glGetProgramResourceiv(prog, GL_UNIFORM_BLOCK, blockIx, 1, activeUnifProp, numActiveUnifs, NULL, &blockUnifs[0]);
 
  for(int unifIx = 0; unifIx < numActiveUnifs; ++unifIx)
  {
    GLint values[3];
    glGetProgramResourceiv(prog, GL_UNIFORM, unifIx, 3, unifProperties, 4, NULL, values);
 
    //Get the name. Must use a std::vector rather than a std::string for C++03 standards issues.
    //C++11 would let you use a std::string directly.
    std::vector<char> nameData(values[0]);
    glGetProgramResourceName(prog, GL_UNIFORM, blockUnifs[unifIx], nameData.size(), NULL, &nameData[0]);
    std::string name(nameData.begin(), nameData.end() - 1);
  }
}