Skip to content

Instantly share code, notes, and snippets.

@roxlu

roxlu/Grid.cpp Secret

Created June 7, 2015 21:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save roxlu/82273f36a0f4de6c1954 to your computer and use it in GitHub Desktop.
Save roxlu/82273f36a0f4de6c1954 to your computer and use it in GitHub Desktop.
Easy embeddable OpenGL Grid drawer
#include <Grid.h>
/* ------------------------------------------------------------------------*/
/* Embeddable OpenGL wrappers. */
/* ------------------------------------------------------------------------*/
static int create_shader(GLuint* out, GLenum type, const char* src); /* create a shader, returns 0 on success, < 0 on error. e.g. create_shader(&vert, GL_VERTEX_SHADER, DRAWER_VS); */
static int create_program(GLuint* out, GLuint vert, GLuint frag, int link); /* create a program from the given vertex and fragment shader. returns 0 on success, < 0 on error. e.g. create_program(&prog, vert, frag, 1); */
static int print_shader_compile_info(GLuint shader); /* prints the compile info of a shader. returns 0 when shader compiled, < 0 on error. */
static int print_program_link_info(GLuint prog); /* prints the program link info. returns 0 on success, < 0 on error. */
/* ------------------------------------------------------------------------*/
static const char* GRID_VS = ""
"#version 330\n"
""
"uniform mat4 u_pm;"
"uniform mat4 u_vm;"
""
"layout (location = 0) in vec4 a_pos;"
"layout (location = 1) in vec4 a_col;"
""
"out vec4 v_col;"
""
"void main() {"
" gl_Position = u_pm * u_vm * a_pos;"
" v_col = a_col;"
"}"
"";
static const char* GRID_FS = ""
"#version 330\n"
""
"layout (location = 0) out vec4 fragcolor;"
""
"in vec4 v_col;"
""
"void main() {"
" fragcolor = v_col;"
"}"
"";
/* ------------------------------------------------------------------------*/
GLuint Grid::vert = 0;
GLuint Grid::frag = 0;
GLuint Grid::prog = 0;
GLint Grid::u_vm = -1;
GLint Grid::u_pm = -1;
/* ------------------------------------------------------------------------*/
Grid::Grid()
:vao(0)
,vbo(0)
{
}
Grid::~Grid() {
if (0 != vao) {
glDeleteVertexArrays(1, &vao);
vao = 0;
}
if (0 != vbo) {
glDeleteBuffers(1, &vbo);
vbo = 0;
}
}
int Grid::init(int hcols, int hrows, float step) {
/* (Cached) variables that we use when creating the vertices for the grid. */
int half_rows = hrows;
int half_cols = hcols;
int cols = half_cols * 2;
int rows = half_rows * 2;
float size_w = step * cols;
float size_h = step * rows;
float half_size_w = size_w * 0.5;
float half_size_h = size_h * 0.5;
float z = 0.0f;
float x = 0.0f;
/* Colors. */
float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f};
float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
float green[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
float blue[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
float gray[4] = { 0.3f, 0.3f, 0.3f, 0.6f };
/* Create shader */
if (0 == vert) {
if (0 != create_shader(&vert, GL_VERTEX_SHADER, GRID_VS)) {
printf("Error: cannot create the grid vertex shader.\n");
return -1;
}
if (0 != create_shader(&frag, GL_FRAGMENT_SHADER, GRID_FS)) {
printf("Error: cannot create the grid fragment shader.\n");
/* @todo delete vert shader. */
return -2;
}
if (0 != create_program(&prog, vert, frag, 1)) {
printf("Error: cannot create program.\n");
/* @todo delete vert, frag, prog shader. */
return -3;
}
glUseProgram(prog);
u_pm = glGetUniformLocation(prog, "u_pm");
u_vm = glGetUniformLocation(prog, "u_vm");
if (-1 == u_pm) {
printf("Error: failed to get the u_pm uniform.\n");
/* @todo delete vert, frag, prog shader. */
return -4;
}
if (-1 == u_vm) {
printf("Error: failed to get the u_vm uniform.\n");
/* @todo delete vert, frag, prog shader. */
return -5;
}
}
vertices.clear();
/* Recreate? */
if (0 != vao) {
glDeleteVertexArrays(1, &vao);
vao = 0;
}
if (0 != vbo) {
glDeleteBuffers(1, &vbo);
vbo = 0;
}
/* Column lines and axis. */
for (int i = 1; i < cols; ++i) {
x = -half_size_w + i * step;
if (i != half_cols) {
addVertex(x, 0.0f, -half_size_h, gray);
addVertex(x, 0.0f, half_size_h, gray);
}
else {
/* Z-axis. */
addVertex(x, 0.0f, 0.0f, blue);
addVertex(x, 0.0f, -half_size_h, blue);
addVertex(x, 0.0f, half_size_h, gray);
addVertex(x, 0.0f, 0.0f, gray);
}
}
/* Row lines and axis */
for (int j = 1; j < rows; ++j) {
z = -half_size_h + j * step;
if (j != half_rows) {
addVertex(-half_size_w, 0.0f, z, gray);
addVertex(half_size_w, 0.0f, z, gray);
}
else {
/* X-axis. */
addVertex(0.0f, 0.0f, z, red);
addVertex(half_size_w, 0.0f, z, red);
addVertex(-half_size_w, 0.0f, z, gray);
addVertex(0.0f, 0.0f, z, gray);
}
}
/* Y-axis */
addVertex(0.0f, 0.0f, 0.0f, green);
addVertex(0.0f, half_size_w, 0.0f, green);
/* Lines around grid. */
addVertex(-half_size_w, 0.0f, half_size_h, white);
addVertex(half_size_w, 0.0f, half_size_h, white);
addVertex(-half_size_w, 0.0f, -half_size_h, white);
addVertex(half_size_w, 0.0f, -half_size_h, white);
addVertex(-half_size_w, 0.0f, half_size_h, white);
addVertex(-half_size_w, 0.0f, -half_size_h, white);
addVertex(half_size_w, 0.0f, half_size_h, white);
addVertex(half_size_w, 0.0f, -half_size_h, white);
/* VBO + VAO */
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GridVertex) * vertices.size(), &vertices[0].pos[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GridVertex), (GLvoid*)0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(GridVertex), (GLvoid*)12);
return 0;
}
void Grid::draw(float* pm, float* vm) {
if (0 == vertices.size()) {
return;
}
glBindVertexArray(vao);
glUseProgram(prog);
glUniformMatrix4fv(u_vm, 1, GL_FALSE, vm);
glUniformMatrix4fv(u_pm, 1, GL_FALSE, pm);
glDrawArrays(GL_LINES, 0, vertices.size());
}
/* ------------------------------------------------------------------------*/
/* Embeddable OpenGL wrappers. */
/* ------------------------------------------------------------------------*/
static int create_shader(GLuint* out, GLenum type, const char* src) {
*out = glCreateShader(type);
glShaderSource(*out, 1, &src, NULL);
glCompileShader(*out);
if (0 != print_shader_compile_info(*out)) {
*out = 0;
return -1;
}
return 0;
}
/* create a program, store the result in *out. when link == 1 we link too. returns -1 on error, otherwise 0 */
static int create_program(GLuint* out, GLuint vert, GLuint frag, int link) {
*out = glCreateProgram();
glAttachShader(*out, vert);
glAttachShader(*out, frag);
if(1 == link) {
glLinkProgram(*out);
if (0 != print_program_link_info(*out)) {
*out = 0;
return -1;
}
}
return 0;
}
/* checks + prints program link info. returns 0 when linking didn't result in an error, on link erorr < 0 */
static int print_program_link_info(GLuint prog) {
GLint status = 0;
GLint count = 0;
GLchar* error = NULL;
GLsizei nchars = 0;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if(status) {
return 0;
}
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &count);
if(count <= 0) {
return 0;
}
error = (GLchar*)malloc(count);
glGetProgramInfoLog(prog, count, &nchars, error);
if (nchars <= 0) {
free(error);
error = NULL;
return -1;
}
printf("\nPROGRAM LINK ERROR");
printf("\n--------------------------------------------------------\n");
printf("%s", error);
printf("--------------------------------------------------------\n\n");
free(error);
error = NULL;
return -1;
}
/* checks the compile info, if it didn't compile we return < 0, otherwise 0 */
static int print_shader_compile_info(GLuint shader) {
GLint status = 0;
GLint count = 0;
GLchar* error = NULL;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if(status) {
return 0;
}
error = (GLchar*) malloc(count);
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &count);
if(count <= 0) {
free(error);
error = NULL;
return 0;
}
glGetShaderInfoLog(shader, count, NULL, error);
printf("\nSHADER COMPILE ERROR");
printf("\n--------------------------------------------------------\n");
printf("%s", error);
printf("--------------------------------------------------------\n\n");
free(error);
error = NULL;
return -1;
}
/* ------------------------------------------------------------------------*/
/* -*-c++-*- */
/*
Grid
====
This class generated the vertices for a 3D grid, using the XZ-Plane to draw a
Grid. This class uses OpenGL to drow the grid; doesn't do any fancy stuff.
The lines that are drawn use the alpha channel; so make sure you enable
blending and set a appropriate blend func.
````c++
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
````
Example render:
---------------
https://www.flickr.com/photos/diederick/18570328802/in/dateposted-public/
*/
#ifndef GRID_H
#define GRID_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glad/glad.h>
#include <vector>
/* ------------------------------------------------------------------------*/
struct GridVertex {
float pos[3];
float col[4];
};
/* ------------------------------------------------------------------------*/
class Grid {
public:
Grid();
~Grid();
int init(int hrows, int hcols, float step); /* Initialize with the half number of rows (e.g. 5 to create 10 rows, 5 in positive and 5 along negative axis. */
void draw(float* pm, float* vm); /* Draw the grid using the given, column major projection and view matrices. */
private:
void addVertex(float x, float y, float z, float* col); /* Internally used to add a vertex for the VBO. */
void addVertex(float x, float y, float z, float r, float g, float b, float a); /* "" "" "" */
public:
static GLuint vert; /* The GL_VERTEX_SHADER */
static GLuint frag; /* The GL_FRAGMENT_SHADER */
static GLuint prog; /* The shader program we use to draw. */
static GLint u_pm; /* The location of the projection matrix. */
static GLint u_vm; /* The location of the view matrix. */
GLuint vao; /* The Vertex Array Object. */
GLuint vbo; /* The Vertex Buffer Object. */
std::vector<GridVertex> vertices; /* The vertices that are used to draw the grid. */
};
/* ------------------------------------------------------------------------*/
inline void Grid::addVertex(float x, float y, float z, float* col) {
addVertex(x, y, z, col[0], col[1], col[2], col[3]);
}
inline void Grid::addVertex(float x, float y, float z, float r, float g, float b, float a) {
GridVertex v;
v.pos[0] = x;
v.pos[1] = y;
v.pos[2] = z;
v.col[0] = r;
v.col[1] = g;
v.col[2] = b;
v.col[3] = a;
vertices.push_back(v);
}
#endif
@roxlu
Copy link
Author

roxlu commented Jun 7, 2015

Screen Shot 2015-06-07 at 22.53.46

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment