- 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
This commit is contained in:
ohsqueezy 2023-06-02 14:54:06 -04:00
parent 9ed0e9ea71
commit 2f7a4cb602
8 changed files with 174 additions and 74 deletions

View File

@ -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<GLvoid*>(_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

View File

@ -131,6 +131,7 @@ namespace sb
std::vector<glm::bvec4>, std::vector<glm::uvec4>, std::vector<glm::ivec4>, std::vector<glm::vec4>>;
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;

View File

@ -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

View File

@ -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<sb::Attributes> position = std::make_shared<sb::Attributes>(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<sb::Attributes> uv = std::make_shared<sb::Attributes>(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<sb::Attributes> color = std::make_shared<sb::Attributes>(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}

View File

@ -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<GLvoid*>(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;
}

View File

@ -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&);
};

View File

@ -1,3 +1,13 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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<float>();
}
std::vector<glm::vec2> sb::bezier(const std::vector<glm::vec2> control, int resolution)
{
std::vector<glm::vec2> 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;
}

View File

@ -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 <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| 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<float>(), c = glm::half_pi<float>(), d = 0.5f, e = glm::pi<float>() * 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 <vector>
/* GLM */
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
@ -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<glm::vec2> bezier(const std::vector<glm::vec2> vertices, int resolution = 30);
}