-
Notifications
You must be signed in to change notification settings - Fork 0
Buffer Loading OpenGL
Carl Woffenden edited this page Dec 21, 2022
·
6 revisions
To make this clearer all the offsets are named, and these are the same regardless of the graphics API:
/**
* Offsets into the metadata.
*
* \note If \c META_NUM_INDICES is zero (which implies \c META_IBUF_BYTES is
* also zero) the content is unindexed triangles.
*/
enum MetaOffset {
META_MAGIC_TEST = 0, /**< Endianness test/file \e magic. (\c uint16 ). */
META_SHORTCODE = 2, /**< Endianness test/file \e magic. (\c uint16 ). */
META_VBUF_OFFSET = 6, /**< Offset to the start of the vertex data (\c uint32 ). */
META_VBUF_BYTES = 10, /**< Number of vertex data bytes (\c uint32 ). */
META_IBUF_OFFSET = 14, /**< Offset to the start of the index data (\c uint32 ). */
META_IBUF_BYTES = 18, /**< Number of index data bytes (\c uint32 ). */
META_NUM_INDICES = 22, /**< Number of triangle indices to draw (\c uint32 ). */
META_MESH_SCALE = 26, /**< Mesh scale to draw at the original size (3x \c float32 ). */
META_MESH_BIAS = 38, /**< Mesh bias to restore the origin (3x \c float32 ). */
META_PACK_TANS = 50, /**< Where the encoded tangents pair are packed (\c uint8 ). */
META_PACK_SIGN = 51, /**< Where the optional tangent sign is packed (\c uint8 ). */
META_VERT_STRIDE = 52, /**< Single vertex stride in bytes (\c uint8 ). */
META_NUM_ATTRIBS = 53, /**< Number of vertex attributes (\c uint8 ). */
META_ATTR_OFFSET = 54, /**< Start of the attribute data (\c n x 4x \c uint8 ). */
META_MAGIC = 0xBDA7, /**< \e Magic number at the start of the metadata. */
META_CIGAM = 0xA7BD, /**< \c META_MAGIC with the wrong endianness. */
};
/**
* Offsets into each attribute entry, starting at \c MetaOffset#META_ATTR_OFFSET
* (with \c MetaOffsetMETA_NUM_ATTRIBS entries, each of \c ATTR_ENTRY_SIZE
* bytes).
*
* \note At a minimum there will be one entry.
*/
enum AttrEntry {
ATTR_INDEX = 0, /**< Shader index the attribute is bound to (\c uint8). */
ATTR_COMPONENTS = 1, /**< Number of components (\c uint8). */
ATTR_DATA_TYPE = 2, /**< Data type (\c uint8 ; see \c getDataType()). */
ATTR_OFFSET = 3, /**< Offset to the attribute within each \c META_VERT_STRIDE (\c uint8). */
ATTR_ENTRY_SIZE = 4, /**< Number of bytes per \c AttrEntry record. */
};
The targets for the loaded attributes are also named:
enum VertexID {
VERT_POSN_ID = 0, /**< Vertex positions. */
VERT_TEX0_ID = 1, /**< Vertex texture channel channel 0. */
VERT_NORM_ID = 2, /**< Vertex normals. */
VERT_TANS_ID = 3, /**< Vertex tangents. */
VERT_BTAN_ID = 4, /**< Vertex bitangents. */
};
A couple of helpers are then used to get multi-byte values out of the header:
/**
* Convert \c Storage#BasicType from the exporter to the equivalent GL type
* (stored at \c AttrEntry#ATTR_DATA_TYPE ).
*
* \param[in] type the combined type and normalised byte (7-bits for the type)
* \return the GL data type to pass to \c glVertexAttribPointer()
*/
GLenum getDataType(unsigned const type) {
#ifndef GL_HALF_FLOAT
#define GL_HALF_FLOAT 0x140B
#endif
switch (type & 0x7F) {
case 1:
return GL_BYTE;
case 2:
return GL_UNSIGNED_BYTE;
case 3:
return GL_SHORT;
case 4:
return GL_UNSIGNED_SHORT;
case 5:
return GL_INT;
case 6:
return GL_UNSIGNED_INT;
case 7:
return GL_HALF_FLOAT;
default:
return GL_FLOAT;
}
}
/**
* If exported with the \c -m option \c objBuf should have 52-68 bytes of data
* before the buffer data (described by the offsets in \c MetaOffset ).
*
* \note The first entry, \c MetaOffset#META_MAGIC_TEST denotes the endianness,
* which should be \c MetaOffset#META_MAGIC if the endianness of the data
* matches this machine (with no provision here to convert from big to little or
* vice versa).
*
* \param[in] offset metadata index
* \param[in] bytes size of the metadata (e.g. \c 4 for a \c uint32 )
* \return retrieved value
*/
GLuint getBufMeta(unsigned const offset, unsigned const bytes = 4) {
if ((offset + bytes) < sizeof(objBuf)) {
switch (bytes) {
case 1:
return objBuf[offset];
case 2: {
uint16_t temp = 0;
memcpy(&temp, objBuf + offset, bytes);
return temp;
}
case 4: {
uint32_t temp = 0;
memcpy(&temp, objBuf + offset, bytes);
return temp;
}
default:
break;
}
}
return 0;
}
The index buffer data type needs determining:
/**
* Helper to determine the index buffer data type (inferred from the buffer size
* in bytes and the number of indices).
*
* \note Whilst byte and int types can be stored, short should always be
* supported by all APIs and hardware.
*
* \return GL enum for unsigned \c BYTE, \c SHORT or \c INT
*/
GLenum getIndexType() {
switch (getBufMeta(META_IBUF_BYTES) / getBufMeta(META_NUM_INDICES)) {
case 1:
return GL_UNSIGNED_BYTE;
case 2:
return GL_UNSIGNED_SHORT;
default:
return GL_UNSIGNED_INT;
}
}
The attribute indices need binding to the names used in the shader, e.g.:
glBindAttribLocation(progId, VERT_POSN_ID, "aPosn");
glBindAttribLocation(progId, VERT_TEX0_ID, "aTex0");
glBindAttribLocation(progId, VERT_NORM_ID, "aNorm");
glBindAttribLocation(progId, VERT_TANS_ID, "aTans");
glBindAttribLocation(progId, VERT_BTAN_ID, "aBtan");
Perform any shader compilation, linking, etc., then load the buffer data from the metadata description. The steps are:
- Create the vertex and index buffers
- Fill them with data from the offsets
- For each of of the attribute entries:
- Get the
VertexID
- Set the relevant data types and sizes
- Enable the attribute
- Get the
This is code is universal, and as long as the shader attribute names are bound it should just work:
glGenBuffers(2, buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, getBufMeta(META_VBUF_BYTES),
objBuf + getBufMeta(META_VBUF_OFFSET), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, getBufMeta(META_IBUF_BYTES),
objBuf + getBufMeta(META_IBUF_OFFSET), GL_STATIC_DRAW);
for (unsigned n = 0; n < getBufMeta(META_NUM_ATTRIBS, 1); n++) {
unsigned attrOffN = META_ATTR_OFFSET + (n * ATTR_ENTRY_SIZE);
unsigned attrIdxN = getBufMeta(attrOffN + ATTR_INDEX, 1);
glVertexAttribPointer(attrIdxN,
getBufMeta(attrOffN + ATTR_COMPONENTS, 1),
getDataType(getBufMeta(attrOffN + ATTR_DATA_TYPE, 1)),
(getBufMeta(attrOffN + ATTR_DATA_TYPE, 1) & 0x80) ? GL_TRUE : GL_FALSE,
getBufMeta(META_VERT_STRIDE, 1),
(void*) ((size_t) getBufMeta(attrOffN + ATTR_OFFSET, 1)));
glEnableVertexAttribArray(attrIdxN);
}
Then to draw simply:
glDrawElements(GL_TRIANGLES, getBufMeta(META_NUM_INDICES), getIndexType(), 0);