Initial commit
This commit is contained in:
commit
edfc5298e1
252 changed files with 93965 additions and 0 deletions
259
source/Graphics/BatchRenderer2D.cpp
Normal file
259
source/Graphics/BatchRenderer2D.cpp
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
|
||||
#include <Spectre/System/Log.h>
|
||||
#include <Spectre/Graphics/OpenGL.h>
|
||||
#include <Spectre/Graphics/Renderable.h>
|
||||
#include <Spectre/Graphics/RenderState.h>
|
||||
#include <Spectre/Graphics/ShaderProgram.h>
|
||||
#include <Spectre/Graphics/Texture.h>
|
||||
#include <Spectre/Graphics/BatchRenderer2D.h>
|
||||
#include <Spectre/Math/Math.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static bool compare_renderable(const Renderable2D* a, const Renderable2D* b) {
|
||||
|
||||
if (a->getRenderType() != b->getRenderType()) {
|
||||
return a->getRenderType() < b->getRenderType();
|
||||
}
|
||||
if (a->getTexture() != b->getTexture()) {
|
||||
return a->getTexture() < b->getTexture();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BatchRenderer2D::BatchRenderer2D()
|
||||
{
|
||||
// Generate buffer objects.
|
||||
glGenBuffers(1, &m_IBO);
|
||||
glGenBuffers(1, &m_VBO);
|
||||
|
||||
setBatchSize(10000);
|
||||
|
||||
m_textShader.create();
|
||||
if (!m_textShader.loadFromFile("assets/shaders/text.shader.glsl")) {
|
||||
std::cout << "Failed to load shader: " << m_textShader.getLastError() << std::endl;
|
||||
}
|
||||
|
||||
if (!m_textShader.link()) {
|
||||
std::cout << "Failed to link shader: " << m_textShader.getLastError() << std::endl;
|
||||
}
|
||||
|
||||
m_spriteShader.create();
|
||||
if (!m_spriteShader.loadFromFile("assets/shaders/standard.shader.glsl")) {
|
||||
std::cout << "Failed to load shader: " << m_spriteShader.getLastError() << std::endl;
|
||||
}
|
||||
|
||||
if (!m_spriteShader.link()) {
|
||||
std::cout << "Failed to link shader: " << m_spriteShader.getLastError() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
BatchRenderer2D::~BatchRenderer2D()
|
||||
{
|
||||
glDeleteBuffers(1, &m_VBO);
|
||||
glDeleteBuffers(1, &m_IBO);
|
||||
}
|
||||
|
||||
void BatchRenderer2D::setBatchSize(unsigned short size)
|
||||
{
|
||||
std::vector<unsigned short> indices;
|
||||
int vtx = 0;
|
||||
|
||||
if (size > 10000) {
|
||||
size = 10000;
|
||||
}
|
||||
m_size = size;
|
||||
|
||||
indices.resize(size * 6);
|
||||
|
||||
for(int i = 0; i < m_size * 6; i += 6) {
|
||||
indices[i + 0] = vtx + 0;
|
||||
indices[i + 1] = vtx + 1;
|
||||
indices[i + 2] = vtx + 2;
|
||||
indices[i + 3] = vtx + 2;
|
||||
indices[i + 4] = vtx + 3;
|
||||
indices[i + 5] = vtx + 0;
|
||||
vtx += 4;
|
||||
}
|
||||
|
||||
// Upload to GPU
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
// Allocate memory for vertex buffer.
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, m_size * sizeof(Vertex2D), NULL, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// Log
|
||||
log("BatchRenderer - BatchSize\n");
|
||||
log(" num sprites: %i\n", m_size);
|
||||
log(" num indices: %i\n", m_size * 6);
|
||||
log(" num vertices: %i\n", m_size);
|
||||
log("------\n");
|
||||
}
|
||||
|
||||
void BatchRenderer2D::begin()
|
||||
{
|
||||
}
|
||||
|
||||
void BatchRenderer2D::end()
|
||||
{
|
||||
}
|
||||
|
||||
void BatchRenderer2D::submit(const Renderable2D& renderable)
|
||||
{
|
||||
m_queue.push_back(&renderable);
|
||||
}
|
||||
|
||||
void BatchRenderer2D::render()
|
||||
{
|
||||
Matrix4f viewMatrix = m_camera ? m_camera->getViewMatrix() : Matrix4f::Identity;
|
||||
Matrix4f projMatrix = m_camera ? m_camera->getProjectionMatrix() : Matrix4f::Identity;
|
||||
Matrix4f guiMatrix = math::orthoProjection(0.0f, 800.0f, 600.0f, 0.0f);
|
||||
Matrix4f MVP = projMatrix * viewMatrix;
|
||||
|
||||
// Nothing to render.
|
||||
if (m_queue.size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind buffers.
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
|
||||
|
||||
// Setup position.
|
||||
glEnableVertexAttribArray(VertexAttribPosition);
|
||||
glVertexAttribPointer(VertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*) 0);
|
||||
|
||||
|
||||
// Setup color
|
||||
glEnableVertexAttribArray(VertexAttribColor0);
|
||||
glVertexAttribPointer(VertexAttribColor0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*) 8);
|
||||
|
||||
glEnableVertexAttribArray(VertexAttribTexCoord0);
|
||||
glVertexAttribPointer(VertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*) 20);
|
||||
|
||||
// Set shader uniforms.
|
||||
m_textShader.enable();
|
||||
m_textShader.setUniform("u_MVP", MVP);
|
||||
m_textShader.disable();
|
||||
|
||||
m_spriteShader.enable();
|
||||
m_spriteShader.setUniform("u_MVP", MVP);
|
||||
m_spriteShader.disable();
|
||||
|
||||
prepareQueue();
|
||||
|
||||
glDisableVertexAttribArray(VertexAttribPosition);
|
||||
glDisableVertexAttribArray(VertexAttribColor0);
|
||||
glDisableVertexAttribArray(VertexAttribTexCoord0);
|
||||
|
||||
// Unbind all buffers.
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
m_queue.clear();
|
||||
m_state.cleanup();
|
||||
}
|
||||
|
||||
void BatchRenderer2D::prepareQueue()
|
||||
{
|
||||
Vertex2D *buffer = static_cast<Vertex2D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
|
||||
|
||||
Batch current;
|
||||
|
||||
std::sort(m_queue.begin(), m_queue.end(), compare_renderable);
|
||||
|
||||
current.type = m_queue[0]->getRenderType();
|
||||
current.texture = m_queue[0]->getTexture();
|
||||
current.count = 0;
|
||||
current.offset = 0;
|
||||
|
||||
for(int i = 0; i < m_queue.size(); i++) {
|
||||
|
||||
const Texture *tex = m_queue[i]->getTexture();
|
||||
RenderType type = m_queue[i]->getRenderType();
|
||||
unsigned int num_vert = m_queue[i]->getVertices().size();
|
||||
|
||||
// TODO: Only upload and draw if buffer is full :)
|
||||
if (current.type != type || current.texture != tex || current.count >= m_size) {
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
drawBatch(current);
|
||||
buffer = static_cast<Vertex2D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
|
||||
|
||||
current.type = m_queue[i]->getRenderType();
|
||||
current.count = 0;
|
||||
current.offset = 0;
|
||||
current.texture = tex;
|
||||
}
|
||||
|
||||
buffer += addRenderable(buffer, m_queue[i]);
|
||||
current.count += num_vert;
|
||||
}
|
||||
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
|
||||
if (current.count > 0) {
|
||||
drawBatch(current);
|
||||
}
|
||||
}
|
||||
|
||||
void BatchRenderer2D::uploadBatch(const Batch& batch)
|
||||
{
|
||||
Vertex2D *buffer = static_cast<Vertex2D*>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
|
||||
unsigned int count = 0;
|
||||
|
||||
for(int i = 0; i < batch.count; i++) {
|
||||
buffer += addRenderable(buffer, m_queue[batch.offset + i]);
|
||||
}
|
||||
|
||||
// Upload gpu data and draw.
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
unsigned int BatchRenderer2D::addRenderable(Vertex2D* buffer, const Renderable2D* renderable)
|
||||
{
|
||||
const Transform& transform = renderable->getTransform();
|
||||
const std::vector<Vertex2D>& vertices = renderable->getVertices();
|
||||
|
||||
// Pretransform vertex positions to skip setting a uniform model
|
||||
// matrix in the shader for each renderable reducing the number of draw calls.
|
||||
|
||||
for(int i = 0; i < vertices.size(); i++) {
|
||||
buffer[i].position = transform * vertices[i].position;
|
||||
buffer[i].color = vertices[i].color;
|
||||
buffer[i].uv = vertices[i].uv;
|
||||
}
|
||||
|
||||
return vertices.size();
|
||||
}
|
||||
|
||||
|
||||
void BatchRenderer2D::drawBatch(Batch& batch)
|
||||
{
|
||||
const ShaderProgram* shader;
|
||||
|
||||
if (batch.type == RenderType_UI) {
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
shader = &m_textShader;
|
||||
} else {
|
||||
shader = &m_spriteShader;
|
||||
}
|
||||
|
||||
// enable shader.
|
||||
m_state.enableShader(shader);
|
||||
|
||||
// enable batch texture
|
||||
m_state.enableTexture(batch.texture);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, (batch.count / 4) * 6, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
if (batch.type == RenderType_UI) {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue