Unofficial OpenGL Software Development Kit
0.5.0
|
API for immediate mode-style rendering.
It is often useful to send vertex data for objects on the fly. Immediate mode in OpenGL was the original way to do this, but OpenGL 3.1 core and above removed that.
These classes provide a means for having functionality similar to immediate mode.
Before rendering can begin, some setup work needs to be done. Core OpenGL 3.1 and above can only render from buffer objects. Therefore, a buffer object must be used.
This is provided by the StreamBuffer class. It provides an interface for sequentially adding vertex data to a buffer. It can invalidate the buffer automatically if there is not enough room left in the buffer to write a particular set of vertex data.
The next setup is to declare a format for the vertex data. Unlike the original immediate mode, this drawing API requires an explicit format for vertex data. This is provided by the VertexFormat class, which defines a series of vertex attributes.
These two classes are used by the glmesh::Draw class. The Draw class is what provides the actual drawing API. It uses a StreamBuffer to stream its data into, and it expects a specific VertexFormat for its vertex data.
You can use immediate mode drawing just to fill a buffer object with data, rather than actually rendering with it. This is done by using CpuDataWriter to write the data to system memory. After writing as much as you like, you call CpuDataWriter::TransferToBuffer to transfer the data to a buffer object. From there, you can bind the buffer to GL_ARRAY_BUFFER
and use the VertexFormat::BindAttributes to fill a VAO and render with it. You can even put data from multiple meshes in the same buffer (so long as they use the same vertex format).
Note that the OpenGL immediate mode API allows you to put as many vertices in as you want, and only checks for errors when you call glEnd
. The glmesh::Draw API is more strict: you must specify how many vertices you want up front, and if you try to provide too many attributes, an exception is thrown. CpuDataWriter is more lenient (since it is writing to arbitrary CPU memory storage); you can provide a guesstimate of the number of vertices, but it will expand that as needed.
Also, the old OpenGL immediate mode has the concept of constant data; you did not have to set every attribute for each vertex. This drawing API is more restrictive; you must set each attribute for each vertex. And each attribute must be provided in the order specified by the VertexFormat.
Here is an example of how to use the API:
If you are inclined to use Boost directly, a Boost.Fusion-capable function exists which is compatible with any glmesh::VertexWriter-based class (such as glmesh::Draw). It takes a Boost.Tuple or other Fusion-compatible sequence type and writes each attribute in order. This allows you to use arbitrary structs directly, rather than having to write each vertex's attributes in order.
This function, glmesh::Attrib, has example code in its documentation.
Classes | |
class | glmesh::CpuDataWriter |
Allows immediate mode drawing to a CPU buffer, rather than a buffer object. More... | |
class | glmesh::Draw |
RAII-style class for immediate-mode type rendering through a VertexFormat and StreamBuffer. More... | |
class | glmesh::StreamBuffer |
A class for streaming vertex data to buffer objects on the GPU. More... | |
class | glmesh::StreamBuffer::Map |
A RAII-style class for mapping a StreamBuffer. More... | |
class | glmesh::AttribDesc |
Describes the storage for a single vertex attribute. More... | |
struct | glmesh::SeparateAttribFormatTag |
Used in VertexFormat::Enable to differentiate constructors. More... | |
class | glmesh::VertexFormat |
Describes the layout for a sequence of vertex attributes, to be used for rendering. More... | |
class | glmesh::VertexFormat::Enable |
RAII-style class for binding a VertexFormat to the OpenGL context. More... | |
class | glmesh::VertexWriter< Sink > |
Base class, using CRTP, that provides a framework for writing vertex attributes to arbitrary locations. More... | |
Typedefs | |
typedef std::vector< AttribDesc > | glmesh::AttributeList |
Convenience typedef for std::vector's of attributes. | |
Enumerations | |
enum | glmesh::VertexDataType { glmesh::VDT_HALF_FLOAT, glmesh::VDT_SINGLE_FLOAT, glmesh::VDT_DOUBLE_FLOAT, glmesh::VDT_SIGN_BYTE, glmesh::VDT_UNSIGN_BYTE, glmesh::VDT_SIGN_SHORT, glmesh::VDT_UNSIGN_SHORT, glmesh::VDT_SIGN_INT, glmesh::VDT_UNSIGN_INT } |
The C data type that you will be providing the vertex attribute data in. More... | |
enum | glmesh::AttribDataType { glmesh::ADT_FLOAT, glmesh::ADT_NORM_FLOAT, glmesh::ADT_INTEGER, glmesh::ADT_DOUBLE } |
The expected interpretation of the attribute data by GLSL. More... | |
Functions | |
template<typename Sink , typename VertexSequence > | |
void | glmesh::Attrib (VertexWriter< Sink > &drawable, const VertexSequence &vertexData) |
A Boost.Fusion-based function for drawing attribute structs. More... | |
Variables | |
const SeparateAttribFormatTag | glmesh::sepFormat |
Use this in VertexFormat::Enable to use the separate attribute format constructor. | |
The expected interpretation of the attribute data by GLSL.
This type must match its corresponding glmesh::VertexDataType or an error will result.
ADT_FLOAT
can be used with anything. ADT_NORM_FLOAT
can only be used with the integer types, signed or unsigned. ADT_INTEGER
can only be used with the integer types, signed or unsigned. ADT_DOUBLE
can only be used with VDT_DOUBLE_FLOAT
. The C data type that you will be providing the vertex attribute data in.
void glmesh::Attrib | ( | VertexWriter< Sink > & | drawable, |
const VertexSequence & | vertexData | ||
) |
A Boost.Fusion-based function for drawing attribute structs.
Boost.Fusion makes it possible to compile-time iterate over boost::tuples, fusion::sequences, and similar types. With the use of certain Boost.Fusion preprocessor commands, it is also possible to iterate over plain structs.
When using glmesh::Draw, if you have some struct that has vertex data, you normally must either write a function to send its vertex data to a glmesh::Draw object, or you must write it out manually at the location where you send vertex data. But if you store your vertex data in a struct that is a valid Boost.Fusion sequence, you can use this function to iterate over them.
Here is an example:
Here is a version that uses Boost.Fusion's struct adaptor utilities:
You can change the vertex type to match whatever you use. In the future, there may be a function that takes a Boost.Fusion type and converts it into a vertex format directly.