paysages3d/src/render/opengl/OpenGLVertexArray.cpp
2016-07-23 22:58:32 +02:00

131 lines
3.9 KiB
C++

#include "OpenGLVertexArray.h"
#include "Logs.h"
#include "OpenGLFunctions.h"
#include "Vector3.h"
OpenGLVertexArray::OpenGLVertexArray(bool has_uv, bool strip) : has_uv(has_uv) {
if (strip) {
draw_mode = GL_TRIANGLE_STRIP;
} else {
draw_mode = GL_TRIANGLES;
}
vao = 0;
vbo_vertex = 0;
vbo_uv = 0;
changed = false;
vertexcount = 0;
array_vertex = (float *)malloc(sizeof(float));
array_uv = (float *)malloc(sizeof(float));
}
OpenGLVertexArray::~OpenGLVertexArray() {
if (vao || vbo_vertex || vbo_uv) {
Logs::warning("OpenGL") << "VertexArray not freed in OpenGL state before destructor called" << endl;
}
free(array_vertex);
free(array_uv);
}
void OpenGLVertexArray::destroy(OpenGLFunctions *functions) {
if (vbo_vertex) {
functions->glDeleteBuffers(1, &vbo_vertex);
vbo_vertex = 0;
}
if (vbo_uv) {
functions->glDeleteBuffers(1, &vbo_uv);
vbo_uv = 0;
}
if (vao) {
functions->glDeleteVertexArrays(1, &vao);
vao = 0;
}
}
void OpenGLVertexArray::render(OpenGLFunctions *functions, int start, int count) {
if (changed) {
changed = false;
update(functions);
}
if (vertexcount and vao) {
functions->glBindVertexArray(vao);
functions->glDrawArrays(draw_mode, start, count < 0 ? vertexcount : count);
functions->glBindVertexArray(0);
}
}
void OpenGLVertexArray::setVertexCount(int count) {
if (count != vertexcount) {
vertexcount = count;
if (count < 1) {
count = 1;
}
array_vertex = (float *)realloc(array_vertex, sizeof(float) * count * 3);
array_uv = (float *)realloc(array_uv, sizeof(float) * count * 2);
changed = true;
}
}
void OpenGLVertexArray::set(int index, const Vector3 &location, double u, double v) {
if (index >= 0 and index < vertexcount) {
array_vertex[index * 3] = location.x;
array_vertex[index * 3 + 1] = location.y;
array_vertex[index * 3 + 2] = location.z;
array_uv[index * 2] = u;
array_uv[index * 2 + 1] = v;
changed = true;
} else {
Logs::error("OpenGL") << "Setting vertex data outside of array bounds" << endl;
}
}
void OpenGLVertexArray::get(int index, Vector3 *location, double *u, double *v) const {
if (index >= 0 and index < vertexcount) {
location->x = array_vertex[index * 3];
location->y = array_vertex[index * 3 + 1];
location->z = array_vertex[index * 3 + 2];
*u = array_uv[index * 2];
*v = array_uv[index * 2 + 1];
} else {
Logs::error("OpenGL") << "Getting vertex data outside of array bounds" << endl;
}
}
void OpenGLVertexArray::copyTo(OpenGLVertexArray *destination) const {
destination->setVertexCount(vertexcount);
if (vertexcount) {
memcpy(destination->array_vertex, array_vertex, sizeof(float) * vertexcount * 3);
memcpy(destination->array_uv, array_uv, sizeof(float) * vertexcount * 2);
}
destination->changed = true;
}
void OpenGLVertexArray::update(OpenGLFunctions *functions) {
if (not vao) {
functions->glGenVertexArrays(1, &vao);
}
functions->glBindVertexArray(vao);
if (not vbo_vertex) {
functions->glGenBuffers(1, &vbo_vertex);
}
functions->glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex);
functions->glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexcount * 3, array_vertex, GL_STATIC_DRAW);
functions->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
functions->glEnableVertexAttribArray(0);
if (not vbo_uv) {
functions->glGenBuffers(1, &vbo_uv);
}
functions->glBindBuffer(GL_ARRAY_BUFFER, vbo_uv);
functions->glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexcount * 2, array_uv, GL_STATIC_DRAW);
functions->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
functions->glEnableVertexAttribArray(1);
functions->glBindVertexArray(0);
}