![]() |
CUGL 3.0
Cornell University Game Library
|
#include <CUInstanceBuffer.h>
Public Member Functions | |
InstanceBuffer () | |
~InstanceBuffer () | |
void | dispose () override |
bool | init (GLsizei size, GLsizei stride) override |
bool | init (GLsizei tsize, GLsizei tstride, GLsizei isize, GLsizei istride) |
void | attach (const std::shared_ptr< Shader > &shader) override |
GLsizei | getInstanceCapacity () const |
GLsizei | getInstanceStride () const |
void | loadInstanceData (const void *data, GLsizei size, GLenum usage=GL_STREAM_DRAW) |
void | drawInstanced (GLenum mode, GLsizei count, GLsizei instances, GLint offset=0) |
void | drawInstancedDirect (GLenum mode, GLint first, GLsizei count, GLsizei instances) |
void | setupInstanceAttribute (const std::string name, GLint size, GLenum type, GLboolean norm, GLsizei offset) |
![]() | |
VertexBuffer () | |
~VertexBuffer () | |
virtual void | dispose () |
virtual bool | init (GLsizei size, GLsizei stride) |
void | bind () |
void | unbind () |
virtual void | attach (const std::shared_ptr< Shader > &shader) |
std::shared_ptr< Shader > | detach () |
std::shared_ptr< Shader > | getShader () const |
bool | isBound () const |
GLsizei | getCapacity () const |
GLsizei | getStride () const |
void | loadVertexData (const void *data, GLsizei size, GLenum usage=GL_STREAM_DRAW) |
void | loadIndexData (const void *data, GLsizei size, GLenum usage=GL_STREAM_DRAW) |
void | draw (GLenum mode, GLsizei count, GLint offset=0) |
void | drawDirect (GLenum mode, GLint first, GLsizei count) |
virtual void | setupAttribute (const std::string name, GLint size, GLenum type, GLboolean norm, GLsizei offset) |
void | enableAttribute (const std::string name) |
void | disableAttribute (const std::string name) |
Static Public Member Functions | |
static std::shared_ptr< InstanceBuffer > | alloc (GLsizei size, GLsizei stride) |
static std::shared_ptr< InstanceBuffer > | alloc (GLsizei tsize, GLsizei tstride, GLsizei isize, GLsizei istride) |
![]() | |
static std::shared_ptr< VertexBuffer > | alloc (GLsizei size, GLsizei stride) |
Protected Attributes | |
GLsizei | _instanceSize |
GLsizei | _instanceStride |
GLuint | _instanceBuffer |
std::unordered_map< std::string, AttribData > | _instAttribs |
![]() | |
GLsizei | _size |
GLsizei | _stride |
GLuint | _vertArray |
GLuint | _vertBuffer |
GLuint | _indxBuffer |
std::shared_ptr< Shader > | _shader |
std::unordered_map< std::string, bool > | _enabled |
std::unordered_map< std::string, AttribData > | _attributes |
This class defines a vertex buffer for drawing instanced shapes.
This class is an alternative to VertexBuffer
for those cases in which you need to instance a simple mesh (e.g. particle systems). It separates the buffer data into two groups: the template and the instance data. The template is the mesh data repeated every instance. The instance data is the unique data for each instance. By design, template data is designed to be static, while instance data is designed to be streamed.
The template mesh uses these methods inherited from VertexBuffer
. Indeed, if you restrict yourself to only the inherited methods, this class behaves exactly like VertexBuffer
. Instancing is provided by the new methods.
For simplicity, we do not support instance depths (e.g glVertexAttribDivisor) greater than 1. If you need that level of control, you should create your own abstraction.
A instance buffer must be attached to a shader to be used. However, an instance buffer can swap shaders at any time, which is why this class is separated out. Unlike Texture
and UniformBuffer
, an instance buffer does not have a true many one relationship with a Shader
object. An instance buffer can only be connected to one shader at a time and vice versa. So we model this as a direct connection. As instance buffers push data to a shader, the dependency requires that a shader be linked to an instance buffer object.
This class tries to remain loosely coupled with its shader. If the instance buffer has attributes lacking in the shader, they will be ignored. If it is missing attributes that the shader expects, the shader will use the default value for the type.
As with VertexBuffer
, we allow the mesh data to be indexed, though that is not required. The index data is applied to the template, not the instance data.
|
inline |
Creates an uninitialized instance buffer.
You must initialize the instance buffer to allocate buffer memory.
|
inline |
Deletes this instance buffer, disposing all resources.
|
inlinestatic |
Returns a new instance buffer to support the given strides.
The stride is the size of a single piece of vertex data. The instance buffer needs this value to set attribute locations for both the template and the instance buffers. In this initializer, these are assumed to be the same value.
Since changing these values fundamentally changes the type of data that can be sent to this instance buffer, they are set at buffer creation and cannot be changed. It is possible for a stride to be 0, but only if that layer consists of a single attribute. Using stride 0 is not recommended.
For performance reasons, we also require that the instance buffer specify a maximum size. This size is applied to everything: vertex, index, and instance data. So it should be the maximum of all of them. Size is specified in terms of maximum elements, not bytes.
size | The maximum number of elements in this buffer |
stride | The size of a single piece of data (template or instance) |
|
inlinestatic |
Returns a new instance buffer to support the given strides.
The stride is the size of a single piece of vertex data. The instance buffer needs this value to set attribute locations for both the template and the instance buffers. Note that these values do not have to be the same as these buffers are separate.
Since changing these values fundamentally changes the type of data that can be sent to this instance buffer, they are set at buffer creation and cannot be changed. It is possible for a stride to be 0, but only if that layer consists of a single attribute. Using stride 0 is not recommended.
For performance reasons, we also require that the instance buffer specify a maximum size. The template size is applied both the template vertices and the indices. So it should be the maximum of both. Size is specified in terms of maximum elements, not bytes.
tsize | The maximum number of elements in the template later |
tstride | The size of a single piece of data in the template layer |
isize | The maximum number of elements in the instance later |
istride | The size of a single piece of data in the instance layer |
|
overridevirtual |
Attaches the given shader to this instance buffer.
This method will link all enabled attributes in this instance buffer (warning about any attributes that are missing from the shader). It will also immediately bind both the instance buffer and the shader, making them ready to use.
shader | The shader to attach |
Reimplemented from cugl::graphics::VertexBuffer.
|
overridevirtual |
Deletes the instance buffer, freeing all resources.
You must reinitialize the instance buffer to use it.
Reimplemented from cugl::graphics::VertexBuffer.
void cugl::graphics::InstanceBuffer::drawInstanced | ( | GLenum | mode, |
GLsizei | count, | ||
GLsizei | instances, | ||
GLint | offset = 0 |
||
) |
Draws to the active framebuffer using this instance buffer
This draw command will instance the mesh defined by both the vertex and index data. The count parameter determines the number of indices to use in the base mesh, while the instances parameter determines the number of indices. The optional paramter offset is for the offset into the indices, not the instances.
Any call to this command will use the current texture and uniforms. If the texture and/or uniforms need to be changed, then this draw command will need to be broken up into chunks. Use the optional parameter offset to chunk up the draw calls without having to reload data.
The drawing mode can be any of GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN or GL_TRIANGLES. These are the only modes accepted by both OpenGL and OpenGLES. See the OpenGL documentation for the number of indices required for each type. In practice the Poly2
class is designed to support GL_POINTS, GL_LINES, and GL_TRIANGLES only.
This method will only succeed if this buffer is actively bound.
mode | The OpenGLES drawing mode |
count | The number of vertices in the base mesh |
instances | The number of mesh instances |
offset | The initial index to start the mesh |
void cugl::graphics::InstanceBuffer::drawInstancedDirect | ( | GLenum | mode, |
GLint | first, | ||
GLsizei | count, | ||
GLsizei | instances | ||
) |
Draws to the active framebuffer using this instance buffer
This draw command will instance the mesh defined in the vertex buffer the given number of times. In defining the mesh, it will bypass the index buffer, and draw the vertices in order starting from the first specified vertex.
Any call to this command will use the current texture and uniforms. If the texture and/or uniforms need to be changed, then this draw command will need to be broken up into chunks. Use the initial offset parameter to chunk up the draw calls without having to reload data.
The drawing mode can be any of GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN or GL_TRIANGLES. These are the only modes accepted by both OpenGL and OpenGLES. See the OpenGL documentation for the number of indices required for each type. In practice the Poly2
class is designed to support GL_POINTS, GL_LINES, and GL_TRIANGLES only.
This method will only succeed if this buffer is actively bound.
mode | The OpenGLES drawing mode |
first | The initial vertex in the base mesh |
count | The number of vertices in the base mesh |
instances | The number of mesh instances |
|
inline |
Returns the maximum capacity of the instance layer.
The size determines the number of elements that can be loaded with loadInstanceData
.
|
inline |
Returns the stride of the instance layer.
The data loaded into the instance layer is expected to have the size of this stride. If it does not, strange things will happen.
|
inlineoverridevirtual |
Initializes this instance buffer to support the given stride
The stride is the size of a single piece of vertex data. The instance buffer needs this value to set attribute locations for both the template and the instance buffers. In this initializer, these are assumed to be the same value.
Since changing these values fundamentally changes the type of data that can be sent to this instance buffer, they are set at buffer creation and cannot be changed. It is possible for a stride to be 0, but only if that layer consists of a single attribute. Using stride 0 is not recommended.
For performance reasons, we also require that the instance buffer specify a maximum size. This size is applied to everything: vertex, index, and instance data. So it should be the maximum of all of them. Size is specified in terms of maximum elements, not bytes.
size | The maximum number of elements in this buffer |
stride | The size of a single piece of data (template or instance) |
Reimplemented from cugl::graphics::VertexBuffer.
bool cugl::graphics::InstanceBuffer::init | ( | GLsizei | tsize, |
GLsizei | tstride, | ||
GLsizei | isize, | ||
GLsizei | istride | ||
) |
Initializes this instance buffer to support the given strides
The stride is the size of a single piece of vertex data. The instance buffer needs this value to set attribute locations for both the template and the instance buffers. Note that these values do not have to be the same as these buffers are separate.
Since changing these values fundamentally changes the type of data that can be sent to this instance buffer, they are set at buffer creation and cannot be changed. It is possible for a stride to be 0, but only if that layer consists of a single attribute. Using stride 0 is not recommended.
For performance reasons, we also require that the instance buffer specify a maximum size. The template size is applied both the template vertices and the indices. So it should be the maximum of both. Size is specified in terms of maximum elements, not bytes.
tsize | The maximum number of elements in the template later |
tstride | The size of a single piece of data in the template layer |
isize | The maximum number of elements in the instance later |
istride | The size of a single piece of data in the instance layer |
void cugl::graphics::InstanceBuffer::loadInstanceData | ( | const void * | data, |
GLsizei | size, | ||
GLenum | usage = GL_STREAM_DRAW |
||
) |
Loads the given instance buffer with data.
The data loaded is the data that will be used at the next call to either drawInstanced
or drawInstancedDirect
. It will be combined with the vertex/index data the render the final image.
The data loaded is expected to have the size of the instance buffer stride. If it does not, strange things will happen.
The usage is one of GL_STATIC_DRAW, GL_STREAM_DRAW, or GL_DYNAMIC_DRAW. Static drawing should be reserved for vertices and/or indices that do not change (so all animation happens in uniforms). Instance data is typically streaming (as is with the case of particle systems), so it is generally best to choose GL_STREAM_DRAW.
This method will only succeed if this buffer is actively bound.
data | The data to load |
size | The number of instances to load |
usage | The type of data load |
void cugl::graphics::InstanceBuffer::setupInstanceAttribute | ( | const std::string | name, |
GLint | size, | ||
GLenum | type, | ||
GLboolean | norm, | ||
GLsizei | offset | ||
) |
Initializes an instance attribute, assigning is a size, type and offset.
This method is necessary for the instance buffer to convey data to the shader. Without it, the shader will used default values for the attribute rather than data from the instance buffer.
It is safe to call this method even when the shader is not attached. The values will be cached and will be used to link this buffer to the shader when the shader is attached. This also means that a instance buffer can swap shaders without having to reinitialize attributes. If a shader is attached, the attribute will be enabled immediately.
If the attribute does not refer to one supported by the active shader, then it will be ignored (e.g. the effect is the same as disabling the attribute).
The attribute type can be one of GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_HALF_FLOAT, GL_FLOAT, GL_FIXED, or GL_INT_2_10_10_10_REV. Doubles are not supported by OpenGLES.
The attribute offset is measured in bytes from the start of the instance data structure (for a single instance).
name | The attribute name |
size | The attribute size in byte. |
type | The attribute type |
norm | Whether to normalize the value (floating point only) |
offset | The attribute offset in the vertex data structure |
|
protected |
The buffer for the instance data
|
protected |
The maximums size of the instance layer
|
protected |
The data stride of the instance layer (0 if there is only one attribute)
|
protected |
The instance attributes