From 095790a9542e4fc784a5d790371651c47aa51a3f Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Mon, 18 Apr 2022 13:26:46 +0100 Subject: [PATCH] use new shiny interface for canvas rendering --- demo/main.cpp | 2 +- fggl/CMakeLists.txt | 1 + fggl/gfx/CMakeLists.txt | 1 + fggl/gfx/ogl/CMakeLists.txt | 1 + fggl/gfx/ogl/renderer.cpp | 84 +----------- fggl/gfx/ogl/types.cpp | 135 +++++++++++++++++++ fggl/gfx/ogl4/CMakeLists.txt | 6 + fggl/gfx/ogl4/canvas.cpp | 92 ++++++++++++- fggl/math/triangulation.cpp | 48 +++++++ fggl/scenes/menu.cpp | 3 +- include/fggl/gfx/ogl/renderer.hpp | 10 +- include/fggl/gfx/ogl/types.hpp | 201 +++++++++++++++++++++++----- include/fggl/gfx/ogl4/canvas.hpp | 11 +- include/fggl/math/triangulation.hpp | 25 +--- 14 files changed, 477 insertions(+), 143 deletions(-) create mode 100644 fggl/gfx/ogl/types.cpp create mode 100644 fggl/gfx/ogl4/CMakeLists.txt create mode 100644 fggl/math/triangulation.cpp diff --git a/demo/main.cpp b/demo/main.cpp index 64d444e..067388d 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -397,7 +397,7 @@ int main(int argc, const char* argv[]) { menu->add("start", [&app]() { app.change_state("game"); }); menu->add("options", [&app]() { app.change_state("game"); }); - menu->add("quit", [&app]() { app.change_state("game"); }); + menu->add("quit", [&app]() { app.running(false); }); // game state app.add_state<GameScene>("game"); diff --git a/fggl/CMakeLists.txt b/fggl/CMakeLists.txt index 0ff4692..d9b16e9 100644 --- a/fggl/CMakeLists.txt +++ b/fggl/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(${PROJECT_NAME} gui/widget.cpp gui/widgets.cpp gui/containers.cpp + math/triangulation.cpp ) # spdlog for cleaner logging diff --git a/fggl/gfx/CMakeLists.txt b/fggl/gfx/CMakeLists.txt index 3b9118f..40d3bef 100644 --- a/fggl/gfx/CMakeLists.txt +++ b/fggl/gfx/CMakeLists.txt @@ -9,4 +9,5 @@ target_sources(fggl # OpenGL backend add_subdirectory(ogl) +add_subdirectory(ogl4) diff --git a/fggl/gfx/ogl/CMakeLists.txt b/fggl/gfx/ogl/CMakeLists.txt index 62e8533..3eb9f94 100644 --- a/fggl/gfx/ogl/CMakeLists.txt +++ b/fggl/gfx/ogl/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(fggl backend.cpp shader.cpp renderer.cpp + types.cpp ) # OpenGL Backend diff --git a/fggl/gfx/ogl/renderer.cpp b/fggl/gfx/ogl/renderer.cpp index baf0a00..af9e019 100644 --- a/fggl/gfx/ogl/renderer.cpp +++ b/fggl/gfx/ogl/renderer.cpp @@ -160,10 +160,12 @@ namespace fggl::gfx { m_cache = std::make_unique<ShaderCache>(storage); // setup 2D rendering system - m_token2D = setupVertex2D(); ShaderConfig shader2DConfig = ShaderFromName("shader2D"); m_cache->load(shader2DConfig); + // rendering helpers + m_canvasRenderer = std::make_unique<ogl4::CanvasRenderer>(); + m_modelRenderer = std::make_unique<ogl4::StaticModelRenderer>(); }; void OpenGL4Backend::clear() { @@ -171,85 +173,13 @@ namespace fggl::gfx { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - inline static void add_mesh_triangle(data::Mesh2D& mesh, const std::vector<data::Vertex2D>& verts) { - assert( verts.size() == 3); - for( const auto& vert : verts ) { - auto idx = mesh.add_vertex(vert); - mesh.add_index(idx); - } - } - - static void generateMesh(const gfx::Paint &paint, Mesh2D &mesh) { - for (const auto &cmd : paint.cmds()) { - auto path = cmd.path; - - std::vector<data::Vertex2D> verts; - math::vec3 colour{1.0F, 1.0F, 1.0F}; - auto idx = 0; - auto colourIdx = 0; - - for (auto &type : path.m_types) { - if (type == PathType::PATH) { - verts.push_back({.position = path.m_points[idx++], .colour = colour}); - } else if (type == PathType::MOVE) { - // polygon finished - if (verts.size() < 3) { - // empty, point, or line - // TODO deal with whatever I'm meant to do with this... - } else if (verts.size() == 3) { - // triangle - add_mesh_triangle(mesh, verts); - } else { - // polygon - math::fanTriangulation(verts, mesh); - } - - verts.clear(); - verts.push_back({.position = path.m_points[idx++], .colour = colour}); - } else if (type == PathType::COLOUR) { - colour = path.m_colours[colourIdx++]; - } else { - // unsupported type - } - } - - if (!verts.empty()) { - math::fanTriangulation(verts, mesh); - } - } - } - void OpenGL4Backend::draw2D(const gfx::Paint &paint) { - // generate the mesh from a paint command list - data::Mesh2D mesh; - generateMesh(paint, mesh); + if ( !m_canvasRenderer ) { + return; + } - // render the resulting mesh auto shader2D = m_cache->get("shader2D"); - - glUseProgram(shader2D); - - auto projMat = glm::ortho(0.0f, 1920.0f, 0.0f, 1080.f); - glUniformMatrix4fv(glGetUniformLocation(shader2D, "projection"), 1, GL_FALSE, - glm::value_ptr(projMat)); - - glBindVertexArray(m_token2D.vao); - - glBindBuffer(GL_ARRAY_BUFFER, m_token2D.buffs[0]); - glBufferData(GL_ARRAY_BUFFER, mesh.vertexList.size() * sizeof(Vertex2D), - mesh.vertexList.data(), GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_token2D.buffs[1]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - mesh.indexList.size() * sizeof(uint32_t), mesh.indexList.data(), - GL_DYNAMIC_DRAW); - - glDrawElements(GL_TRIANGLES, mesh.indexList.size(), GL_UNSIGNED_INT, - (GLvoid *) 0); - - glBindVertexArray(0); - glUseProgram(0); - // glDisable(GL_PRIMITIVE_RESTART); + m_canvasRenderer->render(shader2D, paint); } void OpenGL4Backend::resize(int width, int height) { diff --git a/fggl/gfx/ogl/types.cpp b/fggl/gfx/ogl/types.cpp new file mode 100644 index 0000000..7bb8293 --- /dev/null +++ b/fggl/gfx/ogl/types.cpp @@ -0,0 +1,135 @@ +/* + * ${license.title} + * Copyright (C) 2022 ${license.owner} + * ${license.mailto} + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "fggl/gfx/ogl/types.hpp" +#include <cassert> + +// +// special defines: +// +// FGGL_GL_I_BOUND will take responsibility away from fggl for ensuring buffers are bound before use. +// FGGL_GL_PARANOID will try to ensure that openGL state is managed correctly in method calls, but will be slower + +namespace fggl::gfx::ogl { + + template<> const BuffAttrF attr_type<float>::attr = BuffAttrF::FLOAT; + template<> const BuffAttrF attr_type<math::vec2>::attr = BuffAttrF::FLOAT; + template<> const BuffAttrF attr_type<math::vec3>::attr = BuffAttrF::FLOAT; + template<> const BuffAttrF attr_type<math::vec4>::attr = BuffAttrF::FLOAT; + template<> const GLint attr_type<float>::size = 1; + template<> const GLint attr_type<math::vec2>::size = 2; + template<> const GLint attr_type<math::vec3>::size = 3; + template<> const GLint attr_type<math::vec4>::size = 4; + + VertexArray::VertexArray() { + glGenVertexArrays(1, &m_obj); + } + + VertexArray::~VertexArray() { + release(); + } + + VertexArray::VertexArray(VertexArray &&other) noexcept : m_obj(other.m_obj) { + other.m_obj = 0; + } + + VertexArray &VertexArray::operator=(VertexArray &&other) { + if ( this != &other ){ + release(); + std::swap(m_obj, other.m_obj); + } + return *this; + } + + void VertexArray::release() { + glDeleteVertexArrays(1, &m_obj); + m_obj = 0; + } + + void VertexArray::setAttribute(const ArrayBuffer& buff, GLuint idx, AttributeF& attr) { + assert( 0 <= idx && idx < GL_MAX_VERTEX_ATTRIBS); + assert( 1 <= attr.elmCount && attr.elmCount <= 4); + assert( buff.isValid() ); + + #ifndef FGGL_GL_I_BOUND + bind(); + GLuint boundVertexArray = 0; + bind_buffer(&boundVertexArray, buff); + #endif + + glEnableVertexAttribArray(idx); + glVertexAttribPointer( idx, attr.elmCount, (GLenum)attr.attrType, GL_FALSE, attr.stride, (void*)attr.offset); + + #ifndef FGGL_GL_I_BOUND + unbind_buffer(&boundVertexArray, buff); + #endif + } + + void VertexArray::setAttribute(const ArrayBuffer& buff, GLuint idx, AttributeI& attr, bool normalized) { + assert( 0 <= idx && idx < GL_MAX_VERTEX_ATTRIBS); + assert( 1 <= attr.elmCount && attr.elmCount <= 4); + assert( buff.isValid() ); + + #ifndef FGGL_GL_I_BOUND + GLuint boundVertexArray = 0; + bind_buffer(&boundVertexArray, buff); + #endif + + glVertexAttribPointer(idx, attr.elmCount, (GLenum)attr.attrType, (GLboolean)normalized, attr.stride, (void*)attr.offset); + + #ifndef FGGL_GL_I_BOUND + unbind_buffer(&boundVertexArray, buff); + #endif + } + + void VertexArray::setAttributeI(const ArrayBuffer& buff, GLuint idx, AttributeI& attr) { + assert( 0 <= idx && idx < GL_MAX_VERTEX_ATTRIBS); + assert( 1 <= attr.elmCount && attr.elmCount <= 4); + assert( buff.isValid() ); + + #ifndef FGGL_GL_I_BOUND + GLuint boundVertexArray = 0; + bind_buffer(&boundVertexArray, buff); + #endif + + glVertexAttribIPointer( idx, attr.elmCount, (GLenum)attr.attrType, attr.stride, (void*)attr.offset); + + #ifndef FGGL_GL_I_BOUND + unbind_buffer(&boundVertexArray, buff); + #endif + } + + void VertexArray::drawElements(const ElementBuffer &buff, Primative drawType, std::size_t size) { + bind(); + + #ifndef FGGL_I_BOUND + GLuint boundElementArray = 0; + bind_buffer(&boundElementArray, buff); + #endif + + glDrawElements( (GLenum)drawType, (GLsizei)size, GL_UNSIGNED_INT, nullptr ); + + #ifndef FGGL_I_BOUND + unbind_buffer(&boundElementArray, buff); + #endif + } + + +} // namespace fggl::gfx::ogl \ No newline at end of file diff --git a/fggl/gfx/ogl4/CMakeLists.txt b/fggl/gfx/ogl4/CMakeLists.txt new file mode 100644 index 0000000..b66df94 --- /dev/null +++ b/fggl/gfx/ogl4/CMakeLists.txt @@ -0,0 +1,6 @@ + +# Sources +target_sources(fggl + PRIVATE + canvas.cpp +) diff --git a/fggl/gfx/ogl4/canvas.cpp b/fggl/gfx/ogl4/canvas.cpp index 66f166f..36dcf09 100644 --- a/fggl/gfx/ogl4/canvas.cpp +++ b/fggl/gfx/ogl4/canvas.cpp @@ -22,18 +22,108 @@ #include "fggl/gfx/ogl4/canvas.hpp" #include "fggl/data/model.hpp" +#include "fggl/math/types.hpp" + +#include <glm/gtc/type_ptr.hpp> +#include "fggl/math/triangulation.hpp" #define FGGL_OPENGL_CORRECTNESS namespace fggl::gfx::ogl4 { + inline static void add_mesh_triangle(data::Mesh2D& mesh, const std::vector<data::Vertex2D>& verts) { + assert( verts.size() == 3); + for( const auto& vert : verts ) { + auto idx = mesh.add_vertex(vert); + mesh.add_index(idx); + } + } + static void convert_to_mesh(const gfx::Paint& paint, data::Mesh2D& mesh) { + for (const auto &cmd : paint.cmds()) { + auto path = cmd.path; + + std::vector<data::Vertex2D> verts; + math::vec3 colour{1.0F, 1.0F, 1.0F}; + auto idx = 0; + auto colourIdx = 0; + + for (auto &type : path.m_types) { + if (type == PathType::PATH) { + verts.push_back({.position = path.m_points[idx++], .colour = colour}); + } else if (type == PathType::MOVE) { + // polygon finished + if (verts.size() < 3) { + // empty, point, or line + // TODO deal with whatever I'm meant to do with this... + } else if (verts.size() == 3) { + // triangle + add_mesh_triangle(mesh, verts); + } else { + // polygon + math::fan_triangulation(verts, mesh); + } + + verts.clear(); + verts.push_back({.position = path.m_points[idx++], .colour = colour}); + } else if (type == PathType::COLOUR) { + colour = path.m_colours[colourIdx++]; + } else { + // unsupported type + } + } + + if (!verts.empty()) { + math::fan_triangulation(verts, mesh); + } + } } - void CanvasRenderer::render(const gfx::Paint &paint) { + CanvasRenderer::CanvasRenderer() { + m_vao.bind(); + + #ifdef FGGL_GL_I_BOUND + // user will handle binding themselves usually, so attribute won't bind itself. + // which means it's our problem right now... + GLuint originalVertexList; + ogl::bind_buffer( &originalVertexList, m_vertexList ); + #endif + + // define our attributes + auto posAttr = ogl::attribute<data::Vertex2D, math::vec2>(offsetof(data::Vertex2D, position)); + auto colAttr = ogl::attribute<data::Vertex2D, math::vec3>(offsetof(data::Vertex2D, colour)); + + // bind the attributes to the vao + m_vao.setAttribute(m_vertexList, 0, posAttr); + m_vao.setAttribute(m_vertexList, 1, colAttr); + + #ifdef FGGL_GL_I_BOUND + // cool, rebind whatever happened before, or not + ogl::unbind_buffer( &originalVertexList, m_vertexList ); + #endif + + glBindVertexArray(0); + } + + void CanvasRenderer::render(GLuint shader, const gfx::Paint &paint) { data::Mesh2D mesh; convert_to_mesh(paint, mesh); + // update data + m_vao.bind(); + m_vertexList.replace(mesh.vertexList.size(), mesh.vertexList.data()); + m_indexList.replace(mesh.indexList.size(), mesh.indexList.data()); + + // draw + + // FIXME: this should be abstracted into the shader class + glUseProgram( shader ); + auto projMat = glm::ortho(0.0f, 1920.0f, 1080.0f, 0.f); + glUniformMatrix4fv(glGetUniformLocation( shader, "projection"), 1, GL_FALSE, + glm::value_ptr(projMat)); + + m_vao.drawElements(m_indexList, ogl::Primative::TRIANGLE, mesh.indexList.size()); + glUseProgram( 0 ); } } \ No newline at end of file diff --git a/fggl/math/triangulation.cpp b/fggl/math/triangulation.cpp new file mode 100644 index 0000000..88d3d19 --- /dev/null +++ b/fggl/math/triangulation.cpp @@ -0,0 +1,48 @@ +/* + * ${license.title} + * Copyright (C) 2022 ${license.owner} + * ${license.mailto} + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "fggl/math/triangulation.hpp" + +namespace fggl::math { + + /** + * Fast Triangulation for convex polygons. + */ + void fan_triangulation(const PolygonVertex& polygon, data::Mesh2D &mesh) { + assert(polygon.size() >= 3); + + // add the first two points to the mesh + auto firstIdx = mesh.add_vertex(polygon[0]); + auto prevIdx = mesh.add_vertex(polygon[1]); + + // deal with the indices + const auto nTris = polygon.size() - 2; + for (auto i = 0; i < nTris; i++) { + mesh.add_index(firstIdx); + mesh.add_index(prevIdx); + + auto currIdx = mesh.add_vertex(polygon[i + 2]); + mesh.add_index(currIdx); + prevIdx = currIdx; + } + } + +} // namespace fggl::math + diff --git a/fggl/scenes/menu.cpp b/fggl/scenes/menu.cpp index 386dbf6..26b800a 100644 --- a/fggl/scenes/menu.cpp +++ b/fggl/scenes/menu.cpp @@ -28,7 +28,8 @@ namespace fggl::scenes { // in canvas space math::vec2 projected; projected.x = math::rescale_ndc(m_cursorPos.x, 0, 1920.f); - projected.y = math::rescale_ndc(m_cursorPos.y, 1080.0f, 0); + //projected.y = math::rescale_ndc(m_cursorPos.y, 1080.0f, 0); + projected.y = math::rescale_ndc(m_cursorPos.y, 0, 1080.0f); auto* hoverWidget = m_canvas.getChildAt(projected); if ( hoverWidget != m_hover ){ diff --git a/include/fggl/gfx/ogl/renderer.hpp b/include/fggl/gfx/ogl/renderer.hpp index 1f8a60f..24c0ab1 100644 --- a/include/fggl/gfx/ogl/renderer.hpp +++ b/include/fggl/gfx/ogl/renderer.hpp @@ -49,16 +49,18 @@ namespace fggl::gfx { explicit OpenGL4Backend(const Window &owner); ~OpenGL4Backend() override = default; + // copy bad + OpenGL4Backend(const OpenGL4Backend&) = delete; + OpenGL4Backend& operator=(const OpenGL4Backend&) = delete; + void clear() override; void resize(int width, int height) override; void draw2D(const Paint &paint) override; private: - ogl4::StaticModelRenderer m_modelRenderer; - ogl4::CanvasRenderer m_canvasRenderer; - - GlRenderToken m_token2D; + std::unique_ptr<ogl4::StaticModelRenderer> m_modelRenderer; + std::unique_ptr<ogl4::CanvasRenderer> m_canvasRenderer; std::unique_ptr<ShaderCache> m_cache; }; diff --git a/include/fggl/gfx/ogl/types.hpp b/include/fggl/gfx/ogl/types.hpp index 75917b1..45d8cf6 100644 --- a/include/fggl/gfx/ogl/types.hpp +++ b/include/fggl/gfx/ogl/types.hpp @@ -19,14 +19,16 @@ */ // -// Created by webpigeon on 17/04/22. +// uses RAII, with reference to https://www.khronos.org/opengl/wiki/Common_Mistakes#RAII_and_hidden_destructor_calls // #ifndef FGGL_GFX_OGL_TYPES_HPP #define FGGL_GFX_OGL_TYPES_HPP #include <cstdint> +#include <cassert> #include <string_view> +#include <iostream> #include "fggl/gfx/ogl/common.hpp" #include "fggl/math/types.hpp" @@ -61,30 +63,30 @@ namespace fggl::gfx::ogl { Location uniform(const std::string& name) const; // primatives - void setUniform(Location name, GLfloat value); - void setUniform(Location name, GLint value); - void setUniform(Location name, GLuint value); + void setUniformF(Location name, GLfloat value); + void setUniformI(Location name, GLint value); + void setUniformU(Location name, GLuint value); // vector versions (float) - void setUniform(Location name, math::vec2f value); - void setUniform(Location name, math::vec3f value); - void setUniform(Location name, math::vec4f value); - void setUniform(Location name, const math::vec2f* value, GLsizei size); - void setUniform(Location name, const math::vec3f* value, GLsizei size); - void setUniform(Location name, const math::vec4f* value, GLsizei size); + void setUniformF(Location name, math::vec2f value); + void setUniformF(Location name, math::vec3f value); + void setUniformF(Location name, math::vec4f value); + void setUniformF(Location name, const math::vec2f* value, GLsizei size); + void setUniformF(Location name, const math::vec3f* value, GLsizei size); + void setUniformF(Location name, const math::vec4f* value, GLsizei size); // vector versions (int) - void setUniform(Location name, math::vec2i value); - void setUniform(Location name, math::vec3i value); - void setUniform(Location name, math::vec4i value); - void setUniform(Location name, const math::vec2i* value, GLsizei size); - void setUniform(Location name, const math::vec3i* value, GLsizei size); - void setUniform(Location name, const math::vec4i* value, GLsizei size); + void setUniformI(Location name, math::vec2i value); + void setUniformI(Location name, math::vec3i value); + void setUniformI(Location name, math::vec4i value); + void setUniformI(Location name, const math::vec2i* value, GLsizei size); + void setUniformI(Location name, const math::vec3i* value, GLsizei size); + void setUniformI(Location name, const math::vec4i* value, GLsizei size); // matrix versions - void setUniform(Location name, const math::mat2*, GLsizei count); - void setUniform(Location name, const math::mat3*, GLsizei count); - void setUniform(Location name, const math::mat4*, GLsizei count); + void setUniformMtx(Location name, const math::mat2*, GLsizei count); + void setUniformMtx(Location name, const math::mat3*, GLsizei count); + void setUniformMtx(Location name, const math::mat4*, GLsizei count); }; enum class BuffAttrF { @@ -147,45 +149,176 @@ namespace fggl::gfx::ogl { STREAM_COPY = GL_STREAM_COPY, }; + template<BufType T> class Buffer { private: GLuint m_obj = 0; - void release(); + GLsizeiptr m_capacity = 0; + + /** + * Free an underlying buffer. + * + * If this buffer object is already empty, this is a no-op (and the OpenGL spec guarntees that freeing buffer + * 0 has no effect. + */ + void release() { + glDeleteBuffers(1, &m_obj); + m_obj = 0; + } public: + /** + * Create a new (unfilled) buffer object. + */ + Buffer() { + glGenBuffers(1, &m_obj); + } + + ~Buffer() { + release(); + } + // copy constructor bad Buffer(const Buffer&) = delete; Buffer& operator=(const Buffer&) = delete; - Buffer(Buffer&& other); - Buffer& operator=(Shader&& other); + Buffer(Buffer&& other) : m_obj(other.m_obj), m_capacity(other.m_capacity) { + other.obj_ = 0; + other.m_capacity = 0; + } + + Buffer& operator=(Buffer&& other) { + if ( this != &other) { + release(); + std::swap( m_obj, other.m_obj ); + std::swap( m_capacity, other.m_capacity ); + } + } + + void bind() const { + assert( m_obj != 0 ); + glBindBuffer( (GLenum)T, m_obj ); + } + + inline bool isValid() const { + return m_obj != 0; + }; + + void write(GLsizeiptr size, const GLvoid* data, BufUsage usage) { + bind(); + glBufferData( (GLenum)T, size, data, (GLenum)usage); + } + + void update(GLintptr offset, GLsizeiptr size, const void* data) { + + } + + template<typename D> + void replace(std::size_t size, D* data) { + bind(); + GLsizeiptr sizePtr = size * sizeof(D); + if ( sizePtr > m_capacity) { + glBufferData( (GLenum)T, sizePtr, data, GL_STREAM_DRAW ); + m_capacity = sizePtr; + } else { + glBufferSubData((GLenum)T, 0, sizePtr, data); + } + glBindBuffer( (GLenum)T, 0 ); + } - void bind(); + }; + + // common buffer types + using ArrayBuffer = Buffer<BufType::ARRAY>; + using ElementBuffer = Buffer<BufType::ELEMENT_ARRAY>; + + struct AttributeF { + BuffAttrF attrType; + GLint elmCount; + GLsizei stride; + std::size_t offset; + }; - void write(BufType target, GLsizeiptr size, const GLvoid* data, BufUsage usage); - void update(BufType target, GLintptr offset, GLsizeiptr size, const void* data); + struct AttributeI { + BuffAttrI attrType; + GLint elmCount; + GLsizei stride; + std::size_t offset; + }; - // NOTE: size must be between 1 - 4 - void setAttribute(GLuint idx, GLint size, BuffAttrF attr, bool normalized, GLsizei stride, std::size_t offset); - void setAttribute(GLuint idx, GLint size, BuffAttrI attr, GLsizei stride, std::size_t offset); - void setAttributeI(GLuint idx, GLint size, BuffAttrI attr, GLsizei stride, std::size_t offset); + // type intrincs to make interface nicer + template<typename T> + struct attr_type{ + const static BuffAttrF attr; + const static GLint size; }; + template<typename V, typename T> + AttributeF attribute(std::size_t offset) { + return AttributeF{ + .attrType = attr_type<T>::attr, + .elmCount = attr_type<T>::size, + .stride = sizeof(V), + .offset = offset + }; + } + + /** + * Represents an OpenGL vertex array object (VAO). + * + * This contains most information about an OpenGL state for supplying vertex data to the GPU. There is some basic + * debug checking to stop silly stuff happening, but this will be disabled in release mode. + */ class VertexArray { private: - GLuint obj_ = 0; - void Release(); + GLuint m_obj = 0; + void release(); public: - VertexArray(const Buffer&) = delete; + VertexArray(); + ~VertexArray(); + + // copy constructors bad + VertexArray(const VertexArray&) = delete; VertexArray& operator=(const VertexArray) = delete; - VertexArray(VertexArray&& other); + // move constructors might be ok + VertexArray(VertexArray&& other) noexcept; VertexArray& operator=(VertexArray&& other); - void bind(); + inline void bind() const { + assert( m_obj != 0); + glBindVertexArray( m_obj ); + } + + void setAttribute(const ArrayBuffer& buffer, GLuint idx, AttributeF& attr); + void setAttribute(const ArrayBuffer& buffer, GLuint idx, AttributeI& attr, bool normalized); + void setAttributeI(const ArrayBuffer& buffer, GLuint idx, AttributeI& attr); + + void drawElements(const ElementBuffer& buff, Primative drawType, std::size_t size); }; + // paranoid functions + void bind_vertex_array(GLuint& marker); + void unbind_vertex_array(GLuint& marker); + + template<BufType T> + void bind_buffer(GLuint* marker, const Buffer<T>& buff) { + #ifdef FGGL_GL_PARANOID + assert( marker != nullptr ); + glGetIntegerv( (GLenum)T, (GLint*) marker ); + #endif + buff.bind(); + } + + template<BufType T> + void unbind_buffer(GLuint* marker, const Buffer<T>& buff) { + #ifdef GL_FGGL_PARANOID + assert( marker != nullptr ); + glBindVertexArray(marker); + #endif + } + } // namespace fggl::gfx::ogl #endif //FGGL_GFX_OGL_TYPES_HPP diff --git a/include/fggl/gfx/ogl4/canvas.hpp b/include/fggl/gfx/ogl4/canvas.hpp index 2033068..8ace79c 100644 --- a/include/fggl/gfx/ogl4/canvas.hpp +++ b/include/fggl/gfx/ogl4/canvas.hpp @@ -5,17 +5,20 @@ #ifndef FGGL_GFX_OGL4_CANVAS_HPP #define FGGL_GFX_OGL4_CANVAS_HPP -#include <fggl/gfx/paint.hpp> - +#include "fggl/gfx/paint.hpp" +#include "fggl/gfx/ogl/types.hpp" namespace fggl::gfx::ogl4 { class CanvasRenderer { public: - CanvasRenderer() = default; - void render(const gfx::Paint& paint); + CanvasRenderer(); + void render(GLuint shader, const gfx::Paint& paint); private: + ogl::VertexArray m_vao; + ogl::Buffer<ogl::BufType::ARRAY> m_vertexList; + ogl::Buffer<ogl::BufType::ELEMENT_ARRAY> m_indexList; }; } // namespace fggl::gfx::ogl4 diff --git a/include/fggl/math/triangulation.hpp b/include/fggl/math/triangulation.hpp index 11578c8..a62860a 100644 --- a/include/fggl/math/triangulation.hpp +++ b/include/fggl/math/triangulation.hpp @@ -1,5 +1,5 @@ -#ifndef FGGL_MATH_TRIS_H -#define FGGL_MATH_TRIS_H +#ifndef FGGL_MATH_TRIANGULATION_HPP +#define FGGL_MATH_TRIANGULATION_HPP #include <fggl/math/types.hpp> #include <fggl/data/model.hpp> @@ -48,7 +48,7 @@ namespace fggl::math { * * see https://math.stackexchange.com/a/1745427 */ - bool isConvex(const Polygon &polygon) { + static bool isConvex(const Polygon &polygon) { if (polygon.size() < 3) { return false; } @@ -119,24 +119,7 @@ namespace fggl::math { /** * Fast Triangulation for convex polygons. */ - void fanTriangulation(const PolygonVertex& polygon, data::Mesh2D &mesh) { - assert(polygon.size() >= 3); - - // add the first two points to the mesh - auto firstIdx = mesh.add_vertex(polygon[0]); - auto prevIdx = mesh.add_vertex(polygon[1]); - - // deal with the indices - const auto nTris = polygon.size() - 2; - for (auto i = 0; i < nTris; i++) { - mesh.add_index(firstIdx); - mesh.add_index(prevIdx); - - auto currIdx = mesh.add_vertex(polygon[i + 2]); - mesh.add_index(currIdx); - prevIdx = currIdx; - } - } + void fan_triangulation(const PolygonVertex& polygon, data::Mesh2D &mesh); } // namespace fggl::util -- GitLab