#include "Renderer.hpp" #include RenderObject::RenderObject() : mVao{ GL_NONE } { } RenderObject::~RenderObject() { DeleteGLObjects(); } GLuint RenderObject::GetGLVao() const { return mVao; } void RenderObject::RebuildIfNecessary() { if (mVao != GL_NONE) { return; } assert(mIndexBuf != nullptr); assert(mVertexFormat != nullptr); glGenVertexArrays(1, &mVao); glBindVertexArray(mVao); auto& vBindings = mVertexBufBinding.bindings; auto& shaderInfo = mMaterial->GetShader()->GetInfo(); // Setup vertex buffers for (auto& elm : mVertexFormat->elements) { assert(elm.bindingIndex < vBindings.size()); auto& buffer = vBindings[elm.bindingIndex]; int index = shaderInfo.FindInputLocation(elm.semantic); if (index == -1) { continue; } glBindBuffer(GL_ARRAY_BUFFER, buffer->handle); glEnableVertexAttribArray(index); glVertexAttribPointer( index, Tags::VectorLenOf(elm.type), Tags::FindGLType(elm.type), Tags::IsNormalized(elm.type), mVertexFormat->vertexSize, (void*)(uintptr_t)elm.offset); } // Setup index buffer glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuf->handle); glBindVertexArray(GL_NONE); } void RenderObject::SetMaterial(Material* material) { mMaterial.Attach(material); DeleteGLObjects(); } void RenderObject::UpdateIndexBuffer(GpuIndexBuffer* indexBuffer) { mIndexBuf.Attach(indexBuffer); DeleteGLObjects(); } void RenderObject::UpdateVertexFormat(VertexFormat* vertexFormat) { mVertexFormat.Attach(vertexFormat); DeleteGLObjects(); } void RenderObject::UpdateVertexBufferBindings(BufferBindings** bindingsOut) { *bindingsOut = &mVertexBufBinding; DeleteGLObjects(); } void RenderObject::SetFormat(VertexFormat* vertexFormat, Tags::IndexType indexFormat) { mIndexBuf.Attach(new GpuIndexBuffer()); mIndexBuf->indexType = indexFormat; mIndexBuf->count = 0; mVertexFormat.Attach(vertexFormat); mVertexBufBinding.Clear(); for (auto& element : vertexFormat->elements) { if (mVertexBufBinding.GetBinding(element.bindingIndex) == nullptr) { mVertexBufBinding.SetBinding(element.bindingIndex, new GpuVertexBuffer()); } } } void RenderObject::DeleteGLObjects() { if (mVao != GL_NONE) { glDeleteVertexArrays(1, &mVao); mVao = GL_NONE; } } void Renderer::BeginFrame(Camera& camera, float currentTime, float deltaTime) { assert(mInsideFrame == false); mInsideFrame = true; mFrame.camera = &camera; mFrame.matrixView = camera.CalcViewMatrix(); mFrame.matrixProj = camera.CalcProjectionMatrix(); mFrame.matrixCombined = mFrame.matrixProj * mFrame.matrixView; mFrame.time = currentTime; mFrame.deltaTime = deltaTime; } void Renderer::EndFrame() { assert(mInsideFrame == true); mInsideFrame = false; } void Renderer::Draw(const RenderObject* objects, size_t count) { using namespace Tags; assert(mInsideFrame); // TODO shader grouping // TODO material grouping for (size_t i = 0; i < count; ++i) { auto& object = objects[i]; auto indexBuffer = object.GetIndexBuffer(); auto mat = object.GetMaterial(); auto shader = mat->GetShader(); glUseProgram(shader->GetProgram()); // Material uniforms mat->UseUniforms(); // Next available texture unit ID after all material textures int texIdx = mat->GetTextures().size(); // Autofill uniforms if (shader->autofill_Transform != kInvalidLocation) { glUniformMatrix4fv(shader->autofill_Transform, 1, GL_FALSE, &mFrame.matrixCombined[0][0]); } if (shader->autofill_Time != kInvalidLocation) { glUniform1f(shader->autofill_Time, mFrame.time); } if (shader->autofill_DeltaTime != kInvalidLocation) { glUniform1f(shader->autofill_DeltaTime, mFrame.deltaTime); } if (shader->autofill_TextureAtlas != kInvalidLocation && object.autofill_TextureAtlas != nullptr) { glActiveTexture(GL_TEXTURE0 + texIdx); glBindTexture(GL_TEXTURE_2D, object.autofill_TextureAtlas->GetHandle()); glUniform1i(shader->autofill_TextureAtlas, texIdx); ++texIdx; } glBindVertexArray(object.GetGLVao()); glDrawElements(GL_TRIANGLES, indexBuffer->count, indexBuffer->GetIndexTypeGL(), 0); } }