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 From 354d7df4d2779ed7391701d1ef4344e959b64582 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Wed, 27 Dec 2017 19:21:12 +0000 Subject: [Broken] Texture is black. --- yage/render/batch.h | 3 - yage/render/glslprogram.cpp | 215 -------------------------------------------- yage/render/glslprogram.h | 58 ------------ yage/render/rectangle.cpp | 37 ++++++++ yage/render/rectangle.h | 12 ++- yage/render/shader.cpp | 132 +++++++++++++++++++++++++++ yage/render/shader.h | 49 ++++++++++ yage/render/shape.h | 1 + yage/render/sprite.cpp | 6 +- yage/render/sprite.h | 2 +- yage/render/spritebatch.cpp | 32 +++---- yage/render/spritebatch.h | 5 +- 12 files changed, 249 insertions(+), 303 deletions(-) delete mode 100644 yage/render/glslprogram.cpp delete mode 100644 yage/render/glslprogram.h create mode 100644 yage/render/rectangle.cpp create mode 100644 yage/render/shader.cpp create mode 100644 yage/render/shader.h (limited to 'yage/render') diff --git a/yage/render/batch.h b/yage/render/batch.h index e301531c..57f997c1 100644 --- a/yage/render/batch.h +++ b/yage/render/batch.h @@ -28,10 +28,7 @@ public: virtual bool init(); virtual void begin(); virtual void end(); - virtual void draw(); virtual void render(); - -protected: }; } // namespace yage diff --git a/yage/render/glslprogram.cpp b/yage/render/glslprogram.cpp deleted file mode 100644 index 13abbba3..00000000 --- a/yage/render/glslprogram.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/** --------------------------------------------------------------------------- - * @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 deleted file mode 100644 index 0617bc1e..00000000 --- a/yage/render/glslprogram.h +++ /dev/null @@ -1,58 +0,0 @@ -/** --------------------------------------------------------------------------- - * @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.cpp b/yage/render/rectangle.cpp new file mode 100644 index 00000000..365d058d --- /dev/null +++ b/yage/render/rectangle.cpp @@ -0,0 +1,37 @@ +#include "rectangle.h" + +#include "../data/vertex.h" + +#include + +#include + +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 index 11df8a18..ad38caa5 100644 --- a/yage/render/rectangle.h +++ b/yage/render/rectangle.h @@ -3,11 +3,19 @@ #include "shape.h" -namespace yage { +#include -class Rectangle +namespace yage { + +class Rectangle : public Shape +{ +public: + Rectangle(glm::vec4 position); virtual void render() const; + +private: + glm::vec4 position_; }; } // namespace yage diff --git a/yage/render/shader.cpp b/yage/render/shader.cpp new file mode 100644 index 00000000..be2e77e2 --- /dev/null +++ b/yage/render/shader.cpp @@ -0,0 +1,132 @@ +/** --------------------------------------------------------------------------- + * @file: shader.cpp + * + * Copyright (c) 2017 Yann Herklotz Grave + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#include "shader.h" + +#include +#include +#include +#include +#include + +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(value)); +} + +void Shader::setUniform(const std::string &name, float value) const +{ + glUniform1f(getUniformLocation(name), static_cast(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 +{ + GLint 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 + * MIT License, see LICENSE file for more details. + * ---------------------------------------------------------------------------- + */ + +#ifndef YAGE_RENDER_SHADER_H +#define YAGE_RENDER_SHADER_H + +#include +#include + +#include + +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 index bdf318ed..1fdf1c4f 100644 --- a/yage/render/shape.h +++ b/yage/render/shape.h @@ -8,6 +8,7 @@ namespace yage class Shape : public Drawable { +public: virtual void render() const; }; diff --git a/yage/render/sprite.cpp b/yage/render/sprite.cpp index 6862f910..98853c94 100644 --- a/yage/render/sprite.cpp +++ b/yage/render/sprite.cpp @@ -6,9 +6,9 @@ * ---------------------------------------------------------------------------- */ -#include -#include -#include +#include "sprite.h" +#include "../core/resourcemanager.h" +#include "../data/vertex.h" #include diff --git a/yage/render/sprite.h b/yage/render/sprite.h index 852f4f28..51821be5 100644 --- a/yage/render/sprite.h +++ b/yage/render/sprite.h @@ -9,7 +9,7 @@ #ifndef SPRITE_H #define SPRITE_H -#include "texture.h" +#include "../data/texture.h" #include diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index d65340d7..fb6c3d78 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -25,11 +25,6 @@ Glyph::Glyph(GLuint texture, float depth, const Vertex &top_left, { } -RenderBatch::RenderBatch(GLint offset, GLsizei num_vertices, GLuint texture) - : num_vertices_(num_vertices), offset_(offset), texture_(texture) -{ -} - SpriteBatch::SpriteBatch() { createVertexArray(); @@ -42,7 +37,7 @@ SpriteBatch::~SpriteBatch() } if (vbo_ != 0) { - glDeleteVertexArrays(1, &vbo_); + glDeleteBuffers(1, &vbo_); } } @@ -59,8 +54,8 @@ void SpriteBatch::end() createRenderBatches(); } -void SpriteBatch::draw(const yage::Vector4f &destination_rect, - const yage::Vector4f &uv_rect, GLuint texture, +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; @@ -93,15 +88,15 @@ void SpriteBatch::draw(const yage::Vector4f &destination_rect, void SpriteBatch::render() { // sort and create render batches + glBindVertexArray(vao_); sortGlyphs(); createRenderBatches(); - glBindVertexArray(vao_); for (auto &&batch : render_batches_) { - glBindTexture(GL_TEXTURE_2D, batch.texture()); - glDrawArrays(GL_TRIANGLES, batch.offset(), batch.num_vertices()); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, batch.texture); + glDrawArrays(GL_TRIANGLES, batch.offset, batch.num_vertices); } - glBindVertexArray(0); // clear and reset the vectors glyphs_.clear(); @@ -129,11 +124,6 @@ void SpriteBatch::createVertexArray() // 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)); @@ -141,7 +131,11 @@ void SpriteBatch::createVertexArray() (void *)offsetof(Vertex, colour)); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, uv)); - glDrawArrays(GL_TRIANGLES, 0, 6); + + // enable vertex attribute arrays + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); // unbind vertex array object glBindVertexArray(0); @@ -162,7 +156,7 @@ void SpriteBatch::createRenderBatches() render_batches_.emplace_back(i * NUM_VERTICES, NUM_VERTICES, glyph_ptrs_[i]->texture()); } else { - render_batches_.back().num_vertices_ += NUM_VERTICES; + render_batches_.back().num_vertices += NUM_VERTICES; } vertices.push_back(glyph_ptrs_[i]->bottom_left()); diff --git a/yage/render/spritebatch.h b/yage/render/spritebatch.h index c018bdc6..e82268b8 100644 --- a/yage/render/spritebatch.h +++ b/yage/render/spritebatch.h @@ -10,7 +10,8 @@ #define YAGE_SPRITE_BATCH_H #include "batch.h" -#include "vertex.h" +#include "../data/vertex.h" +#include "../data/renderbatch.h" #include #include @@ -48,7 +49,7 @@ public: }; -class SpriteBatch : public Batch +class SpriteBatch { public: static const int NUM_VERTICES = 6; -- cgit From d2ed94a517066da4f4ec53045f9c69bfc355eab6 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Wed, 27 Dec 2017 21:24:48 +0000 Subject: [Code] Examples working again. --- yage/render/spritebatch.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'yage/render') diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index fb6c3d78..c1bf4a28 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -9,6 +9,7 @@ #include "spritebatch.h" #include +#include #include namespace yage @@ -88,10 +89,9 @@ void SpriteBatch::draw(const glm::vec4 &destination_rect, void SpriteBatch::render() { // sort and create render batches - glBindVertexArray(vao_); sortGlyphs(); createRenderBatches(); - + glBindVertexArray(vao_); for (auto &&batch : render_batches_) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, batch.texture); @@ -155,6 +155,7 @@ void SpriteBatch::createRenderBatches() 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; } -- cgit From 5c1a57b3672ec1e0777d8d0878c6a7ae93ebfdca Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sat, 30 Dec 2017 16:07:41 +0000 Subject: [Code] Fixed spritebatch and optimised it. --- yage/render/rectangle.cpp | 1 + yage/render/spritebatch.cpp | 81 ++++++++++++++++++++------------------------- yage/render/spritebatch.h | 10 +++--- 3 files changed, 40 insertions(+), 52 deletions(-) (limited to 'yage/render') diff --git a/yage/render/rectangle.cpp b/yage/render/rectangle.cpp index 365d058d..632c7ceb 100644 --- a/yage/render/rectangle.cpp +++ b/yage/render/rectangle.cpp @@ -35,3 +35,4 @@ void Rectangle::render() const } } // namepsace yage + diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index c1bf4a28..bce5986f 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -26,9 +26,37 @@ Glyph::Glyph(GLuint texture, float depth, const Vertex &top_left, { } -SpriteBatch::SpriteBatch() +SpriteBatch::SpriteBatch() : vao_(0), vbo_(0) { - createVertexArray(); + 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); + + // unbind vertex array object + glBindVertexArray(0); } SpriteBatch::~SpriteBatch() @@ -88,10 +116,10 @@ void SpriteBatch::draw(const glm::vec4 &destination_rect, void SpriteBatch::render() { + glBindVertexArray(vao_); // sort and create render batches - sortGlyphs(); createRenderBatches(); - glBindVertexArray(vao_); + sortGlyphs(); for (auto &&batch : render_batches_) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, batch.texture); @@ -104,43 +132,6 @@ void SpriteBatch::render() 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_); - - // 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); - - // unbind vertex array object - glBindVertexArray(0); -} - void SpriteBatch::createRenderBatches() { std::vector vertices; @@ -163,12 +154,11 @@ void SpriteBatch::createRenderBatches() 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()); + vertices.push_back(glyph_ptrs_[i]->bottom_right()); + vertices.push_back(glyph_ptrs_[i]->bottom_left()); - // bind vbo - glBindBuffer(GL_ARRAY_BUFFER, vbo_); // orphan the buffer glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), nullptr, GL_DYNAMIC_DRAW); @@ -176,7 +166,6 @@ void SpriteBatch::createRenderBatches() glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex), vertices.data()); // unbind buffer - glBindBuffer(GL_ARRAY_BUFFER, 0); } } diff --git a/yage/render/spritebatch.h b/yage/render/spritebatch.h index e82268b8..35d9a1b1 100644 --- a/yage/render/spritebatch.h +++ b/yage/render/spritebatch.h @@ -9,9 +9,9 @@ #ifndef YAGE_SPRITE_BATCH_H #define YAGE_SPRITE_BATCH_H -#include "batch.h" -#include "../data/vertex.h" #include "../data/renderbatch.h" +#include "../data/vertex.h" +#include "batch.h" #include #include @@ -48,15 +48,14 @@ public: Vertex bottom_left() const { return bottom_left_; } }; - class SpriteBatch { public: static const int NUM_VERTICES = 6; private: - GLuint vbo_ = 0; - GLuint vao_ = 0; + GLuint vao_; + GLuint vbo_; std::vector glyphs_; std::vector glyph_ptrs_; std::vector render_batches_; @@ -81,7 +80,6 @@ public: void render(); private: - void createVertexArray(); void createRenderBatches(); void sortGlyphs(); }; -- cgit From 3ebcb9c134aabd33c1b165a263b1c8c80c5266f6 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sat, 30 Dec 2017 16:10:11 +0000 Subject: [Bug fix] Changed int to unsigned. --- yage/render/shader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'yage/render') diff --git a/yage/render/shader.cpp b/yage/render/shader.cpp index be2e77e2..156c2aa1 100644 --- a/yage/render/shader.cpp +++ b/yage/render/shader.cpp @@ -101,7 +101,7 @@ void Shader::setUniform(const std::string &name, const glm::mat4 &matrix) const GLint Shader::getUniformLocation(const std::string &uniform_name) const { - GLint location = glGetUniformLocation(program_id_, uniform_name.c_str()); + GLuint location = glGetUniformLocation(program_id_, uniform_name.c_str()); if (location == GL_INVALID_INDEX) { throw std::runtime_error("'" + uniform_name + "' not found"); } -- cgit From 34908f108ad7c2ee6cff96491a0bc40381477424 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sun, 31 Dec 2017 18:00:01 +0000 Subject: [Test] Benchmarking the engine and trying to optimize. --- yage/render/spritebatch.cpp | 49 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'yage/render') diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index bce5986f..09df5b9f 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -9,8 +9,10 @@ #include "spritebatch.h" #include -#include #include +#include "../core/logger.h" + +#include namespace yage { @@ -61,13 +63,12 @@ SpriteBatch::SpriteBatch() : vao_(0), vbo_(0) SpriteBatch::~SpriteBatch() { - if (vao_ != 0) { - glDeleteVertexArrays(1, &vao_); - } - if (vbo_ != 0) { glDeleteBuffers(1, &vbo_); } + if (vao_ != 0) { + glDeleteVertexArrays(1, &vao_); + } } void SpriteBatch::begin() @@ -118,10 +119,10 @@ void SpriteBatch::render() { glBindVertexArray(vao_); // sort and create render batches - createRenderBatches(); sortGlyphs(); + createRenderBatches(); + glActiveTexture(GL_TEXTURE0); for (auto &&batch : render_batches_) { - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, batch.texture); glDrawArrays(GL_TRIANGLES, batch.offset, batch.num_vertices); } @@ -134,13 +135,13 @@ void SpriteBatch::render() void SpriteBatch::createRenderBatches() { - std::vector vertices; + std::vector vertices(glyph_ptrs_.size() * NUM_VERTICES); if (glyph_ptrs_.empty()) { return; } - render_batches_.reserve(glyph_ptrs_.size() * NUM_VERTICES); - + int cv = 0; + for (int i = 0; i < (int)glyph_ptrs_.size(); ++i) { if (i == 0 || (i > 0 && (glyph_ptrs_[i]->texture() != glyph_ptrs_[i - 1]->texture()))) { @@ -151,22 +152,20 @@ void SpriteBatch::createRenderBatches() 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); - // upload the data - glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex), - vertices.data()); - // unbind buffer + vertices[cv++] = glyph_ptrs_[i]->bottom_left(); + vertices[cv++] = glyph_ptrs_[i]->top_left(); + vertices[cv++] = glyph_ptrs_[i]->top_right(); + + vertices[cv++] = glyph_ptrs_[i]->top_right(); + vertices[cv++] = glyph_ptrs_[i]->bottom_right(); + vertices[cv++] = 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() -- cgit From 9038ee45f93b1ae07a28a516781676ebe3a67536 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sun, 31 Dec 2017 18:17:04 +0000 Subject: [Bug] Fixed null pointers in spritebatch. --- yage/render/spritebatch.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'yage/render') diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index 09df5b9f..fb8eb605 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -11,6 +11,9 @@ #include #include #include "../core/logger.h" +#include + +using std::cout; #include @@ -112,13 +115,13 @@ void SpriteBatch::draw(const glm::vec4 &destination_rect, // 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() { glBindVertexArray(vao_); // sort and create render batches + sortGlyphs(); createRenderBatches(); glActiveTexture(GL_TEXTURE0); @@ -135,13 +138,13 @@ void SpriteBatch::render() void SpriteBatch::createRenderBatches() { - std::vector vertices(glyph_ptrs_.size() * NUM_VERTICES); + std::vector vertices; if (glyph_ptrs_.empty()) { return; } - int cv = 0; - + 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()))) { @@ -152,13 +155,13 @@ void SpriteBatch::createRenderBatches() render_batches_.back().num_vertices += NUM_VERTICES; } - vertices[cv++] = glyph_ptrs_[i]->bottom_left(); - vertices[cv++] = glyph_ptrs_[i]->top_left(); - vertices[cv++] = glyph_ptrs_[i]->top_right(); + 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[cv++] = glyph_ptrs_[i]->top_right(); - vertices[cv++] = glyph_ptrs_[i]->bottom_right(); - vertices[cv++] = glyph_ptrs_[i]->bottom_left(); + 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 @@ -170,6 +173,10 @@ void SpriteBatch::createRenderBatches() 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(), [](Glyph *a, Glyph *b) -> bool { -- cgit From 86e4aa6265ade205aba94494a7a31a83b5686387 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Wed, 3 Jan 2018 13:26:37 +0000 Subject: [Engine] [Example] Reenabled vsync and working on example. --- yage/render/spritebatch.cpp | 48 ++++++++++++++---------------------- yage/render/spritebatch.h | 60 +++++++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 55 deletions(-) (limited to 'yage/render') diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index fb8eb605..14e30ccd 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -8,10 +8,10 @@ #include "spritebatch.h" -#include -#include #include "../core/logger.h" +#include #include +#include using std::cout; @@ -22,15 +22,6 @@ 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) -{ -} - SpriteBatch::SpriteBatch() : vao_(0), vbo_(0) { glGenVertexArrays(1, &vao_); @@ -59,9 +50,6 @@ SpriteBatch::SpriteBatch() : vao_(0), vbo_(0) glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); - - // unbind vertex array object - glBindVertexArray(0); } SpriteBatch::~SpriteBatch() @@ -121,11 +109,12 @@ void SpriteBatch::render() { glBindVertexArray(vao_); // sort and create render batches - sortGlyphs(); createRenderBatches(); glActiveTexture(GL_TEXTURE0); for (auto &&batch : render_batches_) { + yLog << "Drawing " << batch.num_vertices + << " vertices bound to texture: " << batch.texture; glBindTexture(GL_TEXTURE_2D, batch.texture); glDrawArrays(GL_TRIANGLES, batch.offset, batch.num_vertices); } @@ -146,22 +135,22 @@ void SpriteBatch::createRenderBatches() 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()))) { + 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()); + 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]->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()); + 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 @@ -174,16 +163,17 @@ void SpriteBatch::createRenderBatches() void SpriteBatch::sortGlyphs() { glyph_ptrs_.reserve(glyphs_.size()); - for(auto &glyph : glyphs_) { + for (auto &glyph : glyphs_) { glyph_ptrs_.push_back(&glyph); } + // 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(); + [](details::Glyph *a, details::Glyph *b) -> bool { + if (a->depth == b->depth) { + return a->texture < b->texture; } - return a->depth() < b->depth(); + return a->depth < b->depth; }); } diff --git a/yage/render/spritebatch.h b/yage/render/spritebatch.h index 35d9a1b1..fb9f6337 100644 --- a/yage/render/spritebatch.h +++ b/yage/render/spritebatch.h @@ -9,7 +9,6 @@ #ifndef YAGE_SPRITE_BATCH_H #define YAGE_SPRITE_BATCH_H -#include "../data/renderbatch.h" #include "../data/vertex.h" #include "batch.h" @@ -21,33 +20,42 @@ namespace yage { -class SpriteBatch; +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. */ -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_; } +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: @@ -56,9 +64,9 @@ public: private: GLuint vao_; GLuint vbo_; - std::vector glyphs_; - std::vector glyph_ptrs_; - std::vector render_batches_; + std::vector glyphs_; + std::vector glyph_ptrs_; + std::vector render_batches_; public: SpriteBatch(); -- cgit From a47649786fb94684c415b230669fbf5343cb7c5d Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Wed, 3 Jan 2018 13:57:51 +0000 Subject: [Engine] [Example] Added simple bullets that don't move --- yage/render/drawable.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'yage/render') diff --git a/yage/render/drawable.h b/yage/render/drawable.h index 0e4b6843..8ef48f2d 100644 --- a/yage/render/drawable.h +++ b/yage/render/drawable.h @@ -1,13 +1,15 @@ #ifndef YAGE_CORE_DRAWABLE_H #define YAGE_CORE_DRAWABLE_H +#include "spritebatch.h" + namespace yage { class Drawable { public: - virtual void render() const; + virtual void draw(SpriteBatch &sp) const = 0; }; } // namespace yage -- cgit From 7b95e3a9eacf296f215c73e5d8ad9090a24adb20 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Thu, 4 Jan 2018 21:36:30 +0000 Subject: [Engine] Now using stb_image to laod all kinds of textures. --- yage/render/drawable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'yage/render') diff --git a/yage/render/drawable.h b/yage/render/drawable.h index 8ef48f2d..c126bb09 100644 --- a/yage/render/drawable.h +++ b/yage/render/drawable.h @@ -9,7 +9,7 @@ namespace yage class Drawable { public: - virtual void draw(SpriteBatch &sp) const = 0; + virtual void draw(SpriteBatch &sp) = 0; }; } // namespace yage -- cgit From db6480dccd9a3dbf4100a824930a36251f4e743c Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Fri, 5 Jan 2018 15:56:35 +0000 Subject: [Engine] Log levels added to engine. --- yage/render/spritebatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'yage/render') diff --git a/yage/render/spritebatch.cpp b/yage/render/spritebatch.cpp index 14e30ccd..90958246 100644 --- a/yage/render/spritebatch.cpp +++ b/yage/render/spritebatch.cpp @@ -113,7 +113,7 @@ void SpriteBatch::render() createRenderBatches(); glActiveTexture(GL_TEXTURE0); for (auto &&batch : render_batches_) { - yLog << "Drawing " << batch.num_vertices + 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); -- cgit From 8b50d7f50ba40e51f7afd4e9c9efa023bc89ba48 Mon Sep 17 00:00:00 2001 From: Yann Herklotz Date: Sat, 6 Jan 2018 11:10:52 +0000 Subject: [Engine] Removing whitespace --- yage/render/batch.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'yage/render') diff --git a/yage/render/batch.h b/yage/render/batch.h index 57f997c1..6694fbcb 100644 --- a/yage/render/batch.h +++ b/yage/render/batch.h @@ -4,20 +4,20 @@ namespace yage { -/** The Batch class will be the base class for all the different batching +/** 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 + * 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. -- cgit