|
@@ -31,64 +31,131 @@ namespace opengl
|
|
{
|
|
{
|
|
|
|
|
|
Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
|
|
Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
|
|
- : draw_mode(mode)
|
|
|
|
|
|
+ : vbo(0)
|
|
|
|
+ , vertex_count(0)
|
|
|
|
+ , ibo(0)
|
|
|
|
+ , element_count(0)
|
|
|
|
+ , draw_mode(mode)
|
|
, image(0)
|
|
, image(0)
|
|
|
|
+ , colors_enabled(false)
|
|
{
|
|
{
|
|
setVertices(verts);
|
|
setVertices(verts);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+Mesh::~Mesh()
|
|
|
|
+{
|
|
|
|
+ delete vbo;
|
|
|
|
+ delete ibo;
|
|
|
|
+}
|
|
|
|
+
|
|
void Mesh::setVertices(const std::vector<Vertex> &verts)
|
|
void Mesh::setVertices(const std::vector<Vertex> &verts)
|
|
{
|
|
{
|
|
if (verts.size() < 3)
|
|
if (verts.size() < 3)
|
|
throw love::Exception("At least 3 vertices are required.");
|
|
throw love::Exception("At least 3 vertices are required.");
|
|
|
|
|
|
- vertices = verts;
|
|
|
|
-}
|
|
|
|
|
|
+ size_t size = sizeof(Vertex) * verts.size();
|
|
|
|
|
|
-const std::vector<Vertex> &Mesh::getVertices() const
|
|
|
|
-{
|
|
|
|
- return vertices;
|
|
|
|
|
|
+ if (vbo && size > vbo->getSize())
|
|
|
|
+ {
|
|
|
|
+ delete vbo;
|
|
|
|
+ vbo = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!vbo)
|
|
|
|
+ {
|
|
|
|
+ // Full memory backing because we might access the data at any time.
|
|
|
|
+ vbo = VertexBuffer::Create(size, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, VertexBuffer::BACKING_FULL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ vertex_count = verts.size();
|
|
|
|
+
|
|
|
|
+ VertexBuffer::Bind vbo_bind(*vbo);
|
|
|
|
+ VertexBuffer::Mapper vbo_mapper(*vbo);
|
|
|
|
+
|
|
|
|
+ // Fill the buffer with the vertices.
|
|
|
|
+ memcpy(vbo_mapper.get(), &verts[0], size);
|
|
}
|
|
}
|
|
|
|
|
|
-void Mesh::setVertex(size_t i, Vertex v)
|
|
|
|
|
|
+void Mesh::setVertex(size_t index, const Vertex &v)
|
|
{
|
|
{
|
|
- if (i >= vertices.size())
|
|
|
|
- throw love::Exception("Invalid index.");
|
|
|
|
|
|
+ if (index >= vertex_count)
|
|
|
|
+ throw love::Exception("Invalid vertex index: %ld", index);
|
|
|
|
+
|
|
|
|
+ VertexBuffer::Bind vbo_bind(*vbo);
|
|
|
|
|
|
- vertices[i] = v;
|
|
|
|
|
|
+ // We unmap the vertex buffer in Mesh::draw. This lets us coalesce the
|
|
|
|
+ // buffer transfer calls.
|
|
|
|
+ Vertex *vertices = (Vertex *) vbo->map();
|
|
|
|
+ vertices[index] = v;
|
|
}
|
|
}
|
|
|
|
|
|
-Vertex Mesh::getVertex(size_t i) const
|
|
|
|
|
|
+Vertex Mesh::getVertex(size_t index) const
|
|
{
|
|
{
|
|
- if (i >= vertices.size())
|
|
|
|
- throw love::Exception("Invalid index.");
|
|
|
|
|
|
+ if (index >= vertex_count)
|
|
|
|
+ throw love::Exception("Invalid vertex index: %ld", index);
|
|
|
|
|
|
- return vertices[i];
|
|
|
|
|
|
+ VertexBuffer::Bind vbo_bind(*vbo);
|
|
|
|
+
|
|
|
|
+ // We unmap the vertex buffer in Mesh::draw.
|
|
|
|
+ Vertex *vertices = (Vertex *) vbo->map();
|
|
|
|
+ return vertices[index];
|
|
}
|
|
}
|
|
|
|
|
|
size_t Mesh::getVertexCount() const
|
|
size_t Mesh::getVertexCount() const
|
|
{
|
|
{
|
|
- return vertices.size();
|
|
|
|
|
|
+ return vertex_count;
|
|
}
|
|
}
|
|
|
|
|
|
void Mesh::setVertexMap(const std::vector<uint16> &map)
|
|
void Mesh::setVertexMap(const std::vector<uint16> &map)
|
|
{
|
|
{
|
|
for (size_t i = 0; i < map.size(); i++)
|
|
for (size_t i = 0; i < map.size(); i++)
|
|
{
|
|
{
|
|
- if (map[i] >= vertices.size())
|
|
|
|
|
|
+ if (map[i] >= vertex_count)
|
|
throw love::Exception("Invalid vertex map value: %d", map[i]);
|
|
throw love::Exception("Invalid vertex map value: %d", map[i]);
|
|
}
|
|
}
|
|
|
|
|
|
- vertex_map = map;
|
|
|
|
|
|
+ size_t size = sizeof(uint16) * map.size();
|
|
|
|
+
|
|
|
|
+ if (ibo && size > ibo->getSize())
|
|
|
|
+ {
|
|
|
|
+ delete ibo;
|
|
|
|
+ ibo = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!ibo)
|
|
|
|
+ {
|
|
|
|
+ // Full memory backing because we might access the data at any time.
|
|
|
|
+ ibo = VertexBuffer::Create(size, GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, VertexBuffer::BACKING_FULL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ element_count = map.size();
|
|
|
|
+
|
|
|
|
+ if (element_count > 0)
|
|
|
|
+ {
|
|
|
|
+ VertexBuffer::Bind ibo_bind(*ibo);
|
|
|
|
+ VertexBuffer::Mapper ibo_map(*ibo);
|
|
|
|
+
|
|
|
|
+ // Fill the buffer.
|
|
|
|
+ memcpy(ibo_map.get(), &map[0], size);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-const std::vector<uint16> &Mesh::getVertexMap() const
|
|
|
|
|
|
+const uint16 *Mesh::getVertexMap() const
|
|
{
|
|
{
|
|
- return vertex_map;
|
|
|
|
|
|
+ if (ibo && element_count > 0)
|
|
|
|
+ {
|
|
|
|
+ VertexBuffer::Bind ibo_bind(*ibo);
|
|
|
|
+
|
|
|
|
+ // We unmap the buffer in Mesh::draw and Mesh::setVertexMap.
|
|
|
|
+ return (uint16 *) ibo->map();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-Mesh::~Mesh()
|
|
|
|
|
|
+size_t Mesh::getVertexMapCount() const
|
|
{
|
|
{
|
|
|
|
+ return element_count;
|
|
}
|
|
}
|
|
|
|
|
|
void Mesh::setImage(Image *img)
|
|
void Mesh::setImage(Image *img)
|
|
@@ -124,9 +191,23 @@ Mesh::DrawMode Mesh::getDrawMode() const
|
|
return draw_mode;
|
|
return draw_mode;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void Mesh::setVertexColors(bool enable)
|
|
|
|
+{
|
|
|
|
+ colors_enabled = enable;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool Mesh::hasVertexColors() const
|
|
|
|
+{
|
|
|
|
+ return colors_enabled;
|
|
|
|
+}
|
|
|
|
+
|
|
void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
|
void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
|
|
{
|
|
{
|
|
- if (vertices.size() == 0)
|
|
|
|
|
|
+ const size_t pos_offset = offsetof(Vertex, x);
|
|
|
|
+ const size_t tex_offset = offsetof(Vertex, s);
|
|
|
|
+ const size_t color_offset = offsetof(Vertex, r);
|
|
|
|
+
|
|
|
|
+ if (vertex_count == 0)
|
|
return;
|
|
return;
|
|
|
|
|
|
if (image)
|
|
if (image)
|
|
@@ -140,29 +221,49 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
|
|
glPushMatrix();
|
|
glPushMatrix();
|
|
glMultMatrixf(m.getElements());
|
|
glMultMatrixf(m.getElements());
|
|
|
|
|
|
|
|
+ VertexBuffer::Bind vbo_bind(*vbo);
|
|
|
|
+
|
|
|
|
+ // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.)
|
|
|
|
+ vbo->unmap();
|
|
|
|
+
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
|
|
- glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &(vertices[0].x));
|
|
|
|
- glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &(vertices[0].s));
|
|
|
|
|
|
+ glVertexPointer(2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(pos_offset));
|
|
|
|
+ glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(tex_offset));
|
|
|
|
|
|
|
|
+ if (hasVertexColors())
|
|
{
|
|
{
|
|
|
|
+ // Per-vertex colors.
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &(vertices[0].r));
|
|
|
|
|
|
+ glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), vbo->getPointer(color_offset));
|
|
}
|
|
}
|
|
|
|
|
|
- GLenum gl_draw_mode = getGLDrawMode(draw_mode);
|
|
|
|
|
|
+ GLenum mode = getGLDrawMode(draw_mode);
|
|
|
|
|
|
- if (vertex_map.size() > 0)
|
|
|
|
- glDrawElements(gl_draw_mode, vertex_map.size(), GL_UNSIGNED_SHORT, &vertex_map[0]);
|
|
|
|
|
|
+ if (element_count > 0)
|
|
|
|
+ {
|
|
|
|
+ VertexBuffer::Bind ibo_bind(*ibo);
|
|
|
|
+
|
|
|
|
+ // Make sure the index buffer isn't mapped (sends data to GPU if needed.)
|
|
|
|
+ ibo->unmap();
|
|
|
|
+
|
|
|
|
+ // Use the custom vertex map to draw the vertices.
|
|
|
|
+ glDrawElements(mode, element_count, GL_UNSIGNED_SHORT, ibo->getPointer(0));
|
|
|
|
+ }
|
|
else
|
|
else
|
|
- glDrawArrays(gl_draw_mode, 0, vertices.size());
|
|
|
|
|
|
+ {
|
|
|
|
+ // Normal non-indexed drawing (no custom vertex map.)
|
|
|
|
+ glDrawArrays(mode, 0, vertex_count);
|
|
|
|
+ }
|
|
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
|
|
|
|
+ if (hasVertexColors())
|
|
{
|
|
{
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
|
|
+ // Using the color array leaves the GL constant color undefined.
|
|
gl.setColor(gl.getColor());
|
|
gl.setColor(gl.getColor());
|
|
}
|
|
}
|
|
|
|
|