aboutsummaryrefslogtreecommitdiffstats
path: root/yage/render/spritebatch.cpp
diff options
context:
space:
mode:
authorYann Herklotz <ymherklotz@gmail.com>2017-12-25 13:54:09 +0000
committerYann Herklotz <ymherklotz@gmail.com>2017-12-25 13:54:09 +0000
commitf949692714e72a0e2d45ebb6a5d698424ab71dee (patch)
treecfab638d8c4d35c297e981773cfee1a9af3490ee /yage/render/spritebatch.cpp
parent022a4bdd81332ce67d799be6a06afb42ae45ac2e (diff)
downloadYAGE-f949692714e72a0e2d45ebb6a5d698424ab71dee.tar.gz
YAGE-f949692714e72a0e2d45ebb6a5d698424ab71dee.zip
[Broken] Reorganising and fixing.
Diffstat (limited to 'yage/render/spritebatch.cpp')
-rw-r--r--yage/render/spritebatch.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp
new file mode 100644
index 00000000..d65340d7
--- /dev/null
+++ b/yage/render/spritebatch.cpp
@@ -0,0 +1,200 @@
+/** ---------------------------------------------------------------------------
+ * @file: spritebatch.cpp
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#include "spritebatch.h"
+
+#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)
+ : num_vertices_(num_vertices), offset_(offset), texture_(texture)
+{
+}
+
+SpriteBatch::SpriteBatch()
+{
+ createVertexArray();
+}
+
+SpriteBatch::~SpriteBatch()
+{
+ if (vao_ != 0) {
+ glDeleteVertexArrays(1, &vao_);
+ }
+
+ if (vbo_ != 0) {
+ glDeleteVertexArrays(1, &vbo_);
+ }
+}
+
+void SpriteBatch::begin()
+{
+ glyphs_.clear();
+ glyph_ptrs_.clear();
+ render_batches_.clear();
+}
+
+void SpriteBatch::end()
+{
+ sortGlyphs();
+ createRenderBatches();
+}
+
+void SpriteBatch::draw(const yage::Vector4f &destination_rect,
+ const yage::Vector4f &uv_rect, GLuint texture,
+ const Colour &colour, float depth)
+{
+ Vertex top_left, top_right, bottom_right, bottom_left;
+
+ top_left.colour = colour;
+ 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.colour = colour;
+ 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.colour = colour;
+ 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.colour = colour;
+ 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());
+}
+
+void SpriteBatch::render()
+{
+ // sort and create render batches
+ sortGlyphs();
+ createRenderBatches();
+
+ glBindVertexArray(vao_);
+ for (auto &&batch : render_batches_) {
+ glBindTexture(GL_TEXTURE_2D, batch.texture());
+ glDrawArrays(GL_TRIANGLES, batch.offset(), batch.num_vertices());
+ }
+ glBindVertexArray(0);
+
+ // clear and reset the vectors
+ glyphs_.clear();
+ glyph_ptrs_.clear();
+ render_batches_.clear();
+}
+
+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, colour));
+ 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::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().num_vertices_ += 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();
+ });
+}
+
+} // namespace yage