aboutsummaryrefslogtreecommitdiffstats
path: root/yage/render
diff options
context:
space:
mode:
authorYann Herklotz <ymherklotz@gmail.com>2018-01-06 11:30:24 +0000
committerYann Herklotz <ymherklotz@gmail.com>2018-01-06 11:30:24 +0000
commitc7090180503f263c60ec34844992e0e8d4bea85a (patch)
tree6ecc5b2e16856db49de056738b36e1ba103d3049 /yage/render
parentcf4c73f2a75b470a4d4c4167105f92bc46f1926c (diff)
parent07012cf0982d3f86aebe83b5bdc4a67332c635da (diff)
downloadYAGE-c7090180503f263c60ec34844992e0e8d4bea85a.tar.gz
YAGE-c7090180503f263c60ec34844992e0e8d4bea85a.zip
Merge branch 'develop'
Diffstat (limited to 'yage/render')
-rw-r--r--yage/render/batch.h36
-rw-r--r--yage/render/drawable.h17
-rw-r--r--yage/render/ellipse.h6
-rw-r--r--yage/render/rectangle.cpp38
-rw-r--r--yage/render/rectangle.h23
-rw-r--r--yage/render/shader.cpp132
-rw-r--r--yage/render/shader.h49
-rw-r--r--yage/render/shape.h17
-rw-r--r--yage/render/sprite.cpp95
-rw-r--r--yage/render/sprite.h49
-rw-r--r--yage/render/spritebatch.cpp180
-rw-r--r--yage/render/spritebatch.h97
12 files changed, 739 insertions, 0 deletions
diff --git a/yage/render/batch.h b/yage/render/batch.h
new file mode 100644
index 00000000..6694fbcb
--- /dev/null
+++ b/yage/render/batch.h
@@ -0,0 +1,36 @@
+#ifndef YAGE_CORE_BATCH_H
+#define YAGE_CORE_BATCH_H
+
+namespace yage
+{
+
+/** The Batch class will be the base class for all the different batching
+ * processes that might use different shaders and attributes. This is necessary
+ * because when we use a different shader, we have to bind a specific number
+ * of attributes, and we might not always want to have a texture, colours and
+ * coordinates, for example, when only using simple shapes.
+ *
+ * Batching
+ * ========
+ * The purpose of batching is to combine all sprites that use the same textures
+ * so that the textures does not have to be switched out on the gpu very often.
+ * This produces a much more efficient rendering process. An implementation of
+ * this can be seen in the SpriteBatch class, as it sorts and renders the
+ * objects you give it.
+ *
+ * The reason this base class exists, is because it makes it easier to also
+ * render objects that may not need a texture, or may require multiple textures
+ * or different attributes.
+ */
+class Batch
+{
+public:
+ virtual bool init();
+ virtual void begin();
+ virtual void end();
+ virtual void render();
+};
+
+} // namespace yage
+
+#endif
diff --git a/yage/render/drawable.h b/yage/render/drawable.h
new file mode 100644
index 00000000..c126bb09
--- /dev/null
+++ b/yage/render/drawable.h
@@ -0,0 +1,17 @@
+#ifndef YAGE_CORE_DRAWABLE_H
+#define YAGE_CORE_DRAWABLE_H
+
+#include "spritebatch.h"
+
+namespace yage
+{
+
+class Drawable
+{
+public:
+ virtual void draw(SpriteBatch &sp) = 0;
+};
+
+} // namespace yage
+
+#endif
diff --git a/yage/render/ellipse.h b/yage/render/ellipse.h
new file mode 100644
index 00000000..bd0b0d3e
--- /dev/null
+++ b/yage/render/ellipse.h
@@ -0,0 +1,6 @@
+#ifndef YAGE_RENDER_ELLIPSE_H
+#define YAGE_RENDER_ELLIPSE_H
+
+
+
+#endif
diff --git a/yage/render/rectangle.cpp b/yage/render/rectangle.cpp
new file mode 100644
index 00000000..632c7ceb
--- /dev/null
+++ b/yage/render/rectangle.cpp
@@ -0,0 +1,38 @@
+#include "rectangle.h"
+
+#include "../data/vertex.h"
+
+#include <glad/glad.h>
+
+#include <cstddef>
+
+namespace yage
+{
+
+Rectangle::Rectangle(glm::vec4 position) : position_(position) {}
+
+void Rectangle::render() const
+{
+ // create vertex array
+ GLuint rect_vao, rect_vbo;
+
+ // bind vertex array object
+ glGenVertexArrays(1, &rect_vao);
+ glBindVertexArray(rect_vao);
+
+ // bind vertex buffer object
+ glGenBuffers(1, &rect_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, rect_vbo);
+
+ // enable vertex attribute arrays
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+
+ // set the vertex attribute pointers
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, position));
+
+ glBindVertexArray(0);
+}
+
+} // namepsace yage
+
diff --git a/yage/render/rectangle.h b/yage/render/rectangle.h
new file mode 100644
index 00000000..ad38caa5
--- /dev/null
+++ b/yage/render/rectangle.h
@@ -0,0 +1,23 @@
+#ifndef YAGE_RENDER_RECTANGLE_H
+#define YAGE_RENDER_RECTANGLE_H
+
+#include "shape.h"
+
+#include <glm/glm.hpp>
+
+namespace yage
+{
+
+class Rectangle : public Shape
+{
+public:
+ Rectangle(glm::vec4 position);
+ virtual void render() const;
+
+private:
+ glm::vec4 position_;
+};
+
+} // namespace yage
+
+#endif
diff --git a/yage/render/shader.cpp b/yage/render/shader.cpp
new file mode 100644
index 00000000..156c2aa1
--- /dev/null
+++ b/yage/render/shader.cpp
@@ -0,0 +1,132 @@
+/** ---------------------------------------------------------------------------
+ * @file: shader.cpp
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#include "shader.h"
+
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+using std::runtime_error;
+
+namespace yage
+{
+
+Shader::Shader(const std::string &vertex_path, const std::string &fragment_path)
+{
+ std::string vertex_source, fragment_source;
+ std::ifstream vertex_file, fragment_file;
+
+ vertex_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ fragment_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+
+ try {
+ vertex_file.open(vertex_path);
+ fragment_file.open(fragment_path);
+
+ std::ostringstream vertex_stream, fragment_stream;
+ vertex_stream << vertex_file.rdbuf();
+ fragment_stream << fragment_file.rdbuf();
+
+ vertex_file.close();
+ fragment_file.close();
+
+ vertex_source = vertex_stream.str();
+ fragment_source = fragment_stream.str();
+ } catch (std::ifstream::failure e) {
+ throw runtime_error("File could not be opened: " +
+ std::string(e.what()));
+ }
+
+ const char *vertex_source_c = vertex_source.c_str();
+ const char *fragment_source_c = fragment_source.c_str();
+
+ GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex_shader, 1, &vertex_source_c, NULL);
+ glCompileShader(vertex_shader);
+ errorCheck(vertex_shader, "vertex");
+
+ GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment_shader, 1, &fragment_source_c, NULL);
+ glCompileShader(fragment_shader);
+ errorCheck(fragment_shader, "fragment");
+
+ program_id_ = glCreateProgram();
+ glAttachShader(program_id_, vertex_shader);
+ glAttachShader(program_id_, fragment_shader);
+ glLinkProgram(program_id_);
+ errorCheck(program_id_, "program");
+
+ glDetachShader(program_id_, vertex_shader);
+ glDetachShader(program_id_, fragment_shader);
+
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+}
+
+Shader::~Shader()
+{
+ /// cleans up all the shaders and the program
+ if (program_id_ != 0) {
+ glDeleteProgram(program_id_);
+ }
+}
+
+void Shader::use() const
+{
+ glUseProgram(program_id_);
+}
+
+void Shader::setUniform(const std::string &name, int value) const
+{
+ glUniform1i(getUniformLocation(name), static_cast<GLint>(value));
+}
+
+void Shader::setUniform(const std::string &name, float value) const
+{
+ glUniform1f(getUniformLocation(name), static_cast<GLfloat>(value));
+}
+
+void Shader::setUniform(const std::string &name, const glm::mat4 &matrix) const
+{
+ glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &(matrix[0][0]));
+}
+
+GLint Shader::getUniformLocation(const std::string &uniform_name) const
+{
+ GLuint location = glGetUniformLocation(program_id_, uniform_name.c_str());
+ if (location == GL_INVALID_INDEX) {
+ throw std::runtime_error("'" + uniform_name + "' not found");
+ }
+ return location;
+}
+
+void Shader::errorCheck(GLuint shader, const std::string &shader_type) const
+{
+ int success;
+ char info_log[1024];
+ if (shader_type != std::string("program")) {
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(shader, 1024, NULL, info_log);
+ throw runtime_error(shader_type +
+ " failed to compile: " + std::string(info_log));
+ }
+ } else {
+ glGetProgramiv(shader, GL_LINK_STATUS, &success);
+ if (!success) {
+ glGetProgramInfoLog(shader, 1024, NULL, info_log);
+ throw runtime_error(shader_type +
+ " failed to link: " + std::string(info_log));
+ }
+ }
+}
+
+} // namespace yage
diff --git a/yage/render/shader.h b/yage/render/shader.h
new file mode 100644
index 00000000..7f4d2f9d
--- /dev/null
+++ b/yage/render/shader.h
@@ -0,0 +1,49 @@
+/** ---------------------------------------------------------------------------
+ * @file: shader.h
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef YAGE_RENDER_SHADER_H
+#define YAGE_RENDER_SHADER_H
+
+#include <glm/glm.hpp>
+#include <glad/glad.h>
+
+#include <string>
+
+namespace yage
+{
+
+class Shader
+{
+public:
+ Shader(const std::string &vertex_path, const std::string &fragment_path);
+ Shader(const Shader &) = delete;
+ Shader(Shader &&) = delete;
+ ~Shader();
+
+ Shader &operator=(const Shader &) = delete;
+ Shader &operator=(Shader &&) = delete;
+
+ /// compiles vertex and fragment shader
+ void use() const;
+
+ /// set uniforms of different type
+ void setUniform(const std::string &name, int value) const;
+ void setUniform(const std::string &name, float value) const;
+ void setUniform(const std::string &name, const glm::mat4 &matrix) const;
+
+private:
+ /// compiled shader program id
+ GLuint program_id_ = 0;
+
+ GLint getUniformLocation(const std::string &uniform_name) const;
+ void errorCheck(GLuint shader, const std::string &shader_type) const;
+};
+
+} // namespace yage
+
+#endif
diff --git a/yage/render/shape.h b/yage/render/shape.h
new file mode 100644
index 00000000..1fdf1c4f
--- /dev/null
+++ b/yage/render/shape.h
@@ -0,0 +1,17 @@
+#ifndef YAGE_RENDER_SHAPE_H
+#define YAGE_RENDER_SHAPE_H
+
+#include "drawable.h"
+
+namespace yage
+{
+
+class Shape : public Drawable
+{
+public:
+ virtual void render() const;
+};
+
+} // namespace yage
+
+#endif
diff --git a/yage/render/sprite.cpp b/yage/render/sprite.cpp
new file mode 100644
index 00000000..98853c94
--- /dev/null
+++ b/yage/render/sprite.cpp
@@ -0,0 +1,95 @@
+/** ---------------------------------------------------------------------------
+ * @file: sprite.cpp
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#include "sprite.h"
+#include "../core/resourcemanager.h"
+#include "../data/vertex.h"
+
+#include <cstddef>
+
+namespace yage
+{
+
+Sprite::~Sprite()
+{
+ if (vbo_id_ != 0) {
+ glDeleteBuffers(1, &vbo_id_);
+ }
+}
+
+void Sprite::init(float x, float y, float width, float height,
+ const std::string &texture_path)
+{
+ x_ = x;
+ y_ = y;
+ width_ = width;
+ height_ = height;
+ texture_ = ResourceManager::getTexture(texture_path);
+
+ if (vbo_id_ == 0) {
+ glGenBuffers(1, &vbo_id_);
+ }
+
+ Vertex vertex_data[6];
+
+ vertex_data[0].setPosition(x + width, y + height);
+ vertex_data[0].setUv(1.f, 1.f);
+
+ vertex_data[1].setPosition(x, y + height);
+ vertex_data[1].setUv(0.f, 1.f);
+
+ vertex_data[2].setPosition(x, y);
+ vertex_data[2].setUv(0.f, 0.f);
+
+ vertex_data[3].setPosition(x, y);
+ vertex_data[3].setUv(0.f, 0.f);
+
+ vertex_data[4].setPosition(x + width, y + height);
+ vertex_data[4].setUv(1.f, 1.f);
+
+ vertex_data[5].setPosition(x + width, y);
+ vertex_data[5].setUv(1.f, 0.f);
+
+ for (auto &i : vertex_data) {
+ i.setColour(255, 0, 255, 255);
+ }
+
+ vertex_data[1].setColour(0, 255, 255, 255);
+ vertex_data[4].setColour(255, 0, 0, 255);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_id_);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+void Sprite::draw()
+{
+ glBindTexture(GL_TEXTURE_2D, texture_.id);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_id_);
+
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+
+ 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);
+
+ glDisableVertexAttribArray(2);
+ glDisableVertexAttribArray(1);
+ glDisableVertexAttribArray(0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+} // namespace yage
diff --git a/yage/render/sprite.h b/yage/render/sprite.h
new file mode 100644
index 00000000..51821be5
--- /dev/null
+++ b/yage/render/sprite.h
@@ -0,0 +1,49 @@
+/** ---------------------------------------------------------------------------
+ * @file: sprite.h
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef SPRITE_H
+#define SPRITE_H
+
+#include "../data/texture.h"
+
+#include <glad/glad.h>
+
+#include <string>
+
+namespace yage
+{
+
+/** @deprecated Use SpriteBatch instead
+ */
+class Sprite
+{
+private:
+ float x_;
+ float y_;
+ float width_;
+ float height_;
+ GLuint vbo_id_ = 0;
+ Texture texture_;
+
+public:
+ Sprite() = default;
+ Sprite(const Sprite &) = delete;
+ Sprite(Sprite &&) = delete;
+ ~Sprite();
+
+ Sprite &operator=(const Sprite &) = delete;
+ Sprite &operator=(Sprite &&) = delete;
+
+ void init(float x, float y, float width, float height,
+ const std::string &texture_path);
+ void draw();
+};
+
+} // namespace yage
+
+#endif
diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp
new file mode 100644
index 00000000..90958246
--- /dev/null
+++ b/yage/render/spritebatch.cpp
@@ -0,0 +1,180 @@
+/** ---------------------------------------------------------------------------
+ * @file: spritebatch.cpp
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#include "spritebatch.h"
+
+#include "../core/logger.h"
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+
+using std::cout;
+
+#include <GLFW/glfw3.h>
+
+namespace yage
+{
+
+const int SpriteBatch::NUM_VERTICES;
+
+SpriteBatch::SpriteBatch() : vao_(0), vbo_(0)
+{
+ glGenVertexArrays(1, &vao_);
+ if (vao_ == 0) {
+ throw std::runtime_error("failed to generate VAO");
+ }
+ // bind vertex array object
+ glBindVertexArray(vao_);
+
+ glGenBuffers(1, &vbo_);
+ if (vbo_ == 0) {
+ throw std::runtime_error("failed to generate VBO");
+ }
+ // bind vertex buffer object
+ glBindBuffer(GL_ARRAY_BUFFER, vbo_);
+
+ // 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));
+
+ // enable vertex attribute arrays
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+}
+
+SpriteBatch::~SpriteBatch()
+{
+ if (vbo_ != 0) {
+ glDeleteBuffers(1, &vbo_);
+ }
+ if (vao_ != 0) {
+ glDeleteVertexArrays(1, &vao_);
+ }
+}
+
+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 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);
+}
+
+void SpriteBatch::render()
+{
+ glBindVertexArray(vao_);
+ // sort and create render batches
+ sortGlyphs();
+ createRenderBatches();
+ glActiveTexture(GL_TEXTURE0);
+ for (auto &&batch : render_batches_) {
+ yLogDebug << "Drawing " << batch.num_vertices
+ << " vertices bound to texture: " << batch.texture;
+ glBindTexture(GL_TEXTURE_2D, batch.texture);
+ glDrawArrays(GL_TRIANGLES, batch.offset, batch.num_vertices);
+ }
+
+ // clear and reset the vectors
+ glyphs_.clear();
+ glyph_ptrs_.clear();
+ render_batches_.clear();
+}
+
+void SpriteBatch::createRenderBatches()
+{
+ std::vector<Vertex> vertices;
+ if (glyph_ptrs_.empty()) {
+ return;
+ }
+
+ vertices.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]->top_right);
+ vertices.push_back(glyph_ptrs_[i]->bottom_right);
+ vertices.push_back(glyph_ptrs_[i]->bottom_left);
+ }
+
+ // orphan the buffer
+ glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), nullptr,
+ GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex),
+ vertices.data());
+}
+
+void SpriteBatch::sortGlyphs()
+{
+ glyph_ptrs_.reserve(glyphs_.size());
+ for (auto &glyph : glyphs_) {
+ glyph_ptrs_.push_back(&glyph);
+ }
+
+ // sort using introsort or quicksort
+ std::sort(glyph_ptrs_.begin(), glyph_ptrs_.end(),
+ [](details::Glyph *a, details::Glyph *b) -> bool {
+ if (a->depth == b->depth) {
+ return a->texture < b->texture;
+ }
+ return a->depth < b->depth;
+ });
+}
+
+} // namespace yage
diff --git a/yage/render/spritebatch.h b/yage/render/spritebatch.h
new file mode 100644
index 00000000..fb9f6337
--- /dev/null
+++ b/yage/render/spritebatch.h
@@ -0,0 +1,97 @@
+/** ---------------------------------------------------------------------------
+ * @file: spritebatch.h
+ *
+ * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com>
+ * MIT License, see LICENSE file for more details.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef YAGE_SPRITE_BATCH_H
+#define YAGE_SPRITE_BATCH_H
+
+#include "../data/vertex.h"
+#include "batch.h"
+
+#include <glad/glad.h>
+#include <glm/glm.hpp>
+
+#include <vector>
+
+namespace yage
+{
+
+namespace details
+{
+
+struct RenderBatch {
+ GLint offset;
+ GLsizei num_vertices;
+ GLuint texture;
+
+ RenderBatch(GLint offset_i, GLsizei num_vertices_i, GLuint texture_i)
+ : offset(offset_i), num_vertices(num_vertices_i), texture(texture_i)
+ {
+ }
+};
+
+/** Glyph with information of the texture.
+ */
+struct Glyph {
+ GLuint texture;
+ float depth;
+ Vertex top_left;
+ Vertex top_right;
+ Vertex bottom_right;
+ Vertex bottom_left;
+
+ Glyph(GLuint texture_i, float depth_i, const Vertex &top_left_i,
+ const Vertex &top_right_i, const Vertex &bottom_right_i,
+ const Vertex &bottom_left_i)
+ : texture(texture_i), depth(depth_i), top_left(top_left_i),
+ top_right(top_right_i), bottom_right(bottom_right_i),
+ bottom_left(bottom_left_i)
+ {
+ }
+};
+
+} // namespace details
+
+class SpriteBatch
+{
+public:
+ static const int NUM_VERTICES = 6;
+
+private:
+ GLuint vao_;
+ GLuint vbo_;
+ std::vector<details::Glyph> glyphs_;
+ std::vector<details::Glyph *> glyph_ptrs_;
+ std::vector<details::RenderBatch> render_batches_;
+
+public:
+ SpriteBatch();
+ SpriteBatch(const SpriteBatch &) = delete;
+ SpriteBatch(SpriteBatch &&) = delete;
+ ~SpriteBatch();
+
+ SpriteBatch &operator=(const SpriteBatch &) = delete;
+ SpriteBatch &operator=(SpriteBatch &&) = delete;
+
+ // initialize vaos and vbos
+ void begin();
+ void end();
+
+ // adds a sprite to the sprite batch to be rendered later
+ void draw(const glm::vec4 &destination_rect, const glm::vec4 &uv_rect,
+ GLuint texture, const Colour &colour, float depth);
+ // render the batch
+ void render();
+
+private:
+ void createRenderBatches();
+ void sortGlyphs();
+};
+
+} // namespace yage
+
+#endif