From f949692714e72a0e2d45ebb6a5d698424ab71dee Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Mon, 25 Dec 2017 13:54:09 +0000 Subject: [Broken] Reorganising and fixing. --- yage/render/batch.h | 39 ++++++++ yage/render/drawable.h | 15 ++++ yage/render/ellipse.h | 6 ++ yage/render/glslprogram.cpp | 215 ++++++++++++++++++++++++++++++++++++++++++++ yage/render/glslprogram.h | 58 ++++++++++++ yage/render/rectangle.h | 15 ++++ yage/render/shape.h | 16 ++++ yage/render/sprite.cpp | 95 ++++++++++++++++++++ yage/render/sprite.h | 49 ++++++++++ yage/render/spritebatch.cpp | 200 +++++++++++++++++++++++++++++++++++++++++ yage/render/spritebatch.h | 90 +++++++++++++++++++ 11 files changed, 798 insertions(+) create mode 100644 yage/render/batch.h create mode 100644 yage/render/drawable.h create mode 100644 yage/render/ellipse.h create mode 100644 yage/render/glslprogram.cpp create mode 100644 yage/render/glslprogram.h create mode 100644 yage/render/rectangle.h create mode 100644 yage/render/shape.h create mode 100644 yage/render/sprite.cpp create mode 100644 yage/render/sprite.h create mode 100644 yage/render/spritebatch.cpp create mode 100644 yage/render/spritebatch.h (limited to 'yage/render') diff --git a/yage/render/batch.h b/yage/render/batch.h new file mode 100644 index 00000000..e301531c --- /dev/null +++ b/yage/render/batch.h @@ -0,0 +1,39 @@ +#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 draw(); + virtual void render(); + +protected: +}; + +} // namespace yage + +#endif diff --git a/yage/render/drawable.h b/yage/render/drawable.h new file mode 100644 index 00000000..0e4b6843 --- /dev/null +++ b/yage/render/drawable.h @@ -0,0 +1,15 @@ +#ifndef YAGE_CORE_DRAWABLE_H +#define YAGE_CORE_DRAWABLE_H + +namespace yage +{ + +class Drawable +{ +public: + virtual void render() const; +}; + +} // 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/glslprogram.cpp b/yage/render/glslprogram.cpp new file mode 100644 index 00000000..13abbba3 --- /dev/null +++ b/yage/render/glslprogram.cpp @@ -0,0 +1,215 @@ +/** --------------------------------------------------------------------------- + * @file: glslprogram.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#include "glslprogram.h" + +#include +#include +#include + +namespace yage +{ + +GlslProgram::~GlslProgram() +{ + /// cleans up all the shaders and the program + if (fragment_shader_id_ != 0) { + glDeleteShader(fragment_shader_id_); + } + + if (vertex_shader_id_ != 0) { + glDeleteShader(vertex_shader_id_); + } + + if (program_id_ != 0) { + glDeleteProgram(program_id_); + } +} + +void GlslProgram::compileShader(GLuint shader, const std::string &shaderContent) +{ + // cast source to a c string to get the address of it and input it for + // compilation + const auto *vertex_source = (const GLchar *)shaderContent.c_str(); + glShaderSource(shader, 1, &vertex_source, nullptr); + glCompileShader(shader); + + // check if compilation was successful + GLint is_compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, (int *)&is_compiled); + + // if it isn't compiled throw exception to clean up + if (is_compiled == GL_FALSE) { + GLint max_length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); + + std::vector error_log(max_length); + glGetShaderInfoLog(shader, max_length, &max_length, &error_log[0]); + std::string error_log_str((const char *)&error_log[0]); + + std::string shaderName; + if (shader == vertex_shader_id_) + shaderName = "vertex shader"; + else + shaderName = "fragment shader"; + + throw std::runtime_error("Couldn't compile the " + shaderName + " : " + + error_log_str); + } +} + +void GlslProgram::compileShaderFromFile(GLuint shader, + const std::string &file_path) +{ + // get a string with the input from the shader file + std::ifstream file(file_path); + if (!file.is_open()) { + throw std::runtime_error("Failed to open '" + file_path + "'"); + } + + std::string content = ""; + std::string line; + + while (std::getline(file, line)) { + content += line + "\n"; + } + file.close(); + + compileShader(shader, content); +} + +void GlslProgram::initShaderId() +{ + // create the program that will be run on GPU + program_id_ = glCreateProgram(); + + // create vertex shader + vertex_shader_id_ = glCreateShader(GL_VERTEX_SHADER); + if (vertex_shader_id_ == 0) { + throw std::runtime_error("Vertex shader failed to be created"); + } + + // create fragment shader + fragment_shader_id_ = glCreateShader(GL_FRAGMENT_SHADER); + if (fragment_shader_id_ == 0) { + throw std::runtime_error("Fragment shader failed to be created"); + } +} + +void GlslProgram::compileShaders(const std::string &vertexShader, + const std::string fragmentShader) +{ + initShaderId(); + + compileShader(vertex_shader_id_, vertexShader); + compileShader(fragment_shader_id_, fragmentShader); +} + +void GlslProgram::compileShadersFromFile( + const std::string &vertex_shader_path, + const std::string &fragment_shader_path) +{ + initShaderId(); + + // compile the two shaders + compileShaderFromFile(vertex_shader_id_, vertex_shader_path); + compileShaderFromFile(fragment_shader_id_, fragment_shader_path); +} + +void GlslProgram::linkShaders() +{ + // attach the shaders that we want + glAttachShader(program_id_, vertex_shader_id_); + glAttachShader(program_id_, fragment_shader_id_); + + // link our program + glLinkProgram(program_id_); + + GLint is_linked = 0; + glGetProgramiv(program_id_, GL_LINK_STATUS, (int *)&is_linked); + if (is_linked == GL_FALSE) { + GLint max_length = 0; + glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &max_length); + + std::vector error_log(max_length); + glGetProgramInfoLog(program_id_, max_length, &max_length, + &error_log[0]); + + std::string error_log_str((const char *)&error_log[0]); + + throw std::runtime_error("Could not link program: " + error_log_str); + } + + // detach shaders after successful link + glDetachShader(program_id_, fragment_shader_id_); + glDetachShader(program_id_, vertex_shader_id_); + + // we can then delete the shaders once we have the program + glDeleteShader(fragment_shader_id_); + glDeleteShader(vertex_shader_id_); +} + +void GlslProgram::addAttribute(const std::string &attribute_name) +{ + glBindAttribLocation(program_id_, attribute_index_++, + attribute_name.c_str()); +} + +GLint GlslProgram::getUniformLocation(const std::string &uniform_name) +{ + GLint location = glGetUniformLocation(program_id_, uniform_name.c_str()); + if ((GLuint)location == GL_INVALID_INDEX) { + throw std::runtime_error("'" + uniform_name + "' not found"); + } + return location; +} + +void GlslProgram::use() +{ + glUseProgram(program_id_); + for (int i = 0; i < attribute_index_; ++i) { + glEnableVertexAttribArray(i); + } +} + +void GlslProgram::unuse() +{ + for (int i = 0; i < attribute_index_; ++i) { + glDisableVertexAttribArray(i); + } + glUseProgram(0); +} + +void GlslProgram::defaultSetup() +{ + std::string vertexShader = + "#version 130\n\nin vec2 vertex_position;\nin vec4 vertex_colour;\nin " + "vec2 vertex_uv;\n\nout vec2 fragment_position;\nout vec4 " + "fragment_colour;\nout vec2 fragment_uv;\n\nuniform mat4 P;\n\nvoid " + "main()\n{\n gl_Position.xy = (P*vec4(vertex_position, 0.0, " + "1.0)).xy;\n gl_Position.z = 0.0;\n gl_Position.w = 1.0;\n\n " + "fragment_position = vertex_position;\n fragment_colour = " + "vertex_colour;\n fragment_uv = vec2(vertex_uv.x, " + "1-vertex_uv.y);\n\n}"; + + std::string fragmentShader = + "#version 130\n\nin vec2 fragment_position;\nin vec4 " + "fragment_colour;\nin vec2 fragment_uv;\n\nout vec4 colour;\n\nuniform " + "sampler2D texture_sampler;\n\nvoid main()\n{\n vec4 texture_color " + "= texture(texture_sampler, fragment_uv);\n\n colour = " + "texture_color;\n}"; + + compileShaders(vertexShader, fragmentShader); + addAttribute("vertex_position"); + addAttribute("vertex_colour"); + addAttribute("vertex_uv"); + + linkShaders(); +} + +} // namespace yage diff --git a/yage/render/glslprogram.h b/yage/render/glslprogram.h new file mode 100644 index 00000000..0617bc1e --- /dev/null +++ b/yage/render/glslprogram.h @@ -0,0 +1,58 @@ +/** --------------------------------------------------------------------------- + * @file: glslprogram.h + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#ifndef GLSL_PROGRAM_H +#define GLSL_PROGRAM_H + +#include + +#include + +namespace yage +{ + +class GlslProgram +{ +public: + GlslProgram() = default; + GlslProgram(const GlslProgram &) = delete; + GlslProgram(GlslProgram &&) = delete; + ~GlslProgram(); + + GlslProgram &operator=(const GlslProgram &) = delete; + GlslProgram &operator=(GlslProgram &&) = delete; + + /// compiles vertex and fragment shader + void compileShaders(const std::string &vertexShader, + const std::string fragmentShader); + void compileShadersFromFile(const std::string &vertex_shader_path, + const std::string &fragment_shader_path); + void linkShaders(); + void addAttribute(const std::string &attribute_name); + GLint getUniformLocation(const std::string &uniform_name); + void use(); + void unuse(); + + void defaultSetup(); + +private: + /// compiled shader program id + GLuint program_id_ = 0; + GLuint vertex_shader_id_ = 0; + GLuint fragment_shader_id_ = 0; + int attribute_index_ = 0; + + /// compiles one shader + void compileShader(GLuint shader, const std::string &shaderContent); + void compileShaderFromFile(GLuint shader, const std::string &file_path); + void initShaderId(); +}; + +} // namespace yage + +#endif diff --git a/yage/render/rectangle.h b/yage/render/rectangle.h new file mode 100644 index 00000000..11df8a18 --- /dev/null +++ b/yage/render/rectangle.h @@ -0,0 +1,15 @@ +#ifndef YAGE_RENDER_RECTANGLE_H +#define YAGE_RENDER_RECTANGLE_H + +#include "shape.h" + +namespace yage { + +class Rectangle +{ + virtual void render() const; +}; + +} // namespace yage + +#endif diff --git a/yage/render/shape.h b/yage/render/shape.h new file mode 100644 index 00000000..bdf318ed --- /dev/null +++ b/yage/render/shape.h @@ -0,0 +1,16 @@ +#ifndef YAGE_RENDER_SHAPE_H +#define YAGE_RENDER_SHAPE_H + +#include "drawable.h" + +namespace yage +{ + +class Shape : public Drawable +{ + 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..6862f910 --- /dev/null +++ b/yage/render/sprite.cpp @@ -0,0 +1,95 @@ +/** --------------------------------------------------------------------------- + * @file: sprite.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include + +#include + +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..852f4f28 --- /dev/null +++ b/yage/render/sprite.h @@ -0,0 +1,49 @@ +/** --------------------------------------------------------------------------- + * @file: sprite.h + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#ifndef SPRITE_H +#define SPRITE_H + +#include "texture.h" + +#include + +#include + +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..d65340d7 --- /dev/null +++ b/yage/render/spritebatch.cpp @@ -0,0 +1,200 @@ +/** --------------------------------------------------------------------------- + * @file: spritebatch.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#include "spritebatch.h" + +#include +#include + +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 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 diff --git a/yage/render/spritebatch.h b/yage/render/spritebatch.h new file mode 100644 index 00000000..c018bdc6 --- /dev/null +++ b/yage/render/spritebatch.h @@ -0,0 +1,90 @@ +/** --------------------------------------------------------------------------- + * @file: spritebatch.h + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_SPRITE_BATCH_H +#define YAGE_SPRITE_BATCH_H + +#include "batch.h" +#include "vertex.h" + +#include +#include + +#include + +namespace yage +{ + +class SpriteBatch; + +/** Glyph with information of the texture. + */ +class Glyph +{ +private: + GLuint texture_; + float depth_; + Vertex top_left_; + Vertex top_right_; + Vertex bottom_right_; + Vertex bottom_left_; + +public: + Glyph(GLuint texture, float depth, const Vertex &top_left, + const Vertex &top_right, const Vertex &bottom_right, + const Vertex &bottom_left); + + GLuint texture() const { return texture_; } + float depth() const { return depth_; } + Vertex top_left() const { return top_left_; } + Vertex top_right() const { return top_right_; } + Vertex bottom_right() const { return bottom_right_; } + Vertex bottom_left() const { return bottom_left_; } +}; + + +class SpriteBatch : public Batch +{ +public: + static const int NUM_VERTICES = 6; + +private: + GLuint vbo_ = 0; + GLuint vao_ = 0; + std::vector glyphs_; + std::vector glyph_ptrs_; + std::vector 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 createVertexArray(); + void createRenderBatches(); + void sortGlyphs(); +}; + +} // namespace yage + +#endif -- cgit