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

}

}