aboutsummaryrefslogtreecommitdiff
path: root/src/brussel.engine/Renderer.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2023-10-19 22:50:07 -0700
committerrtk0c <[email protected]>2025-08-16 11:31:16 -0700
commit297232d21594b138bb368a42b5b0d085ff9ed6aa (patch)
tree075d5407e1e12a9d35cbee6e4c20ad34e0765c42 /src/brussel.engine/Renderer.cpp
parentd5cd34ff69f7fd134d5450696f298af1a864afbc (diff)
The great renaming: switch to "module style"
Diffstat (limited to 'src/brussel.engine/Renderer.cpp')
-rw-r--r--src/brussel.engine/Renderer.cpp256
1 files changed, 256 insertions, 0 deletions
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 <RapidJsonHelper.hpp>
+
+#include <rapidjson/document.h>
+#include <cassert>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/quaternion.hpp>
+#include <glm/gtx/quaternion.hpp>
+#include <string_view>
+
+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;
+}