From 2f7a4cb602cc37186390c3f8e2af44bbc6e1b03c Mon Sep 17 00:00:00 2001 From: frank Date: Fri, 2 Jun 2023 14:54:06 -0400 Subject: [PATCH] - attributes objects track their offset in the VBO - call to glVertexAttribPointer moved from VBO class to Attributes class - added a public domain function for computing bezier points --- src/Attributes.cpp | 38 ++++++++++---------------- src/Attributes.hpp | 35 ++++++++++++++++++++++-- src/Model.cpp | 2 +- src/Model.hpp | 5 ++++ src/VBO.cpp | 23 +++------------- src/VBO.hpp | 15 ++++++++++ src/math.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++ src/math.hpp | 68 +++++++++++++++++++++++++++------------------- 8 files changed, 174 insertions(+), 74 deletions(-) diff --git a/src/Attributes.cpp b/src/Attributes.cpp index 35f402b..4ebfbb4 100644 --- a/src/Attributes.cpp +++ b/src/Attributes.cpp @@ -39,6 +39,11 @@ GLint sb::Attributes::index() const return attribute_index; } +void sb::Attributes::offset(GLintptr offset) +{ + _offset = offset; +} + /* Returns the count of attributes */ std::size_t sb::Attributes::count() const { @@ -55,18 +60,6 @@ std::size_t sb::Attributes::count() const }, vertices); } -/* Enable the attributes in the VAO. */ -void sb::Attributes::enable() const -{ - glEnableVertexAttribArray(*this); -} - -/* Disable the attributes in the VAO. */ -void sb::Attributes::disable() const -{ - glDisableVertexAttribArray(*this); -} - /* Returns the size in bytes of the object's underlying vector of vertices. This can be passed to OpenGL * along with the memory pointer when copying vertices to the GPU. */ std::size_t sb::Attributes::size() const @@ -84,23 +77,20 @@ std::size_t sb::Attributes::size() const }, vertices); } -/* Set the index to the location of attributes with given name in a shader program. The program - * must already be linked to get the location. */ -void sb::Attributes::bind(GLuint program, const std::string& name) +void sb::Attributes::bind(const std::string& name, GLuint program) { index(glGetAttribLocation(program, name.c_str())); - std::ostringstream message; - message << "index for " << name << " is " << index(); - sb::Log::log(message, sb::Log::DEBUG); + glVertexAttribPointer(index(), dimensions(), type(), normalized(), 0, reinterpret_cast(_offset)); } -/* Set the index and bind it to the given name in a shader program. This should be called before - * the shader program is linked, otherwise the name will already have been assigned a location - * index by GL. */ -void sb::Attributes::bind(std::uint32_t index, GLuint program, const std::string& name) +void sb::Attributes::enable() const { - glBindAttribLocation(program, index, name.c_str()); - this->index(index); + glEnableVertexAttribArray(*this); +} + +void sb::Attributes::disable() const +{ + glDisableVertexAttribArray(*this); } /* Return the GLenum that corresponds to the type of scalar being held in the vertices. This diff --git a/src/Attributes.hpp b/src/Attributes.hpp index aee20cb..9748c9c 100644 --- a/src/Attributes.hpp +++ b/src/Attributes.hpp @@ -131,6 +131,7 @@ namespace sb std::vector, std::vector, std::vector, std::vector>; Vertices vertices; GLint attribute_index = 0; + GLintptr _offset = 0; public: @@ -272,10 +273,40 @@ namespace sb void extend(const Attributes&, std::size_t = 1); void index(GLint); GLint index() const; - void bind(GLuint, const std::string&); - void bind(std::uint32_t, GLuint, const std::string&); + + /*! + * Set the byte offset into the VBO where this object's vertex data is stored. This can be set by passing this object to + * `VBO::add`. + * + * @param offset byte offset in the VBO where this object's vertex data is stored + */ + void offset(GLintptr offset); + + /*! + * Get the index of the uniform with the given name, store it as this object's index, and create a pointer to these + * attributes in the VAO using this object's offset value. + * + * The offset should have been previously set by a call to `VBO::add` or some equivalent in manual GL calls. The program + * must already be linked to get the location. + * + * @param name uniform name + * @param program GLSL program, created with glCreateProgram + */ + void bind(const std::string& name, GLuint program); + + /*! + * Enable the attributes in the VAO associated with this object's index. `Attributes::bind` must have been called previously, + * unless the index has been set up manually with direct calls to GL. + * + * The object's current index is used refer to the pointer. + */ void enable() const; + + /*! + * Disable the attributes in the VAO associated with this object's index. + */ void disable() const; + std::size_t size() const; std::size_t count() const; GLenum type() const; diff --git a/src/Model.cpp b/src/Model.cpp index 4dddeca..54b89b0 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -122,7 +122,7 @@ sb::Texture& sb::Model::texture(const std::string& name) else if (textures().find(name) == textures().end()) { std::ostringstream message; - message << "No texture named " << name << " attached to this model."; + message << "No texture named " << name << " found attached to this model."; throw std::out_of_range(message.str()); } else diff --git a/src/Model.hpp b/src/Model.hpp index b74c28c..ce27f9e 100644 --- a/src/Model.hpp +++ b/src/Model.hpp @@ -130,14 +130,19 @@ namespace sb public: + /* A plane in the X and Y dimensions, from (-1.0, -1.0) to (1.0, 1.0) */ inline const static std::shared_ptr position = std::make_shared(sb::Attributes{ {-1.0f, 1.0f}, {1.0f, 1.0f}, {-1.0f, -1.0f}, {1.0f, 1.0f}, {1.0f, -1.0f}, {-1.0f, -1.0f} }); + + /* Map a texture to fill the plane */ inline const static std::shared_ptr uv = std::make_shared(sb::Attributes{ {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f} }); + + /* A gradient from magenta to yellow */ inline const static std::shared_ptr color = std::make_shared(sb::Attributes{ {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, {0.8f, 0.0f, 0.3f}, {1.0f, 1.0f, 0.0f}, {0.8f, 0.0f, 0.3f}, {0.8f, 0.0f, 0.3f} diff --git a/src/VBO.cpp b/src/VBO.cpp index 8a890ab..92b2a6f 100644 --- a/src/VBO.cpp +++ b/src/VBO.cpp @@ -29,33 +29,18 @@ void VBO::allocate(GLsizeiptr size, GLenum usage) sb::Log::gl_errors(message.str()); } -/* Set memory in the GPU buffer to the values of the attribute data using glBufferSubData. The memory - * set is a contiguous area from the object's current byte offset value to the offset plus the size in - * bytes of the attributes. After the memory is set, the offset is updated to point to the end of the - * area. - * - * Define an array of vertex attribute data on the GPU by passing the attributes's index, dimensions, - * normalization state, and type to glVertexAttribPointer, along with the buffer object's current - * offset. - * - * The updated offset is returned and can be used to independently keep track of where the next - * attributes will be stored in the buffer and apply to direct usage of glBufferSubData. */ GLintptr VBO::add(sb::Attributes& attributes) { /* Set memory */ glBufferSubData(target(), offset, attributes.size(), attributes); + attributes.offset(offset); + /* Debug */ std::ostringstream initialization_message; initialization_message << "After setting " << attributes.size() << "bytes in " << *this; sb::Log::gl_errors(initialization_message.str()); - /* Define array */ - glVertexAttribPointer( - attributes.index(), attributes.dimensions(), attributes.type(), attributes.normalized(), 0, reinterpret_cast(offset)); - /* Debug */ - std::ostringstream pointer_message; - pointer_message << "After defining pointer for " << attributes; - sb::Log::gl_errors(pointer_message.str()); - /* Increase offset */ + + /* Increase offset and return */ offset += attributes.size(); return offset; } diff --git a/src/VBO.hpp b/src/VBO.hpp index c1cfccd..1918c9c 100644 --- a/src/VBO.hpp +++ b/src/VBO.hpp @@ -51,7 +51,22 @@ namespace sb VBO(); void allocate(GLsizeiptr, GLenum); + + /*! + * Set memory in the GPU buffer to the values of the attribute data using glBufferSubData. The memory + * is a contiguous area from the object's current byte offset value to the offset plus the size in + * bytes of the attributes. After the memory is set, the offset is updated to point to the end of the + * area. + * + * The offset is stored in the sb::Attributes object, so the object can associate the vertex data with + * the VAO by passing the offset along when it calls glVertexAttribPointer in its sb::Attributes::bind + * method. + * + * @param attributes vertices to be added to the vertex buffer, wrapped in a sb::Attributes object + * @return the new offset that indicates the end of the vertex buffer + */ GLintptr add(sb::Attributes&); + friend std::ostream& operator<<(std::ostream&, const VBO&); }; diff --git a/src/math.cpp b/src/math.cpp index c981af7..40093dc 100644 --- a/src/math.cpp +++ b/src/math.cpp @@ -1,3 +1,13 @@ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + #include "math.hpp" glm::vec2 sb::velocity_to_delta(float angle, float magnitude) @@ -24,3 +34,55 @@ float sb::angle_ratio(float start, float end) { return sb::angle_difference(start, end) / glm::pi(); } + +std::vector sb::bezier(const std::vector control, int resolution) +{ + std::vector points; + points.reserve(resolution); + + float b0x = control[0][0]; + float b0y = control[0][1]; + float b1x = control[1][0]; + float b1y = control[1][1]; + float b2x = control[2][0]; + float b2y = control[2][1]; + float b3x = control[3][0]; + float b3y = control[3][1]; + + float ax = -b0x + 3.0f * b1x + -3.0f * b2x + b3x; + float ay = -b0y + 3.0f * b1y + -3.0f * b2y + b3y; + float bx = 3.0f * b0x + -6.0f * b1x + 3.0f * b2x; + float by = 3.0f * b0y + -6.0f * b1y + 3.0f * b2y; + float cx = -3.0f * b0x + 3.0f * b1x; + float cy = -3.0f * b0y + 3.0f * b1y; + float dx = b0x; + float dy = b0y; + + float steps = resolution - 1; + float h = 1.0f / steps; + + float pointX = dx; + float pointY = dy; + + float firstFDX = ax * std::pow(h, 3.0f) + bx * std::pow(h, 2.0f) + cx * h; + float firstFDY = ay * std::pow(h, 3.0f) + by * std::pow(h, 2.0f) + cy * h; + float secondFDX = 6 * ax * std::pow(h, 3.0f) + 2 * bx * std::pow(h, 2.0f); + float secondFDY = 6 * ay * std::pow(h, 3.0f) + 2 * by * std::pow(h, 2.0f); + float thirdFDX = 6 * ax * std::pow(h, 3.0f); + float thirdFDY = 6 * ay * std::pow(h, 3.0f); + + points.push_back({pointX, pointY}); + + for (int ii = 0; ii < steps; ii++) + { + pointX += firstFDX; + pointY += firstFDY; + firstFDX += secondFDX; + firstFDY += secondFDY; + secondFDX += thirdFDX; + secondFDY += thirdFDY; + points.push_back({pointX, pointY}); + } + + return points; +} diff --git a/src/math.hpp b/src/math.hpp index 04a774a..7f34d5f 100644 --- a/src/math.hpp +++ b/src/math.hpp @@ -1,46 +1,46 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [https://shampoo.ooo] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +--------------+ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++--------------+ - [math.hpp] +[math.hpp] - For math helper functions that require only GLM primitives, especially trigonometric functions. - Angle values are in radians. 0 is directly up on the screen in GL coordinates, and the angle increases - clockwise. +For math helper functions that require only GLM primitives, especially trigonometric functions. +Angle values are in radians. 0 is directly up on the screen in GL coordinates, and the angle increases +clockwise. - This test of points on a square and one point below the square should print the output below it: +This test of points on a square and one point below the square should print the output below. glm::vec2 a {5.0f, 5.0f}, b {1.0f, 1.0f}, c {1.0f, 5.0f}, d {5.0f, 1.0f}, e {5.0f, -1.0f}; std::cout << glm::degrees(sb::angle_between(a, b)) << " " << glm::degrees(sb::angle_between(b, a)) << " " << - glm::degrees(sb::angle_between(a, c)) << " " << glm::degrees(sb::angle_between(c, a)) << " " << - glm::degrees(sb::angle_between(b, e)) << " " << glm::degrees(sb::angle_between(e, b)) << std::endl << - sb::velocity_to_delta(sb::angle_between(a, b), 4.0f * glm::sqrt(2.0f)) << " " << - sb::velocity_to_delta(sb::angle_between(b, a), 4.0f * glm::sqrt(2.0f)) << " " << - sb::velocity_to_delta(sb::angle_between(d, a), 4.0f) << " " << - sb::velocity_to_delta(sb::angle_between(b, e), 1.0f) << std::endl; + glm::degrees(sb::angle_between(a, c)) << " " << glm::degrees(sb::angle_between(c, a)) << " " << + glm::degrees(sb::angle_between(b, e)) << " " << glm::degrees(sb::angle_between(e, b)) << std::endl << + sb::velocity_to_delta(sb::angle_between(a, b), 4.0f * glm::sqrt(2.0f)) << " " << + sb::velocity_to_delta(sb::angle_between(b, a), 4.0f * glm::sqrt(2.0f)) << " " << + sb::velocity_to_delta(sb::angle_between(d, a), 4.0f) << " " << + sb::velocity_to_delta(sb::angle_between(b, e), 1.0f) << std::endl; - Should print: +Should print, -135 45 -90 90 116.565 -63.435 {-4, -4} {4, 4} {0, 4} {0.894427, -0.447214} - This test of angle differences should print the output below it: +This test of angle differences should print the output below. float a = 0.0f, b = glm::pi(), c = glm::half_pi(), d = 0.5f, e = glm::pi() * 4; std::cout << sb::angle_difference(a, b) << " " << sb::angle_difference(a, c) << " " << sb::angle_difference(b, c) << " " << - sb::angle_difference(a, d) << " " << sb::angle_difference(c, d) << " " << sb::angle_difference(a, e) << " " << - sb::angle_difference(c, e) << " " << sb::angle_difference(d, e) << " " << sb::angle_difference(c, c) << std::endl << - sb::angle_ratio(a, b) << " " << sb::angle_ratio(a, c) << " " << sb::angle_ratio(b, c) << " " << sb::angle_ratio(a, d) << " " << - sb::angle_ratio(c, d) << " " << sb::angle_ratio(a, e) << " " << sb::angle_ratio(c, e) << " " << sb::angle_ratio(d, e) << " " << - sb::angle_ratio(c, c) << std::endl; + sb::angle_difference(a, d) << " " << sb::angle_difference(c, d) << " " << sb::angle_difference(a, e) << " " << + sb::angle_difference(c, e) << " " << sb::angle_difference(d, e) << " " << sb::angle_difference(c, c) << std::endl << + sb::angle_ratio(a, b) << " " << sb::angle_ratio(a, c) << " " << sb::angle_ratio(b, c) << " " << sb::angle_ratio(a, d) << " " << + sb::angle_ratio(c, d) << " " << sb::angle_ratio(a, e) << " " << sb::angle_ratio(c, e) << " " << sb::angle_ratio(d, e) << " " << + sb::angle_ratio(c, c) << std::endl; - Should print: +Should print, -3.14159 1.5708 -1.5708 0.5 -1.0708 3.49691e-07 -1.5708 -0.5 0 -1 0.5 -0.5 0.159155 -0.340845 1.1131e-07 -0.5 -0.159155 0 @@ -48,6 +48,8 @@ #pragma once +#include + /* GLM */ #define GLM_ENABLE_EXPERIMENTAL #include @@ -101,4 +103,14 @@ namespace sb * turn it is. */ float angle_ratio(float start, float end); + + /*! + * Calculate a 2D bezier curve from four 2D control points. + * + * Adapted from public domain released code, 2007 Victor Blomqvist, originally at https://www.pygame.org/wiki/BezierCurve. + * + * @param vertices four 2D control points + * @param resolution number of points that will be in the computed curve + */ + std::vector bezier(const std::vector vertices, int resolution = 30); }