aboutsummaryrefslogtreecommitdiffstats
path: root/src/spritebatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/spritebatch.cpp')
-rw-r--r--src/spritebatch.cpp165
1 files changed, 134 insertions, 31 deletions
diff --git a/src/spritebatch.cpp b/src/spritebatch.cpp
index 1abcc567..8a08ea86 100644
--- a/src/spritebatch.cpp
+++ b/src/spritebatch.cpp
@@ -1,14 +1,30 @@
#include "spritebatch.hpp"
#include <algorithm>
+#include <stdexcept>
namespace yage
{
+const int SpriteBatch::NUM_VERTICES;
+
+Glyph::Glyph(GLuint texture, float depth, const Vertex &top_left, const Vertex &top_right, const Vertex &bottom_right, const Vertex &bottom_left) :
+ texture_(texture),
+ depth_(depth),
+ top_left_(top_left),
+ top_right_(top_right),
+ bottom_right_(bottom_right),
+ bottom_left_(bottom_left)
+{}
+
+RenderBatch::RenderBatch(GLint offset, GLsizei num_vertices, GLuint texture) :
+ offset_(offset),
+ num_vertices_(num_vertices),
+ texture_(texture)
+{}
+
SpriteBatch::SpriteBatch()
-{
- createVertexArray();
-}
+{}
SpriteBatch::~SpriteBatch()
{
@@ -19,48 +35,135 @@ SpriteBatch::~SpriteBatch()
glDeleteVertexArrays(1, &vbo_);
}
+void SpriteBatch::init()
+{
+ createVertexArray();
+}
+
void SpriteBatch::begin()
-{}
+{
+ glyphs_.clear();
+ glyph_ptrs_.clear();
+ render_batches_.clear();
+}
void SpriteBatch::end()
-{}
+{
+ sortGlyphs();
+ createRenderBatches();
+}
void SpriteBatch::draw(const glm::vec4 &destination_rect, const glm::vec4 &uv_rect, GLuint texture, const Color &color, float depth)
{
- Glyph new_glyph;
- new_glyph.texture=texture;
- new_glyph.depth=depth;
-
- new_glyph.top_left.color=color;
- new_glyph.top_left.setPosition(destination_rect.x, destination_rect.y+destination_rect.w);
- new_glyph.top_left.setUv(uv_rect.x, uv_rect.y+uv_rect.w);
-
- new_glyph.top_right.color=color;
- new_glyph.top_right.setPosition(destination_rect.x+destination_rect.z, destination_rect.y+destination_rect.w);
- new_glyph.top_right.setUv(uv_rect.x+uv_rect.z, uv_rect.y+uv_rect.w);
-
- new_glyph.bottom_right.color=color;
- new_glyph.bottom_right.setPosition(destination_rect.x+destination_rect.z, destination_rect.y);
- new_glyph.bottom_right.setUv(uv_rect.x+uv_rect.z, uv_rect.y);
+ Vertex top_left, top_right, bottom_right, bottom_left;
+
+ top_left.color=color;
+ top_left.setPosition(destination_rect.x, destination_rect.y+destination_rect.w);
+ top_left.setUv(uv_rect.x, uv_rect.y+uv_rect.w);
+
+ top_right.color=color;
+ top_right.setPosition(destination_rect.x+destination_rect.z, destination_rect.y+destination_rect.w);
+ top_right.setUv(uv_rect.x+uv_rect.z, uv_rect.y+uv_rect.w);
+
+ bottom_right.color=color;
+ bottom_right.setPosition(destination_rect.x+destination_rect.z, destination_rect.y);
+ bottom_right.setUv(uv_rect.x+uv_rect.z, uv_rect.y);
+
+ bottom_left.color=color;
+ bottom_left.setPosition(destination_rect.x, destination_rect.y);
+ bottom_left.setUv(uv_rect.x, uv_rect.y);
+
+ // deal with fragmenting by creating vector of pointers
+ glyphs_.emplace_back(texture, depth, top_left, top_right, bottom_right, bottom_left);
+ glyph_ptrs_.push_back(&glyphs_.back());
+}
- new_glyph.bottom_right.color=color;
- new_glyph.bottom_right.setPosition(destination_rect.x, destination_rect.y);
- new_glyph.bottom_right.setUv(uv_rect.x, uv_rect.y);
+void SpriteBatch::render()
+{
+ glBindVertexArray(vao_);
+ for(auto &&batch : render_batches_)
+ {
+ glBindTexture(GL_TEXTURE_2D, batch.texture());
+ glDrawArrays(GL_TRIANGLES, batch.offset(), batch.num_vertices());
+ }
+ glBindVertexArray(0);
+}
- // deal with fragmenting
- glyphs_.push_back(new_glyph);
- glyph_ptrs_.push_back(&glyphs_.back());
+void SpriteBatch::createVertexArray()
+{
+ if(vao_==0)
+ {
+ glGenVertexArrays(1, &vao_);
+ if(vao_==0)
+ throw std::runtime_error("glGenVertexArrays failed");
+ }
+ // bind vertex array object
+ glBindVertexArray(vao_);
+
+ if(vbo_==0)
+ {
+ glGenBuffers(1, &vbo_);
+ if(vbo_==0)
+ throw std::runtime_error("glGenBuffers failed");
+ }
+ // bind vertex buffer object
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_);
+
+ // enable vertex attribute arrays
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+
+ // set the vertex attribute pointers
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, position));
+ glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void *)offsetof(Vertex, color));
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, uv));
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ // unbind vertex array object
+ glBindVertexArray(0);
}
-void SpriteBatch::renderBatch()
-{}
+void SpriteBatch::createRenderBatches()
+{
+ std::vector<Vertex> vertices;
+ if(glyph_ptrs_.empty())
+ return;
+
+ render_batches_.reserve(glyph_ptrs_.size()*NUM_VERTICES);
+
+ for(int i=0; i<(int)glyph_ptrs_.size(); ++i)
+ {
+ if(i==0 || (i>0 && (glyph_ptrs_[i]->texture()!=glyph_ptrs_[i-1]->texture())))
+ render_batches_.emplace_back(i*NUM_VERTICES, NUM_VERTICES, glyph_ptrs_[i]->texture());
+ else
+ render_batches_.back().offset_+=NUM_VERTICES;
+
+ vertices.push_back(glyph_ptrs_[i]->bottom_left());
+ vertices.push_back(glyph_ptrs_[i]->top_left());
+ vertices.push_back(glyph_ptrs_[i]->top_right());
+ vertices.push_back(glyph_ptrs_[i]->bottom_left());
+ vertices.push_back(glyph_ptrs_[i]->bottom_right());
+ vertices.push_back(glyph_ptrs_[i]->top_right());
+
+ // bind vbo
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_);
+ // orphan the buffer
+ glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vertex), nullptr, GL_DYNAMIC_DRAW);
+ // upload the data
+ glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vertex), vertices.data());
+ // unbind buffer
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+}
void SpriteBatch::sortGlyphs()
{
+ // sort using introsort or quicksort
std::sort(glyph_ptrs_.begin(), glyph_ptrs_.end(), [] (Glyph *a, Glyph *b)->bool {
- if(a->depth==b->depth)
- return a->texture<b->texture;
- return a->depth<b->depth;
+ if(a->depth()==b->depth())
+ return a->texture()<b->texture();
+ return a->depth()<b->depth();
});
}