Example Code

From OpenGL Wiki
Revision as of 02:16, 27 April 2013 by Alfonse (talk | contribs) (More examples.)
Jump to navigation Jump to search

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

GLSL error testing

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<GLchar> errorLog(maxLength);
	glGetShaderInfoLog(shader, 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.


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 manner you deem best.
	// Exit with failure.
	return;
}


GLSL full compile/link example

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(program, 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);

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);


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);


Program introspection

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(values[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);
}


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; ++blockIx)
{
  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, blockUnifs[unifIx], 3, unifProperties, 3, 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);
  }
}