diff --git a/CMakeLists.txt b/CMakeLists.txt index ff71ed8..08411cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,12 @@ add_library(Engine STATIC engine/src/utils/openglWrapper/GLRenderState.h engine/src/utils/openglWrapper/openglObjects/Attribute.cpp engine/src/utils/openglWrapper/openglObjects/Attribute.h + engine/src/utils/openglWrapper/openglObjects/Vbo.cpp + engine/src/utils/openglWrapper/openglObjects/Vbo.h + engine/src/utils/openglWrapper/openglObjects/Vao.cpp + engine/src/utils/openglWrapper/openglObjects/Vao.h + engine/src/utils/openglWrapper/shader/ShaderProgram.cpp + engine/src/utils/openglWrapper/shader/ShaderProgram.h ) target_include_directories(Engine PUBLIC engine/src) target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui) @@ -98,8 +104,7 @@ add_executable(ColorRace game/src/main.cpp game/src/ColorRaceApp.cpp game/src/ColorRaceApp.h - engine/src/utils/openglWrapper/shader/ShaderProgram.cpp - engine/src/utils/openglWrapper/shader/ShaderProgram.h + ) target_link_libraries(ColorRace PRIVATE diff --git a/engine/src/utils/openglWrapper/openglObjects/Attribute.h b/engine/src/utils/openglWrapper/openglObjects/Attribute.h index 7cad1ad..a78a710 100644 --- a/engine/src/utils/openglWrapper/openglObjects/Attribute.h +++ b/engine/src/utils/openglWrapper/openglObjects/Attribute.h @@ -16,6 +16,8 @@ namespace engine { void enable(bool enable) const; virtual void link(int offset, int stride); + int getBytesPerVertex() const { return m_bytesPerVertex; } + unsigned int getAttributeNumber() const { return m_attributeNumber; } protected: unsigned int m_attributeNumber; diff --git a/engine/src/utils/openglWrapper/openglObjects/Vao.cpp b/engine/src/utils/openglWrapper/openglObjects/Vao.cpp new file mode 100644 index 0000000..52cf342 --- /dev/null +++ b/engine/src/utils/openglWrapper/openglObjects/Vao.cpp @@ -0,0 +1,136 @@ +// +// Created by sebastian on 29.07.26. +// + +#include "Vao.h" +#include "Vao.h" + +namespace engine { + +Vao::Vao(unsigned int id) : m_id(id) { + bind(); +} + +Vao::~Vao() { + glDeleteVertexArrays(1, &m_id); + // m_relatedVbos und m_indexBuffer räumen sich selbst auf (unique_ptr, RAII) +} + +std::unique_ptr Vao::create() { + unsigned int id; + glGenVertexArrays(1, &id); + return std::unique_ptr(new Vao(id)); +} + +void Vao::bind() const { + glBindVertexArray(m_id); +} + +void Vao::unbind() const { + glBindVertexArray(0); +} + +void Vao::enableAttributes() const { + for (const auto& attribute : m_attributes) { + attribute->enable(true); + } +} + +void Vao::disableAttributes(const std::vector& attribNumbers) const { + for (unsigned int i : attribNumbers) { + glDisableVertexAttribArray(i); + } +} + +int Vao::getVertexDataTotalBytes(const std::vector>& attributes) { + int total = 0; + for (const auto& attribute : attributes) { + total += attribute->getBytesPerVertex(); + } + return total; +} + +void Vao::linkAttributes(int bytesPerVertex, std::vector>& newAttributes) { + int offset = 0; + for (auto& attribute : newAttributes) { + attribute->link(offset, bytesPerVertex); + offset += attribute->getBytesPerVertex(); + attribute->enable(true); + m_attributes.push_back(std::move(attribute)); + } +} + +void Vao::indicateInstancedAttributes(const std::vector>& attributes) const { + for (const auto& attribute : attributes) { + glVertexAttribDivisor(attribute->getAttributeNumber(), 1); + } +} + +Vbo& Vao::createDataFeed(size_t maxVertexCount, GLenum usage, + std::vector> newAttributes) { + int bytesPerVertex = getVertexDataTotalBytes(newAttributes); + auto vbo = Vbo::create(GL_ARRAY_BUFFER, usage); + vbo->allocateData(bytesPerVertex * maxVertexCount); + linkAttributes(bytesPerVertex, newAttributes); + vbo->unbind(); + + m_relatedVbos.push_back(std::move(vbo)); + return *m_relatedVbos.back(); +} + +Vbo& Vao::createInstanceDataFeed(size_t maxInstances, + std::vector> newAttributes) { + int bytesPerInstance = getVertexDataTotalBytes(newAttributes); + auto vbo = Vbo::create(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW); + vbo->allocateData(bytesPerInstance * maxInstances); + linkAttributes(bytesPerInstance, newAttributes); + indicateInstancedAttributes(newAttributes); + vbo->unbind(); + + m_relatedVbos.push_back(std::move(vbo)); + return *m_relatedVbos.back(); +} + +Vbo& Vao::initDataFeed(const void* data, size_t sizeInBytes, GLenum usage, + std::vector> newAttributes) { + int bytesPerVertex = getVertexDataTotalBytes(newAttributes); + auto vbo = Vbo::create(GL_ARRAY_BUFFER, usage); + vbo->allocateAndStoreData(data, sizeInBytes); + linkAttributes(bytesPerVertex, newAttributes); + vbo->unbind(); + + m_relatedVbos.push_back(std::move(vbo)); + return *m_relatedVbos.back(); +} + +void Vao::linkBoundVbo(std::unique_ptr vbo, + std::vector> newAttributes) { + int bytesPerVertex = getVertexDataTotalBytes(newAttributes); + linkAttributes(bytesPerVertex, newAttributes); + m_relatedVbos.push_back(std::move(vbo)); +} + +void Vao::linkInstancingVbo(std::unique_ptr vbo, + std::vector> newAttributes) { + vbo->bind(); + int bytesPerVertex = getVertexDataTotalBytes(newAttributes); + linkAttributes(bytesPerVertex, newAttributes); + indicateInstancedAttributes(newAttributes); + vbo->unbind(); + + m_relatedVbos.push_back(std::move(vbo)); +} + +Vbo& Vao::createIndexBuffer(const unsigned int* indices, size_t count) { + m_indexBuffer = Vbo::create(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW); + m_indexBuffer->allocateAndStoreData(indices, count * sizeof(unsigned int)); + return *m_indexBuffer; +} + +Vbo& Vao::createIndexBufferFeed(size_t maxIndexCount) { + m_indexBuffer = Vbo::create(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW); + m_indexBuffer->allocateData(maxIndexCount * sizeof(unsigned int)); + return *m_indexBuffer; +} + +} // namespace engine \ No newline at end of file diff --git a/engine/src/utils/openglWrapper/openglObjects/Vao.h b/engine/src/utils/openglWrapper/openglObjects/Vao.h new file mode 100644 index 0000000..44fc509 --- /dev/null +++ b/engine/src/utils/openglWrapper/openglObjects/Vao.h @@ -0,0 +1,70 @@ +// +// Created by sebastian on 29.07.26. +// + +#ifndef COLORRACE_VAO_H +#define COLORRACE_VAO_H + +#pragma once +#include +#include +#include +#include "Vbo.h" +#include "Attribute.h" + +namespace engine { + +class Vao { +public: + static std::unique_ptr create(); + + ~Vao(); + + Vao(const Vao&) = delete; + Vao& operator=(const Vao&) = delete; + + Vbo& getVbo(size_t index) const { return *m_relatedVbos.at(index); } + + void bind() const; + void unbind() const; + + void enableAttributes() const; + void disableAttributes(const std::vector& attribNumbers) const; + + Vbo& createDataFeed(size_t maxVertexCount, GLenum usage, + std::vector> newAttributes); + + Vbo& createInstanceDataFeed(size_t maxInstances, + std::vector> newAttributes); + + Vbo& initDataFeed(const void* data, size_t sizeInBytes, GLenum usage, + std::vector> newAttributes); + + void linkBoundVbo(std::unique_ptr vbo, + std::vector> newAttributes); + + void linkInstancingVbo(std::unique_ptr vbo, + std::vector> newAttributes); + + Vbo& createIndexBuffer(const unsigned int* indices, size_t count); + Vbo& createIndexBufferFeed(size_t maxIndexCount); + + unsigned int getId() const { return m_id; } + bool hasIndexBuffer() const { return m_indexBuffer != nullptr; } + +private: + explicit Vao(unsigned int id); + + unsigned int m_id; + std::vector> m_relatedVbos; + std::unique_ptr m_indexBuffer; + std::vector> m_attributes; + + void indicateInstancedAttributes(const std::vector>& attributes) const; + void linkAttributes(int bytesPerVertex, std::vector>& newAttributes); + static int getVertexDataTotalBytes(const std::vector>& attributes); +}; + +} // namespace engine + +#endif //COLORRACE_VAO_H diff --git a/engine/src/utils/openglWrapper/openglObjects/Vbo.cpp b/engine/src/utils/openglWrapper/openglObjects/Vbo.cpp new file mode 100644 index 0000000..5ea06a4 --- /dev/null +++ b/engine/src/utils/openglWrapper/openglObjects/Vbo.cpp @@ -0,0 +1,92 @@ +// +// Created by sebastian on 29.07.26. +// + +#include "Vbo.h" + +namespace engine { + +Vbo::Vbo(unsigned int id, GLenum type, GLenum usage) + : m_id(id), m_type(type), m_usage(usage) { + bind(); +} + +Vbo::~Vbo() { + glDeleteBuffers(1, &m_id); +} + +std::unique_ptr Vbo::create(GLenum type, GLenum usage) { + unsigned int id; + glGenBuffers(1, &id); + // std::unique_ptr(new Vbo(...)), da Konstruktor privat ist und + // std::make_unique keinen Zugriff auf private Konstruktoren hat + return std::unique_ptr(new Vbo(id, type, usage)); +} + +std::unique_ptr Vbo::createAndAllocate(GLenum type, GLenum usage, size_t sizeInBytes) { + auto vbo = create(type, usage); + vbo->allocateData(sizeInBytes); + return vbo; +} + +void Vbo::bind() const { + glBindBuffer(m_type, m_id); +} + +void Vbo::unbind() const { + glBindBuffer(m_type, 0); +} + +void Vbo::allocateData(size_t sizeInBytes) { + allocateData(sizeInBytes, m_type); +} + +void Vbo::orphan() { + allocateData(m_sizeInBytes, m_type); +} + +void Vbo::allocateData(size_t sizeInBytes, GLenum target) { + glBufferData(target, static_cast(sizeInBytes), nullptr, m_usage); + m_sizeInBytes = sizeInBytes; +} + +void Vbo::storeData(size_t startInBytes, const void* data, size_t dataSizeInBytes) { + glBufferSubData(m_type, static_cast(startInBytes), + static_cast(dataSizeInBytes), data); +} + +void Vbo::allocateAndStoreData(const void* data, size_t sizeInBytes) { + glBufferData(m_type, static_cast(sizeInBytes), data, m_usage); + m_sizeInBytes = sizeInBytes; +} + +std::unique_ptr Vbo::createTempVbo(size_t dataSize) { + auto tempVbo = create(GL_COPY_WRITE_BUFFER, GL_STATIC_COPY); // TODO: GL_STREAM_COPY erwägen? + tempVbo->allocateData(dataSize); + return tempVbo; +} + +void Vbo::copyContentsTo(Vbo& destination, size_t readStart, size_t writeStart, size_t dataSize) const { + glBindBuffer(GL_COPY_READ_BUFFER, m_id); + glBindBuffer(GL_COPY_WRITE_BUFFER, destination.m_id); + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, + static_cast(readStart), static_cast(writeStart), + static_cast(dataSize)); +} + +void Vbo::resize(size_t copyDataSize, size_t newSizeInBytes) { + if (copyDataSize == 0) { + bind(); + allocateData(newSizeInBytes); + return; + } + + auto temporaryVbo = createTempVbo(copyDataSize); + copyContentsTo(*temporaryVbo, 0, 0, copyDataSize); + allocateData(newSizeInBytes, GL_COPY_READ_BUFFER); + temporaryVbo->copyContentsTo(*this, 0, 0, copyDataSize); + // temporaryVbo wird hier automatisch gelöscht (unique_ptr out-of-scope) - + // kein manuelles delete() nötig, im Gegensatz zur Java-Vorlage +} + +} // namespace engine \ No newline at end of file diff --git a/engine/src/utils/openglWrapper/openglObjects/Vbo.h b/engine/src/utils/openglWrapper/openglObjects/Vbo.h new file mode 100644 index 0000000..2ab897a --- /dev/null +++ b/engine/src/utils/openglWrapper/openglObjects/Vbo.h @@ -0,0 +1,58 @@ +// +// Created by sebastian on 29.07.26. +// + +#ifndef COLORRACE_VBO_H +#define COLORRACE_VBO_H +#pragma once +#include +#include +#include + +namespace engine { + class Vbo { + public: + static std::unique_ptr create(GLenum type, GLenum usage); + static std::unique_ptr createAndAllocate(GLenum type, GLenum usage, size_t sizeInBytes); + + ~Vbo(); + + Vbo(const Vbo&) = delete; + Vbo& operator=(const Vbo&) = delete; + + [[nodiscard]] size_t getByteSize() const { return m_sizeInBytes; } + [[nodiscard]] unsigned int getId() const { return m_id; } + + void bind() const; + void unbind() const; + + + // Legt den Buffer neu an; kopiert optional vorhandene Daten in den neuen, größeren/kleineren Buffer + void resize(size_t copyDataSize, size_t newSizeInBytes); + + void copyContentsTo(Vbo& destination, size_t readStart, size_t writeStart, size_t dataSize) const; + + void allocateData(size_t sizeInBytes); + void allocateData(size_t sizeInBytes, GLenum target); + void orphan(); + + void storeData(size_t startInBytes, const void* data, size_t dataSizeInBytes); + void allocateAndStoreData(const void* data, size_t sizeInBytes); + + private: + Vbo(unsigned int id, GLenum type, GLenum usage); + + unsigned int m_id; + GLenum m_type; + GLenum m_usage; + size_t m_sizeInBytes = 0; + + static std::unique_ptr createTempVbo(size_t dataSize); + + }; +} + + + + +#endif //COLORRACE_VBO_H