Browse Source

Add font batch renderer

master
Riyyi 4 years ago
parent
commit
e95d3a560e
  1. 65
      assets/glsl/batch-font.frag
  2. 36
      assets/glsl/batch-font.vert
  3. 74
      inferno/src/inferno/application.cpp
  4. 2
      inferno/src/inferno/application.h
  5. 155
      inferno/src/inferno/render/font.cpp
  6. 87
      inferno/src/inferno/render/font.h
  7. 197
      inferno/src/inferno/render/renderer.cpp
  8. 46
      inferno/src/inferno/render/renderer.h

65
assets/glsl/batch-font.frag

@ -0,0 +1,65 @@
#version 450 core
layout(location = 0) out vec4 color;
in vec4 v_color;
in vec2 v_textureCoordinates;
in flat float v_textureIndex;
in float v_width;
in float v_edge;
in float v_borderWidth;
in float v_borderEdge;
in vec4 v_borderColor;
in flat float v_offset;
uniform sampler2D u_textures[32];
float alpha(float textureAlpha)
{
float distance = 1.0f - textureAlpha;
float alpha = 1.0f - smoothstep(v_width, v_width + v_edge, distance);
return alpha;
}
void main()
{
vec4 textureColor = v_color;
switch(int(v_textureIndex)) {
case 0: break; // Texture unit 0 is reserved for no texture
case 1: textureColor.a = alpha(texture(u_textures[1], v_textureCoordinates).a); break;
// case 1: textureColor *= texture(u_textures[1], v_textureCoordinates); break;
case 2: textureColor.a = alpha(texture(u_textures[2], v_textureCoordinates).a); break;
case 3: textureColor.a = alpha(texture(u_textures[3], v_textureCoordinates).a); break;
case 4: textureColor.a = alpha(texture(u_textures[4], v_textureCoordinates).a); break;
case 5: textureColor.a = alpha(texture(u_textures[5], v_textureCoordinates).a); break;
case 6: textureColor.a = alpha(texture(u_textures[6], v_textureCoordinates).a); break;
case 7: textureColor.a = alpha(texture(u_textures[7], v_textureCoordinates).a); break;
case 8: textureColor.a = alpha(texture(u_textures[8], v_textureCoordinates).a); break;
case 9: textureColor.a = alpha(texture(u_textures[9], v_textureCoordinates).a); break;
case 10: textureColor.a = alpha(texture(u_textures[10], v_textureCoordinates).a); break;
case 11: textureColor.a = alpha(texture(u_textures[11], v_textureCoordinates).a); break;
case 12: textureColor.a = alpha(texture(u_textures[12], v_textureCoordinates).a); break;
case 13: textureColor.a = alpha(texture(u_textures[13], v_textureCoordinates).a); break;
case 14: textureColor.a = alpha(texture(u_textures[14], v_textureCoordinates).a); break;
case 15: textureColor.a = alpha(texture(u_textures[15], v_textureCoordinates).a); break;
case 16: textureColor.a = alpha(texture(u_textures[16], v_textureCoordinates).a); break;
case 17: textureColor.a = alpha(texture(u_textures[17], v_textureCoordinates).a); break;
case 18: textureColor.a = alpha(texture(u_textures[18], v_textureCoordinates).a); break;
case 19: textureColor.a = alpha(texture(u_textures[19], v_textureCoordinates).a); break;
case 20: textureColor.a = alpha(texture(u_textures[20], v_textureCoordinates).a); break;
case 21: textureColor.a = alpha(texture(u_textures[21], v_textureCoordinates).a); break;
case 22: textureColor.a = alpha(texture(u_textures[22], v_textureCoordinates).a); break;
case 23: textureColor.a = alpha(texture(u_textures[23], v_textureCoordinates).a); break;
case 24: textureColor.a = alpha(texture(u_textures[24], v_textureCoordinates).a); break;
case 25: textureColor.a = alpha(texture(u_textures[25], v_textureCoordinates).a); break;
case 26: textureColor.a = alpha(texture(u_textures[26], v_textureCoordinates).a); break;
case 27: textureColor.a = alpha(texture(u_textures[27], v_textureCoordinates).a); break;
case 28: textureColor.a = alpha(texture(u_textures[28], v_textureCoordinates).a); break;
case 29: textureColor.a = alpha(texture(u_textures[29], v_textureCoordinates).a); break;
case 30: textureColor.a = alpha(texture(u_textures[30], v_textureCoordinates).a); break;
case 31: textureColor.a = alpha(texture(u_textures[31], v_textureCoordinates).a); break;
}
// textureColor.a = 1; // tmp
color = textureColor;
}

36
assets/glsl/batch-font.vert

@ -0,0 +1,36 @@
#version 450 core
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;
layout(location = 2) in vec2 a_textureCoordinates;
layout(location = 3) in float a_textureIndex;
layout(location = 4) in float a_width;
layout(location = 5) in float a_edge;
layout(location = 6) in float a_borderWidth;
layout(location = 7) in float a_borderEdge;
layout(location = 8) in vec4 a_borderColor;
layout(location = 9) in float a_offset;
out vec4 v_color;
out vec2 v_textureCoordinates;
out flat float v_textureIndex;
out float v_width;
out float v_edge;
out float v_borderWidth;
out float v_borderEdge;
out vec4 v_borderColor;
out flat float v_offset;
void main()
{
v_color = a_color;
v_textureCoordinates = a_textureCoordinates;
v_textureIndex = a_textureIndex;
v_width = a_width;
v_edge = a_edge;
v_borderWidth = a_borderWidth;
v_borderEdge = a_borderEdge;
v_borderColor = a_borderColor;
v_offset = a_offset;
gl_Position = vec4(a_position, 1.0f);
}

74
inferno/src/inferno/application.cpp

@ -9,13 +9,14 @@
#include "inferno/input.h"
#include "inferno/inputcodes.h"
#include "inferno/log.h"
#include "inferno/settings.h"
#include "inferno/render/buffer.h"
#include "inferno/render/camera.h"
#include "inferno/render/context.h"
#include "inferno/render/font.h"
#include "inferno/render/renderer.h"
#include "inferno/render/shader.h"
#include "inferno/render/texture.h"
#include "inferno/settings.h"
#include "inferno/time.h"
#include "inferno/window.h"
@ -49,14 +50,24 @@ namespace Inferno {
Renderer2D* renderer2D = new Renderer2D();
renderer2D->initialize();
RendererCharacter* rendererCharacter = new RendererCharacter();
rendererCharacter->initialize();
FontManager* fontManager = new FontManager();
fontManager->initialize();
// Load assets
m_texture = TextureManager::the().load("assets/gfx/test.png");
m_texture2 = TextureManager::the().load("assets/gfx/test-inverted.png");
m_font = FontManager::the().load("assets/fnt/dejavu-sans");
}
Application::~Application()
{
FontManager::the().destroy();
RendererCharacter::the().destroy();
Renderer2D::the().destroy();
TextureManager::the().destroy();
ShaderManager::the().destroy();
@ -84,6 +95,63 @@ namespace Inferno {
Transform cube3({2.2f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f});
cube3.update();
Transform cube4({0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f});
cube4.update();
std::array<CharacterVertex, Renderer::vertexPerQuad> character;
// character.at(0).quad.textureCoordinates = { 0.0f, 0.0f }; // bottom left
// character.at(1).quad.textureCoordinates = { 1.0f, 0.0f };
// character.at(2).quad.textureCoordinates = { 1.0f, 1.0f }; // top right
// character.at(3).quad.textureCoordinates = { 0.0f, 1.0f };
auto f = FontManager::the().get("assets/fnt/dejavu-sans");
auto c = f->get('5');
dbg() << c->position << " " << c->size;
uint32_t textureWidth = f->texture()->width();
uint32_t textureHeight = f->texture()->height();
ASSERT(textureWidth == textureHeight, "Invalid font texture!");
float quadWidth = (c->size.x / (float)textureWidth) - 0.04; // @Todo something wrong with the width
float quadHeight = c->size.y / (float)textureHeight;
character.at(0).quad.position = { -quadWidth, -quadHeight, 0.0f }; // bottom left
character.at(1).quad.position = { quadWidth, -quadHeight, 0.0f }; // bottom right
character.at(2).quad.position = { quadWidth, quadHeight, 0.0f }; // top right
character.at(3).quad.position = { -quadWidth, quadHeight, 0.0f }; // top left
glm::vec2 x {
1 - (textureWidth - c->position.x) / (float)textureWidth,
1 - (textureWidth - c->position.x - c->size.x) / (float)textureWidth
};
glm::vec2 y {
(textureHeight - c->position.y - c->size.y) / (float)textureHeight,
(textureHeight - c->position.y) / (float)textureHeight
};
dbg() << y;
character.at(0).quad.textureCoordinates = { x.x, y.x };
character.at(1).quad.textureCoordinates = { x.y, y.x };
character.at(2).quad.textureCoordinates = { x.y, y.y };
character.at(3).quad.textureCoordinates = { x.x, y.y };
character.at(0).quad.textureIndex = 1.0f;
character.at(1).quad.textureIndex = 1.0f;
character.at(2).quad.textureIndex = 1.0f;
character.at(3).quad.textureIndex = 1.0f;
// pos
// texcoords
//
// width
// edge
// borderwidth
// borderedge
// bordercolor
// offse
while(!m_window->shouldClose()) {
float time = Time::time();
@ -104,12 +172,16 @@ namespace Inferno {
RenderCommand::clear();
Renderer2D::the().beginScene(m_cameraP); // camera, lights, environment
RendererCharacter::the().beginScene();
Renderer2D::the().drawQuad(std::make_shared<Transform>(cube), colors);
Renderer2D::the().drawQuad(std::make_shared<Transform>(cube2), { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture);
Renderer2D::the().drawQuad(std::make_shared<Transform>(cube3), { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2);
RendererCharacter::the().drawCharacter(character, {1,1,1,1}, f->texture());
Renderer2D::the().endScene();
RendererCharacter::the().endScene();
m_window->render();

2
inferno/src/inferno/application.h

@ -6,6 +6,7 @@
namespace Inferno {
class Event;
class Font;
class KeyPressEvent;
class MousePositionEvent;
class OrthographicCamera;
@ -49,6 +50,7 @@ namespace Inferno {
//
std::shared_ptr<Texture> m_texture;
std::shared_ptr<Texture> m_texture2;
std::shared_ptr<Font> m_font;
//
static Application* s_instance;

155
inferno/src/inferno/render/font.cpp

@ -0,0 +1,155 @@
#include <bits/stdint-uintn.h>
#include <string> // std::getline
#include "inferno/assertions.h"
#include "inferno/file.h"
#include "inferno/render/font.h"
#include "inferno/render/texture.h"
namespace Inferno {
Font::Font(const std::string& name)
{
std::string path = name + ".fnt";
std::string image = name + ".png";
std::string font = File::read(path);
parseFont(font);
m_texture = std::make_shared<Texture>(image);
}
void Font::parseFont(const std::string& font)
{
std::istringstream iss(font);
for (std::string line; std::getline(iss, line);) {
if (findAction(line).compare("char") != 0) {
continue;
}
const std::vector<std::string> data = findColumns(line);
unsigned char id = std::stoi(findValue("id", data));
Character character = {
{ std::stoi(findValue("x", data)), std::stoi(findValue("y", data)) },
{ std::stoi(findValue("width", data)), std::stoi(findValue("height", data)) },
{ std::stoi(findValue("xoffset", data)), std::stoi(findValue("yoffset", data)) },
std::stoi(findValue("xadvance", data))
};
m_characterList.emplace(id, std::make_shared<Character>(character));
}
}
const std::string Font::findAction(const std::string& line)
{
return line.substr(0, line.find(" "));
}
const std::vector<std::string> Font::findColumns(const std::string& line)
{
std::vector<std::string> elements;
size_t index = 0;
size_t find = 0;
size_t findFirstNotOf = 0;
// Loop over line characters
while (find != std::string::npos) {
find = line.find(" ", index);
findFirstNotOf = line.find_first_not_of(" ", index);
// Add element
if (find > findFirstNotOf) {
elements.push_back(line.substr(index, find - findFirstNotOf));
index += 1 + find - findFirstNotOf;
}
// Skip double spaces
else {
index = findFirstNotOf;
}
}
return elements;
}
const std::string Font::findValue(const std::string& key, const std::vector<std::string>& columns)
{
size_t find = 0;
// Loop over columns
for (auto it = columns.begin(); it != columns.end(); it++) {
find = it->find(key + "=");
if (find != std::string::npos) {
return it->substr(key.length() + 1);
}
}
return "";
}
// -----------------------------------------
FontManager* FontManager::s_instance = nullptr;
void FontManager::initialize()
{
ASSERT(!s_instance, "FontManager already exists!");
s_instance = this;
dbg(Log::Info) << "FontManager initialized";
}
void FontManager::destroy()
{
delete s_instance;
s_instance = nullptr;
}
void FontManager::add(const std::string& name, const std::shared_ptr<Font>& font)
{
// Construct (key, value) pair and insert it into the unordered_map
m_fontList.emplace(name, font);
}
std::shared_ptr<Font> FontManager::load(const std::string& name)
{
if (exists(name)) {
return get(name);
}
std::shared_ptr<Font> font = std::make_shared<Font>(name);
add(name, font);
return get(name);
}
std::shared_ptr<Font> FontManager::get(const std::string& name)
{
return exists(name) ? m_fontList.at(name) : nullptr;
}
bool FontManager::exists(const std::string& name)
{
return m_fontList.find(name) != m_fontList.end();
}
void FontManager::remove(const std::string& name)
{
if (exists(name)) {
m_fontList.erase(name);
}
}
void FontManager::remove(const std::shared_ptr<Font>& font)
{
if (exists(font->name())) {
m_fontList.erase(font->name());
}
}
// -----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value)
{
return stream << "{ " << value.x << ", " << value.y << " }";
}
}

87
inferno/src/inferno/render/font.h

@ -0,0 +1,87 @@
#ifndef FONT_H
#define FONT_H
#include <cstdint> // int32_t
#include <memory> // std::shared_ptr
#include <string> // std::string
#include <unordered_map> // std::unordered_map
#include <vector> // std::vector
#include <glm/ext/vector_int2.hpp> // glm::ivec2
#include "inferno/log.h"
namespace Inferno {
class Texture;
struct Character {
glm::ivec2 position; // Position
glm::ivec2 size; // Width/height
glm::ivec2 offset; // Offset from baseline to left / top of glyph
int32_t advance; // Amount to advance to next glyph
};
// -----------------------------------------
class Font {
public:
Font(const std::string& name);
virtual ~Font() {}
inline const std::shared_ptr<Character>& get(unsigned char c) const { return m_characterList.at(c); }
inline const std::shared_ptr<Character>& operator[](unsigned char c) const { return m_characterList.at(c); }
inline std::string name() const { return m_name; }
inline const std::shared_ptr<Texture>& texture() const { return m_texture; }
private:
void parseFont(const std::string& font);
const std::string findAction(const std::string& line);
const std::vector<std::string> findColumns(const std::string& line);
const std::string findValue(const std::string& key, const std::vector<std::string>& columns);
std::string m_name;
std::shared_ptr<Texture> m_texture;
std::unordered_map<unsigned char, std::shared_ptr<Character>> m_characterList;
};
// -----------------------------------------
class FontManager {
public:
void initialize();
void destroy();
void add(const std::string& name, const std::shared_ptr<Font>& font);
std::shared_ptr<Font> load(const std::string& name);
std::shared_ptr<Font> get(const std::string& name);
bool exists(const std::string& name);
void remove(const std::string& name);
void remove(const std::shared_ptr<Font>& shader);
static inline FontManager& the() { return *s_instance; }
private:
std::unordered_map<std::string, std::shared_ptr<Font>> m_fontList;
static FontManager* s_instance;
};
// ----------------------------------------
const LogStream& operator<<(const LogStream& stream, const glm::ivec2& value);
}
#endif // FONT_H
// FontManager fm;
// Font f = fm.load("path/to/font");
// Font f2("path/to/font");
// Character c = f['a'];
// Look into using signed distance fields for texture map generation ? anti-aliasing for text
// https://youtu.be/d8cfgcJR9Tk

197
inferno/src/inferno/render/renderer.cpp

@ -57,10 +57,13 @@ namespace Inferno {
}
// Create shader
m_shader = ShaderManager::the().load("assets/glsl/batch-quad");
loadShader();
m_shader->bind();
m_shader->setInt("u_textures", samplers, textureUnitPerBatch);
m_shader->unbind();
// Create vertex array
m_vertexArray = std::make_shared<VertexArray>();
}
void Renderer::destroy()
@ -121,13 +124,13 @@ namespace Inferno {
void Renderer2D::initialize()
{
ASSERT(!s_instance, "ShaderManager already exists!");
ASSERT(!s_instance, "RendererCharacter already exists!");
s_instance = this;
Renderer::initialize();
// CPU
// -----------------------------------------
// CPU
// ---------------------------------
// Create array for storing quads vertices
m_vertexBufferBase = std::unique_ptr<QuadVertex[]>(new QuadVertex[vertexCount]);
@ -139,22 +142,6 @@ namespace Inferno {
m_vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f };
m_vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f };
// GPU
// -----------------------------------------
// Create vertex array
m_vertexArray = std::make_shared<VertexArray>();
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
});
m_vertexArray->addVertexBuffer(std::move(vertexBuffer));
// Generate indices
uint32_t* indices = new uint32_t[indexCount];
@ -171,6 +158,19 @@ namespace Inferno {
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(QuadVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
});
m_vertexArray->addVertexBuffer(std::move(vertexBuffer));
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
m_vertexArray->setIndexBuffer(indexBuffer);
@ -235,6 +235,11 @@ namespace Inferno {
m_quadIndex++;
}
void Renderer2D::loadShader()
{
m_shader = ShaderManager::the().load("assets/glsl/batch-quad");
}
void Renderer2D::flush()
{
if (m_quadIndex == 0) {
@ -244,13 +249,13 @@ namespace Inferno {
// Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
quadCount * vertexPerQuad * sizeof(QuadVertex));
m_quadIndex * vertexPerQuad * sizeof(QuadVertex));
bind();
// Render
m_shader->setFloat("u_projectionView", s_camera->projection() * s_camera->transform()->transform());
RenderCommand::drawIndexed(m_vertexArray, quadCount * indexPerQuad);
RenderCommand::drawIndexed(m_vertexArray, m_quadIndex * indexPerQuad);
unbind();
}
@ -269,4 +274,152 @@ namespace Inferno {
startBatch();
}
// -----------------------------------------
RendererCharacter* RendererCharacter::s_instance = nullptr;
void RendererCharacter::initialize()
{
ASSERT(!s_instance, "RendererCharacter already exists!");
s_instance = this;
Renderer::initialize();
// CPU
// ---------------------------------
// Create array for storing quads vertices
m_vertexBufferBase = std::unique_ptr<CharacterVertex[]>(new CharacterVertex[vertexCount]);
m_vertexBufferPtr = m_vertexBufferBase.get();
// Generate indices
uint32_t* indices = new uint32_t[indexCount];
uint32_t offset = 0;
for (uint32_t i = 0; i < indexCount; i += indexPerQuad) {
indices[i + 0] = offset + 0;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset + 0;
offset += vertexPerQuad;
}
// GPU
// ---------------------------------
// Create vertex buffer
auto vertexBuffer = std::make_shared<VertexBuffer>(sizeof(CharacterVertex) * vertexCount);
vertexBuffer->setLayout({
{ BufferElementType::Vec3, "a_position" },
{ BufferElementType::Vec4, "a_color" },
{ BufferElementType::Vec2, "a_textureCoordinates" },
{ BufferElementType::Float, "a_textureIndex" },
{ BufferElementType::Float, "a_width" },
{ BufferElementType::Float, "a_edge" },
{ BufferElementType::Float, "a_borderWidth" },
{ BufferElementType::Float, "a_borderEdge" },
{ BufferElementType::Vec4, "a_borderColor" },
{ BufferElementType::Float, "a_offset" },
});
m_vertexArray->addVertexBuffer(std::move(vertexBuffer));
// Create index buffer
auto indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(uint32_t) * indexCount);
m_vertexArray->setIndexBuffer(indexBuffer);
delete[] indices;
dbg() << "RendererCharacter initialized";
}
void RendererCharacter::destroy()
{
delete s_instance;
s_instance = nullptr;
}
void RendererCharacter::beginScene()
{
}
void RendererCharacter::endScene()
{
nextBatch();
}
void RendererCharacter::drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, glm::vec4 color, std::shared_ptr<Texture> texture)
{
drawCharacter(characterQuad, glm::mat4 { color, color, color, color }, texture);
}
void RendererCharacter::drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, glm::mat4 color, std::shared_ptr<Texture> texture)
{
// Create a new batch if the quad limit has been reached
if (m_quadIndex >= quadCount) {
nextBatch();
}
uint32_t textureUnitIndex = addTextureUnit(texture);
// Add the quads 4 vertices
for (uint32_t i = 0; i < vertexPerQuad; i++) {
m_vertexBufferPtr->quad.position = characterQuad[i].quad.position;
m_vertexBufferPtr->quad.color = characterQuad[i].quad.color;
m_vertexBufferPtr->quad.textureCoordinates = characterQuad[i].quad.textureCoordinates;
m_vertexBufferPtr->quad.textureIndex = (float)textureUnitIndex;
m_vertexBufferPtr->width = characterQuad[i].width;
m_vertexBufferPtr->edge = characterQuad[i].edge;
m_vertexBufferPtr->borderWidth = characterQuad[i].borderWidth;
m_vertexBufferPtr->borderEdge = characterQuad[i].borderEdge;
m_vertexBufferPtr->borderColor = characterQuad[i].borderColor;
m_vertexBufferPtr->offset = characterQuad[i].offset;
m_vertexBufferPtr++;
}
m_quadIndex++;
}
void RendererCharacter::loadShader()
{
m_shader = ShaderManager::the().load("assets/glsl/batch-font");
}
void RendererCharacter::flush()
{
if (m_quadIndex == 0) {
return;
}
// Upload vertex data to GPU
m_vertexArray->getVertexBuffers().at(0)->uploadData(
m_vertexBufferBase.get(),
m_quadIndex * vertexPerQuad * sizeof(CharacterVertex));
bind();
// Render
RenderCommand::drawIndexed(m_vertexArray, m_quadIndex * indexPerQuad);
unbind();
}
void RendererCharacter::startBatch()
{
m_quadIndex = 0;
m_vertexBufferPtr = m_vertexBufferBase.get();
m_textureUnitIndex = 1;
}
void RendererCharacter::nextBatch()
{
flush();
startBatch();
}
}

46
inferno/src/inferno/render/renderer.h

@ -24,6 +24,18 @@ namespace Inferno {
float textureIndex = 0; // @Todo get int to pass to fragment correctly
};
struct CharacterVertex {
QuadVertex quad;
float width = 0.44f;
float edge = 0.15f;
float borderWidth = 0.7f;
float borderEdge = 0.1f;
glm::vec4 borderColor { 1.0f, 1.0f, 1.0f, 1.0f };
float offset = 0.0f;
};
// -----------------------------------------
class RenderCommand {
@ -52,6 +64,7 @@ namespace Inferno {
void bind();
void unbind();
virtual void loadShader() = 0;
virtual void flush() = 0;
virtual void startBatch() = 0;
virtual void nextBatch() = 0;
@ -90,6 +103,7 @@ namespace Inferno {
static inline Renderer2D& the() { return *s_instance; }
private:
void loadShader() override;
void flush() override;
void startBatch() override;
void nextBatch() override;
@ -106,6 +120,38 @@ namespace Inferno {
static Renderer2D* s_instance;
};
// -----------------------------------------
class RendererCharacter final : public Renderer {
public:
static const uint32_t quadCount = 1000;
static const uint32_t vertexCount = quadCount * vertexPerQuad;
static const uint32_t indexCount = quadCount * indexPerQuad;
void initialize() override;
void destroy() override;
void beginScene();
void endScene();
void drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, glm::vec4 color, std::shared_ptr<Texture> texture);
void drawCharacter(std::array<CharacterVertex, vertexPerQuad>& characterQuad, glm::mat4 color, std::shared_ptr<Texture> texture);
static inline RendererCharacter& the() { return *s_instance; }
private:
void loadShader() override;
void flush() override;
void startBatch() override;
void nextBatch() override;
// CPU quad vertices
std::unique_ptr<CharacterVertex[]> m_vertexBufferBase = nullptr;
CharacterVertex* m_vertexBufferPtr = nullptr;
static RendererCharacter* s_instance;
};
}
#endif // RENDERER_H

Loading…
Cancel
Save