Skip to content

Instantly share code, notes, and snippets.

@milesrout
Last active August 29, 2015 14:01
Show Gist options
  • Save milesrout/04617d0e1f7decffb547 to your computer and use it in GitHub Desktop.
Save milesrout/04617d0e1f7decffb547 to your computer and use it in GitHub Desktop.
#define GL_GLEXT_PROTOTYPES
#include <GLFW/glfw3.h>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <streambuf>
#include <string>
#include <vector>
#ifdef M_PI
#define PI M_PI
#else
#define PI 3.14159265359
#endif
template <typename T>
using vec4 = std::array<T, 4>;
template <typename T>
using vec3 = std::array<T, 3>;
template <typename T>
using vec2 = std::array<T, 2>;
struct Vertex {
vec3<GLfloat> position;
vec4<GLfloat> colour;
};
class Mesh {
GLuint vao;
union {
struct {
GLuint vbo_vertices;
GLuint vbo_indices;
};
GLuint vbo[2];
};
int numVertices;
std::vector<GLfloat> vertexData;
std::vector<GLshort> indices;
GLfloat offsetX, offsetY, offsetZ;
public:
Mesh(std::vector<Vertex>, std::vector<GLshort>);
void draw() const;
void offset(GLfloat x, GLfloat y, GLfloat z);
};
GLuint theProgram;
GLuint perspectiveMatrixUniform;
GLuint offsetUniform;
void Mesh::offset(GLfloat x, GLfloat y, GLfloat z)
{
this->offsetX = x;
this->offsetY = y;
this->offsetZ = z;
}
Mesh::Mesh(const std::vector<Vertex> vertices, const std::vector<GLshort> indices)
{
this->numVertices = vertices.size();
this->vertexData.reserve(7*this->numVertices);
for (const Vertex &vertex : vertices)
{
vertexData.push_back(vertex.position[0]);
vertexData.push_back(vertex.position[1]);
vertexData.push_back(vertex.position[2]);
vertexData.push_back(vertex.colour[0]);
vertexData.push_back(vertex.colour[1]);
vertexData.push_back(vertex.colour[2]);
vertexData.push_back(vertex.colour[3]);
}
for (const GLshort index : indices)
this->indices.push_back(index);
// Generate and bind vertex array.
glGenVertexArrays(1, &this->vao);
glBindVertexArray(this->vao);
// Generate vertex buffers.
glGenBuffers(2, this->vbo);
// Bind vertex buffer.
glBindBuffer(GL_ARRAY_BUFFER, this->vbo_vertices);
// Copy data into vertex buffer.
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*this->vertexData.size(), this->vertexData.data(), GL_STATIC_DRAW);
// Define the format of the position data.
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(GLfloat), 0);
// Define the format of the colour data.
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
// Clean up
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Bind index buffer.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->vbo_indices);
// Copy data into vertex buffer.
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLshort)*this->indices.size(), this->indices.data(), GL_STATIC_DRAW);
// Clean up
glBindVertexArray(0);
}
void Mesh::draw() const
{
// Bind object 1's vertex array
glBindVertexArray(this->vao);
// Offset the object.
glUniform3f(offsetUniform, this->offsetX, this->offsetY, this->offsetZ);
// Draw the triangle
glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_SHORT, 0);
// Clean up
glBindVertexArray(0);
}
std::vector<Mesh> meshes;
GLfloat frustumScale = 1.0f, zNear = 0.1f, zFar = 3.0f;
GLfloat perspectiveMatrix[16] = {0};
int degreesX = 0;
int degreesY = 0;
int degreesZ = 0;
void Display(GLFWwindow *window)
{
// Clear the screen
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(theProgram);
glUniformMatrix4fv(perspectiveMatrixUniform, 1, GL_FALSE, perspectiveMatrix);
for (Mesh &mesh : meshes)
mesh.draw();
glUseProgram(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
/*std::vector<Vertex> vertices1 = {
{{0.33f, 0.33f, -1.15f}, {1.0f, 0.2f, 0.2f, 1.0f}},
{{0.66f, 0.33f, -1.15f}, {0.2f, 1.0f, 0.2f, 1.0f}},
{{0.33f, 0.66f, -1.15f}, {0.2f, 0.2f, 1.0f, 1.0f}},
{{0.66f, 0.66f, -1.15f}, {1.0f, 1.0f, 0.2f, 1.0f}},
{{0.33f, 0.33f, -1.85f}, {0.2f, 1.0f, 1.0f, 1.0f}},
{{0.66f, 0.33f, -1.85f}, {1.0f, 0.2f, 1.0f, 1.0f}},
{{0.33f, 0.66f, -1.85f}, {1.0f, 1.0f, 1.0f, 1.0f}},
{{0.66f, 0.66f, -1.85f}, {0.2f, 0.2f, 0.2f, 1.0f}},
};*/
std::vector<Vertex> vertices1 = {
{{-0.33f, -0.33f, 0.33f}, {1.0f, 0.2f, 0.2f, 1.0f}},
{{0.33f, -0.33f, 0.33f}, {0.2f, 1.0f, 0.2f, 1.0f}},
{{-0.33f, 0.33f, 0.33f}, {0.2f, 0.2f, 1.0f, 1.0f}},
{{0.33f, 0.33f, 0.33f}, {1.0f, 1.0f, 0.2f, 1.0f}},
{{-0.33f, -0.33f, -0.33f}, {0.2f, 1.0f, 1.0f, 1.0f}},
{{0.33f, -0.33f, -0.33f}, {1.0f, 0.2f, 1.0f, 1.0f}},
{{-0.33f, 0.33f, -0.33f}, {1.0f, 1.0f, 1.0f, 1.0f}},
{{0.33f, 0.33f, -0.33f}, {0.2f, 0.2f, 0.2f, 1.0f}},
};
std::vector<GLshort> indices1 = {
0, 2, 3,
0, 3, 1,
1, 3, 7,
1, 7, 5,
5, 7, 6,
5, 6, 4,
4, 6, 2,
4, 2, 0,
2, 6, 7,
2, 7, 3,
4, 0, 5,
0, 1, 5,
};
/*
std::vector<Vertex> vertices2 = {
{{0.33f, 0.33f, -2.15f}, {1.0f, 0.2f, 0.2f, 1.0f}},
{{0.66f, 0.33f, -2.15f}, {0.2f, 1.0f, 0.2f, 1.0f}},
{{0.33f, 0.66f, -2.15f}, {0.2f, 0.2f, 1.0f, 1.0f}},
{{0.66f, 0.66f, -2.15f}, {1.0f, 1.0f, 0.2f, 1.0f}},
{{0.33f, 0.33f, -2.85f}, {0.2f, 1.0f, 1.0f, 1.0f}},
{{0.66f, 0.33f, -2.85f}, {1.0f, 0.2f, 1.0f, 1.0f}},
{{0.33f, 0.66f, -2.85f}, {1.0f, 1.0f, 1.0f, 1.0f}},
{{0.66f, 0.66f, -2.85f}, {0.2f, 0.2f, 0.2f, 1.0f}},
};
std::vector<GLshort> indices2 = {
0, 2, 3,
0, 3, 1,
1, 3, 7,
1, 7, 5,
5, 7, 6,
5, 6, 4,
4, 6, 2,
4, 2, 0,
2, 6, 7,
2, 7, 3,
4, 0, 5,
0, 1, 5,
};
*/
void InitializeVertexBuffer()
{
// meshes.emplace_back(vertices1, indices1);
// meshes.emplace_back(vertices2, indices2);
for (int i = 0; i < 2 * 2 * 2; i++)
{
meshes.emplace_back(vertices1, indices1);
meshes[i].offset(((i / 4) * 2 - 1) * 0.66f, (((i / 2) % 2) * 2 - 1) * 0.66f, -(1.66f + (i % 2)));
}
}
GLuint CreateProgram(std::vector<GLuint> shaders)
{
GLuint program = glCreateProgram();
for (GLuint shader : shaders)
glAttachShader(program, shader);
glLinkProgram(program);
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
GLint infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog = new GLchar[infoLogLength + 1];
glGetProgramInfoLog(program, infoLogLength, NULL, infoLog);
fprintf(stderr, "Linker failure: %s\n", infoLog);
delete[] infoLog;
}
return program;
}
GLuint CreateShader(GLenum type, const std::string &filename)
{
GLuint shader = glCreateShader(type);
std::ifstream shaderFile(filename);
std::string shaderText((std::istreambuf_iterator<char>(shaderFile)),
std::istreambuf_iterator<char>());
const char *fileData = shaderText.c_str();
glShaderSource(shader, 1, &fileData, NULL);
glCompileShader(shader);
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus = GL_FALSE) {
GLint infoLogLength;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar *infoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(shader, infoLogLength, NULL, infoLog);
const char *shaderType = NULL;
switch(type) {
case GL_VERTEX_SHADER: shaderType = "vertex"; break;
case GL_FRAGMENT_SHADER: shaderType = "fragment"; break;
case GL_GEOMETRY_SHADER: shaderType = "geometry"; break;
}
fprintf(stderr, "Compile failure in %s shader:\n%s\n", shaderType, infoLog);
delete[] infoLog;
}
return shader;
}
void InitializeProgram()
{
std::vector<GLuint> shaderList;
shaderList.push_back(CreateShader(GL_VERTEX_SHADER, "shader.vert"));
shaderList.push_back(CreateShader(GL_FRAGMENT_SHADER, "shader.frag"));
theProgram = CreateProgram(shaderList);
perspectiveMatrixUniform = glGetUniformLocation(theProgram, "perspectiveMatrix");
offsetUniform = glGetUniformLocation(theProgram, "offset");
for (GLuint shader : shaderList)
glDeleteShader(shader);
}
void WindowSizeCallback(GLFWwindow *window, int w, int h)
{
perspectiveMatrix[0] = frustumScale / (w / (float) h);
perspectiveMatrix[5] = frustumScale;
glViewport(0, 0, w, h);
}
void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if (action == GLFW_PRESS)
if (key == GLFW_KEY_SPACE)
if (degreesX == 0)
{
degreesX += 2;
degreesY += 2;
degreesZ += 2;
}
else
degreesX = degreesY = degreesZ = 0.0f;
}
void Initialize(GLFWwindow* window)
{
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, KeyCallback);
glfwSetWindowSizeCallback(window, WindowSizeCallback);
InitializeProgram();
InitializeVertexBuffer();
int w, h;
glfwGetFramebufferSize(window, &w, &h);
memset(perspectiveMatrix, 0, sizeof(GLfloat) * 16);
perspectiveMatrix[10] = (zFar + zNear) / (zNear - zFar);
perspectiveMatrix[14] = (2 * zFar * zNear) / (zNear - zFar);
perspectiveMatrix[11] = -1.0f;
perspectiveMatrix[0] = frustumScale / (w / (GLfloat) h);
perspectiveMatrix[5] = frustumScale;
glViewport(0, 0, w, h);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_CLAMP);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.0f, 1.0f);
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_SAMPLES, 16);
GLFWwindow *window = glfwCreateWindow(800, 800, "My Title", NULL, NULL);
Initialize(window);
while (!glfwWindowShouldClose(window)) {
Display(window);
}
return 0;
}
#version 440 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 colour_in;
uniform mat4 perspectiveMatrix;
uniform mat4 rotationMatrix;
uniform vec3 offset;
smooth out vec4 colour;
void main() {
gl_Position = perspectiveMatrix * vec4(position + offset, 1.0f);
colour = colour_in;
}
#version 440 core
smooth in vec4 colour;
smooth out vec4 colour_out;
void main() {
colour_out = colour;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment