aboutsummaryrefslogtreecommitdiff
path: root/ProjectBrussel/Game/Renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ProjectBrussel/Game/Renderer.cpp')
-rw-r--r--ProjectBrussel/Game/Renderer.cpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/ProjectBrussel/Game/Renderer.cpp b/ProjectBrussel/Game/Renderer.cpp
new file mode 100644
index 0000000..3497449
--- /dev/null
+++ b/ProjectBrussel/Game/Renderer.cpp
@@ -0,0 +1,170 @@
+#include "Renderer.hpp"
+
+#include "GameObject.hpp"
+
+#include <cassert>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/quaternion.hpp>
+#include <glm/gtx/quaternion.hpp>
+
+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.time = currentTime;
+ mFrame.deltaTime = deltaTime;
+}
+
+void Renderer::EndFrame() {
+ assert(mInsideFrame == true);
+ mInsideFrame = false;
+}
+
+void Renderer::Draw(const RenderObject* objects, const GameObject* gameObject, size_t count) {
+ using namespace Tags;
+
+ assert(mInsideFrame);
+
+ auto vpMatrix = mFrame.matrixProj * mFrame.matrixView;
+
+ // 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) {
+ glm::mat4 objectMatrix(1.0f);
+ objectMatrix = glm::translate(objectMatrix, gameObject->GetPos());
+ objectMatrix *= glm::toMat4(gameObject->GetRotation());
+ objectMatrix = glm::scale(objectMatrix, gameObject->GetScale());
+ glm::mat4 transform = vpMatrix * objectMatrix;
+
+ glUniformMatrix4fv(shader->autofill_Transform, 1, GL_FALSE, &transform[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);
+ }
+}