namespace shader {
std::string vFlat =
"#version 150" "\n"
"uniform mat4 transform, camera, projection;" "\n"
"in vec3 position, normal;" "\n"
"in vec2 uv;" "\n"
"out mat4 modelview;" "\n"
"out vec3 frag_position, frag_normal;" "\n"
"out vec2 frag_uv;" "\n"
"void main() {" "\n"
"modelview = camera * transform;" "\n"
"vec4 eye_position = modelview * vec4(position, 1.0);" "\n"
"gl_Position = projection * eye_position;" "\n"
"frag_position = eye_position.xyz;" "\n"
"frag_normal = (modelview * vec4(normal, 0.0)).xyz;" "\n"
"frag_uv = uv;" "\n"
"}";
std::string fFlat =
"#version 150" "\n"
"in mat4 modelview;" "\n"
"in vec3 frag_position, frag_normal;" "\n"
"in vec2 frag_uv;" "\n"
"uniform vec4 color;" "\n"
"const vec3 light_direction = vec3(0.408248, -0.816497, -0.408248);" "\n"
"out vec4 fragColor;" "\n"
"void main() {" "\n"
"vec3 normal = normalize(frag_normal);" "\n"
"float shade = 0.5 * (-dot(normal, normalize(light_direction)) + 1.0);" "\n"
"fragColor = vec4(color.rgb * shade, color.a);" "\n"
"}";
}
namespace gl {
struct Vertex {
glm::vec3 position;
glm::vec3 normal;
glm::vec2 uv;
};
class Object {
public:
glm::vec4 color;
GLuint data;
vector<GLushort> faces;
GLuint program;
mat4 transform;
};
}
class OBJMesh {
public:
OBJMesh(string const& filename);
vector<gl::Vertex> verts;
vector<GLushort> faces;
vector<GLushort> segments;
}
gl::Object* cube = NULL;
void load() { // assumes context is created : no errors up to this point
GLuint v = glCreateShader(GL_VERTEX_SHADER), f = glCreateShader(GL_FRAGMENT_SHADER);
GLint length = static_cast<GLint>(shader::vFlat.length());
char const* text = shader::vFlat.c_str();
glShaderSource(v, 1, &text, &length);
glCompileShader(v);
GLint status = GL_FALSE;
glGetShaderiv(v, GL_COMPILE_STATUS, &status);
length = static_cast<GLint>(shader::fFlat.length());
text = shader::fFlat.c_str();
glShaderSource(f, 1, &text, &length);
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &status);
plain = glCreateProgram();
glAttachShader(plain, v);
glAttachShader(plain, f);
glBindAttribLocation(plain, 0, "position");
glBindAttribLocation(plain, 1, "normal");
glBindAttribLocation(plain, 2, "uv");
glLinkProgram(plain);
glGetProgramiv(plain, GL_LINK_STATUS, &status);
glDetachShader(plain, v);
glDetachShader(plain, f);
glUseProgram(plain);
glUniformMatrix4fv(glGetUniformLocation(plain, "camera"), 1, GL_FALSE, glm::value_ptr(glm::lookAt(vec3(0.0f, 2.0f, 4.0f), vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f))));
glUniformMatrix4fv(glGetUniformLocation(plain, "projection"), 1, GL_FALSE, glm::value_ptr(glm::frustum(-2.0f, 2.0f, -1.5f, 1.5f, 02.0f, -5.0f)));
glUniformMatrix4fv(glGetUniformLocation(plain, "transform"), 1, GL_FALSE, glm::value_ptr(glm::mat4()));
cube = new gl::Object();
glGenVertexArrays(1, &cube->data);
cube->program = plain;
cube->color = glm::vec4(1.0f);
cube->transform = glm::mat4();
OBJMesh cubeMesh("cube.obj"); // confirmed working
GLuint vbo, ebo;
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(gl::Vertex) * cubeMesh.verts.size(), cubeMesh.verts.data(), GL_STATIC_DRAW);
glBindVertexArray(cube->data);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(gl::Vertex), reinterpret_cast<void*>(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(gl::Vertex), reinterpret_cast<void*>(sizeof(glm::vec3)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(gl::Vertex), reinterpret_cast<void*>(sizeof(glm::vec3)+sizeof(glm::vec3)));
glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(cube->data); // because of C++ wrapper class in original code
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * cubeMesh.faces.size(), cubeMesh.faces.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
cube->faces = cubeMesh.segments();
}
void render() {
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram(cube->program);
glUniform4fv(glGetUniformLocation(cube->program, "color"), 1, glm::value_ptr(cube->color));
glUniformMatrix4fv(glGetUniformLocation(cube->program, "transform"), 1, GL_FALSE, glm::value_ptr(cube->transform));
glBindVertexArray(cube->data);
GLushort position = 0;
for (GLushort range: faces) {
// THIS glDrawElements LINE YIELDS GL_OUT_OF_MEMORY ON THE FIRST CALL!!!!!
glDrawElements(GL_TRIANGLE_STRIP, range, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(position * sizeof(GLushort)));
position += range;
}
glBindVertexArray(0);
}
Comments