4.1 Draw Arrays
Complete Source Code:
DrawCommands.h
#ifndef DRAWCOMMANDS_H
#define DRAWCOMMANDS_H
#define GLEW_STATIC
#include <GL/glew.h>
/* basic drawing */
/**********************************************************************************/
struct DrawArrays
{
GLenum Mode;
GLint First;
GLsizei Count;
};
struct DrawElements
{
GLenum Mode;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
};
/**********************************************************************************/
/* multi-draw */
/**********************************************************************************/
struct MultiDrawArrays
{
GLenum Mode;
const GLint* First;
const GLsizei* Count;
GLsizei DrawCount;
};
struct MultiDrawElements
{
GLenum Mode;
const GLsizei* Count;
GLenum Type;
const GLvoid* const* Indices;
GLsizei DrawCount;
};
/**********************************************************************************/
/* base index */
/**********************************************************************************/
struct DrawElementsBaseVertex
{
GLenum Mode;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
GLint BaseVertex;
};
/**********************************************************************************/
/* instancing */
/**********************************************************************************/
struct DrawArraysInstanced
{
GLenum Mode;
GLint First;
GLsizei Count;
GLsizei InstanceCount;
};
struct DrawElementsInstanced
{
GLenum Mode;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
GLsizei InstanceCount;
};
struct DrawArraysInstancedBaseInstance
{
GLenum Mode;
GLint First;
GLsizei Count;
GLsizei InstanceCount;
GLuint BaseInstance;
};
struct DrawElementsInstancedBaseInstance
{
GLenum Mode;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
GLsizei InstanceCount;
GLuint BaseInstance;
};
/**********************************************************************************/
/* range */
/**********************************************************************************/
struct DrawRangeElements
{
GLenum Mode;
GLuint Start;
GLuint End;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
};
/**********************************************************************************/
/* combinations */
/**********************************************************************************/
struct MultiDrawElementsBaseVertex
{
GLenum Mode;
const GLsizei* Count;
GLenum Type;
const GLvoid* const* Indices;
GLsizei Drawcount;
const GLint* BaseVertex;
};
struct DrawRangeElementsBaseVertex
{
GLenum Mode;
GLuint Start;
GLuint End;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
GLint BaseVertex;
};
struct DrawElementsInstancedBaseVertex
{
GLenum Mode;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
GLsizei PrimCount;
GLint BaseVertex;
};
struct DrawElementsInstancedBaseVertexBaseInstance
{
GLenum Mode;
GLsizei Count;
GLenum Type;
const GLvoid* Indices;
GLsizei PrimCount;
GLint BaseVertex;
GLuint BaseInstance;
};
/**********************************************************************************/
/* transform feedback rendering */
/**********************************************************************************/
struct DrawTransformFeedback
{
GLenum Mode;
GLuint TransformFeedback;
};
struct DrawTransformFeedbackStream
{
GLenum Mode;
GLuint TransformFeedback;
GLuint Stream;
};
struct DrawTransformFeedbackInstanced
{
GLenum Mode;
GLuint TransformFeedback;
GLsizei InstanceCount;
};
struct DrawTransformFeedbackStreamInstanced
{
GLenum Mode;
GLuint TransformFeedback;
GLuint Stream;
GLsizei InstanceCount;
};
/**********************************************************************************/
/* indirect rendering */
/**********************************************************************************/
/* argument type buffered in GL_DRAW_INDIRECT_BUFFER */
struct DrawArraysIndirectCommand
{
GLuint Count;
GLuint InstanceCount;
GLuint First;
GLuint BaseInstance;
};
/* argument type buffered in GL_DRAW_INDIRECT_BUFFER */
struct DrawElementsIndirectCommand
{
GLuint Count;
GLuint InstanceCount;
GLuint FirstIndex;
GLuint BaseVertex;
GLuint BaseInstance;
};
struct DrawArraysIndirect
{
GLenum Mode;
const GLvoid* Indirect;
};
struct MultiDrawArraysIndirect
{
GLenum Mode;
const GLvoid* Indirect;
GLsizei DrawCount;
GLsizei Stride;
};
struct DrawElementsIndirect
{
GLenum Mode;
GLenum Type;
const GLvoid* Indirect;
};
struct MultiDrawElementsIndirect
{
GLenum Mode;
GLenum Type;
const GLvoid* Indirect;
GLsizei DrawCount;
GLsizei Stride;
};
/**********************************************************************************/
/*
conditional rendering
https://www.khronos.org/opengl/wiki/Vertex_Rendering#Conditional_rendering
occlusion query object needed:
... start occlusion query ...
glBeginConditionalRender(GLuint occlusion_query, GLenum mode​);
... render here complex ...
glEndConditionalRender();
*/
/* render commands */
/**********************************************************************************/
inline void Draw(const DrawArrays& cmd)
{
glDrawArrays(cmd.Mode, cmd.First, cmd.Count);
}
inline void Draw(const DrawElements& cmd)
{
glDrawElements(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices);
}
inline void Draw(const MultiDrawArrays& cmd)
{
glMultiDrawArrays(cmd.Mode, cmd.First, cmd.Count, cmd.DrawCount);
}
inline void Draw(const MultiDrawElements& cmd)
{
glMultiDrawElements(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.DrawCount);
}
inline void Draw(const DrawElementsBaseVertex& cmd)
{
glDrawElementsBaseVertex(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.BaseVertex);
}
inline void Draw(const DrawArraysInstanced& cmd)
{
glDrawArraysInstanced(cmd.Mode, cmd.First, cmd.Count, cmd.InstanceCount);
}
inline void Draw(const DrawElementsInstanced& cmd)
{
glDrawElementsInstanced(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.InstanceCount);
}
inline void Draw(const DrawArraysInstancedBaseInstance& cmd)
{
glDrawArraysInstancedBaseInstance(cmd.Mode, cmd.First, cmd.Count, cmd.InstanceCount, cmd.BaseInstance);
}
inline void Draw(const DrawElementsInstancedBaseInstance& cmd)
{
glDrawElementsInstancedBaseInstance(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.InstanceCount, cmd.BaseInstance);
}
inline void Draw(const DrawRangeElements& cmd)
{
glDrawRangeElements(cmd.Mode, cmd.Start, cmd.End, cmd.Count, cmd.Type, cmd.Indices);
}
inline void Draw(const MultiDrawElementsBaseVertex& cmd)
{
glMultiDrawElementsBaseVertex(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.Drawcount, cmd.BaseVertex);
}
inline void Draw(const DrawRangeElementsBaseVertex& cmd)
{
glDrawRangeElementsBaseVertex(cmd.Mode, cmd.Start, cmd.End, cmd.Count, cmd.Type, cmd.Indices, cmd.BaseVertex);
}
inline void Draw(const DrawElementsInstancedBaseVertex& cmd)
{
glDrawElementsInstancedBaseVertex(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.PrimCount, cmd.BaseVertex);
}
inline void Draw(const DrawElementsInstancedBaseVertexBaseInstance& cmd)
{
glDrawElementsInstancedBaseVertexBaseInstance(cmd.Mode, cmd.Count, cmd.Type, cmd.Indices, cmd.PrimCount, cmd.BaseVertex, cmd.BaseInstance);
}
inline void Draw(const DrawTransformFeedback& cmd)
{
glDrawTransformFeedback(cmd.Mode, cmd.TransformFeedback);
}
inline void Draw(const DrawTransformFeedbackStream& cmd)
{
glDrawTransformFeedbackStream(cmd.Mode, cmd.TransformFeedback, cmd.Stream);
}
inline void Draw(const DrawTransformFeedbackInstanced& cmd)
{
glDrawTransformFeedbackInstanced(cmd.Mode, cmd.TransformFeedback, cmd.InstanceCount);
}
inline void Draw(const DrawTransformFeedbackStreamInstanced& cmd)
{
glDrawTransformFeedbackStreamInstanced(cmd.Mode, cmd.TransformFeedback, cmd.Stream, cmd.InstanceCount);
}
inline void Draw(const DrawArraysIndirect& cmd)
{
glDrawArraysIndirect(cmd.Mode, cmd.Indirect);
}
inline void Draw(const MultiDrawArraysIndirect& cmd)
{
glMultiDrawArraysIndirect(cmd.Mode, cmd.Indirect, cmd.DrawCount, cmd.Stride);
}
inline void Draw(const DrawElementsIndirect& cmd)
{
glDrawElementsIndirect(cmd.Mode, cmd.Type, cmd.Indirect);
}
inline void Draw(const MultiDrawElementsIndirect& cmd)
{
glMultiDrawElementsIndirect(cmd.Mode, cmd.Type, cmd.Indirect, cmd.DrawCount, cmd.Stride);
}
/**********************************************************************************/
#endif // DRAWCOMMANDS_H
Graphics.cpp
#include "Graphics.h"
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <iostream>
#include <vector>
#include "Shader.h"
#include "DrawCommands.h"
using namespace std;
using namespace glm;
struct Vertex
{
vec3 Position;
vec4 Color;
};
uvec2 framebuffersize(0, 0);
GLuint program = 0;
GLuint vertexshader = 0;
GLuint fragmentshader = 0;
GLuint vertexarray = 0;
GLuint vertexbuffer = 0;
DrawArrays drawarrays_triangle;
bool Graphics::Initialize(unsigned int width, unsigned int height)
{
/* set view port */
Resize(width, height);
/* general settings */
glClearColor(0.3f, 0.3f, 0.3f, 0.0f); /* background gray */
glEnable(GL_DEPTH_TEST);
/* create all objects */
program = glCreateProgram();
vertexshader = glCreateShader(GL_VERTEX_SHADER);
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glGenVertexArrays(1, &vertexarray);
glGenBuffers(1, &vertexbuffer);
/* shader source */
string vertexshader_source(
"#version 450 core\n"
"layout (location = 0) in vec3 in_position;"
"layout (location = 1) in vec4 in_color;"
"layout (location = 0) uniform mat4 Model = mat4(1);"
"layout (location = 4) uniform mat4 View = mat4(1);"
"layout (location = 8) uniform mat4 Projection = mat4(1);"
"smooth out vec4 color;"
"void main() {"
"mat4 MVP = Projection * View * Model;"
"gl_Position = MVP * vec4(in_position, 1);"
"color = in_color;"
"}"
);
string fragmentshader_source(
"#version 450 core\n"
"smooth in vec4 color;"
"layout (location = 0) out vec4 out_color;"
"void main() {"
"out_color = color;"
"}"
);
/* compile shaders */
if (!CompileShader(vertexshader, vertexshader_source))
return false;
if (!CompileShader(fragmentshader, fragmentshader_source))
return false;
/* link program */
if (!LinkProgram(program, { vertexshader, fragmentshader }))
return false;
/* setup vertexarray */
glBindVertexArray(vertexarray);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, Position)));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, Color)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
/* create vertices */
vector<Vertex> vertices;
vertices.push_back({ { 0, 0, 0}, { 1, 0, 0, 1 } });
vertices.push_back({ { 1, 0, 0}, { 0, 1, 0, 1 } });
vertices.push_back({ { 0, 1, 0}, { 0, 0, 1, 1 } });
/* the parameters for a "glDrawArrays(...)" call */
drawarrays_triangle = { GL_TRIANGLES, 0, 3 };
/* setup vertexbuffer */
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/* successfully initialized */
return true;
}
void Graphics::CleanUp()
{
/* destroy all objects */
glDeleteProgram(program);
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
glDeleteVertexArrays(1, &vertexarray);
glDeleteBuffers(1, &vertexbuffer);
}
void Graphics::Render(const Scene& scene)
{
float aspectratio= (float)framebuffersize.x / framebuffersize.y;
mat4 View = scene.camera.View();
mat4 Projection = scene.camera.Projection(aspectratio);
/* view and projection matrix */
glProgramUniformMatrix4fv(program, 4, 1, GL_FALSE, value_ptr(View));
glProgramUniformMatrix4fv(program, 8, 1, GL_FALSE, value_ptr(Projection));
/* clear framebuffer */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw triangles */
glUseProgram(program);
glBindVertexArray(vertexarray);
for (auto& object : scene.triangles)
{
mat4 Model = object.Transformation();
glUniformMatrix4fv(0, 1, GL_FALSE, value_ptr(Model));
/* render triangle */
Draw(drawarrays_triangle);
}
glBindVertexArray(0);
glUseProgram(0);
CheckForGLError();
}
void Graphics::Resize(unsigned int width, unsigned int height)
{
framebuffersize = uvec2(width, height);
glViewport(0, 0, width, height);
}
GLContextInfo Graphics::GetContextInfos()
{
GLContextInfo infos;
glGetIntegerv(GL_MAJOR_VERSION, &infos.Version.Major);
glGetIntegerv(GL_MINOR_VERSION, &infos.Version.Minor);
infos.Version.Driver = (const char*)glGetString(GL_VERSION);
infos.Vendor = (const char*)glGetString(GL_VENDOR);
infos.Renderer = (const char*)glGetString(GL_RENDERER);
infos.Version.ShadingLanguage = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
GLint numberofextensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numberofextensions);
for (int i = 0; i < numberofextensions; i++)
infos.SupportedExtensions.push_back((const char*)glGetStringi(GL_EXTENSIONS, i));
GLint numberofsupportedglslversions = 0;
glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &numberofsupportedglslversions);
for (int i = 0; i < numberofsupportedglslversions; i++)
infos.SupportedGLSLVersions.push_back((const char*)glGetStringi(GL_SHADING_LANGUAGE_VERSION, i));
return infos;
}
void Graphics::CheckForGLError()
{
for (GLenum error; (error = glGetError()) != GL_NO_ERROR;)
{
cout << "OpenGL Error: \t";
if (error == GL_INVALID_ENUM)
cout << "GL_INVALID_ENUM";
if (error == GL_INVALID_VALUE)
cout << "GL_INVALID_VALUE";
if (error == GL_INVALID_OPERATION)
cout << "GL_INVALID_OPERATION";
if (error == GL_STACK_OVERFLOW)
cout << "GL_STACK_OVERFLOW";
if (error == GL_STACK_UNDERFLOW)
cout << "GL_STACK_UNDERFLOW";
if (error == GL_OUT_OF_MEMORY)
cout << "GL_OUT_OF_MEMORY";
if (error == GL_INVALID_FRAMEBUFFER_OPERATION)
cout << "GL_INVALID_FRAMEBUFFER_OPERATION";
if (error == GL_CONTEXT_LOST)
cout << "GL_CONTEXT_LOST";
cout << (char)7 << endl; /*play sound*/
cin.get();
}
}