From 297232d21594b138bb368a42b5b0d085ff9ed6aa Mon Sep 17 00:00:00 2001 From: rtk0c Date: Thu, 19 Oct 2023 22:50:07 -0700 Subject: The great renaming: switch to "module style" --- src/brussel.engine/Renderer.cpp | 256 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 src/brussel.engine/Renderer.cpp (limited to 'src/brussel.engine/Renderer.cpp') diff --git a/src/brussel.engine/Renderer.cpp b/src/brussel.engine/Renderer.cpp new file mode 100644 index 0000000..0454efe --- /dev/null +++ b/src/brussel.engine/Renderer.cpp @@ -0,0 +1,256 @@ +#include "Renderer.hpp" + +#include "GameObject.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +RenderObject::RenderObject() + : mVao{ 0 } { +} + +RenderObject::~RenderObject() { + DeleteGLObjects(); +} + +GLuint RenderObject::GetGLVao() const { + return mVao; +} + +void RenderObject::RebuildIfNecessary() { + if (mVao != 0) { + 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(0); +} + +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 != 0) { + glDeleteVertexArrays(1, &mVao); + mVao = 0; + } +} + +Renderer::Renderer() + : binding_WireframeMaterial{ gDefaultMaterial } // +{ + mRenderOptions[RO_Shading] = true; + mRenderOptions[RO_Wireframe] = false; +} + +void Renderer::LoadBindings(const rapidjson::Value& bindings) { + if (auto rvWireframe = rapidjson::GetProperty(bindings, "WireframeMaterial"sv)) { + Uid uidWireframe; + uidWireframe.Read(*rvWireframe); + // TODO don't assume + binding_WireframeMaterial.Attach(((IresMaterial*)IresManager::instance->FindIres(uidWireframe))->GetInstance()); + } +} + +void Renderer::SaveBindings(rapidjson::Value& into, rapidjson::Document& root) const { + if (auto ires = binding_WireframeMaterial->GetIres()) { + into.AddMember("WireframeMaterial", ires->GetUid().Write(root), root.GetAllocator()); + } +} + +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); + + // Desired order: proj * view * (translate * rotate * scale) * vec + // <----- order of application <----- ^^^ input + glm::mat4 objectMatrix(1.0f); + objectMatrix = glm::translate(objectMatrix, gameObject->GetPos()); + objectMatrix *= glm::toMat4(gameObject->GetRotation()); + objectMatrix = glm::scale(objectMatrix, gameObject->GetScale()); + auto mvpMatrix = mFrame.matrixProj * mFrame.matrixView * objectMatrix; + + if (GetRenderOption(RO_Shading)) { + // 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, &mvpMatrix[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); + } + } + + if (GetRenderOption(RO_Wireframe)) { + auto& mat = *binding_WireframeMaterial; + auto& shader = *mat.GetShader(); + auto& shaderInfo = shader.GetInfo(); + + glUseProgram(shader.GetProgram()); + mat.UseUniforms(); + + // TODO reduce calls with consecutive wireframe setting + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + for (size_t i = 0; i < count; ++i) { + auto& object = objects[i]; + + auto& vBindings = object.GetVertexBufferBindings().bindings; + auto vf = object.GetVertexFormat(); + + // Setup vertex buffers + for (auto& elm : vf->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), + vf->vertexSize, + (void*)(uintptr_t)elm.offset); + } + + // Setup index buffer + auto indexBuffer = object.GetIndexBuffer(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->handle); + + glDrawElements(GL_TRIANGLES, indexBuffer->count, indexBuffer->GetIndexTypeGL(), 0); + } + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + return; + } +} + +bool Renderer::GetRenderOption(RenderOption option) const { + return mRenderOptions[option]; +} + +void Renderer::SetRenderOption(RenderOption option, bool flag) { + mRenderOptions[option] = flag; +} -- cgit v1.2.3-70-g09d2