update VertexBuffer to use Initialize() methods to setup itself instead of the constructor. vertex attributes are now passed as an array instead of using "Add" methods

This commit is contained in:
Gered 2013-04-01 17:14:05 -04:00
parent a20bc14b71
commit 2ec3ed3673
2 changed files with 240 additions and 280 deletions

View file

@ -7,8 +7,7 @@
const unsigned int FLOATS_PER_GPU_ATTRIB_SLOT = 4;
const unsigned int MAX_GPU_ATTRIB_SLOTS = 8;
VertexBuffer::VertexBuffer(BUFFEROBJECT_USAGE usage)
: BufferObject(BUFFEROBJECT_TYPE_VERTEX, usage)
VertexBuffer::VertexBuffer()
{
STACK_TRACE;
m_numVertices = 0;
@ -20,6 +19,8 @@ VertexBuffer::VertexBuffer(BUFFEROBJECT_USAGE usage)
m_position3Offset = 0;
m_normalOffset = 0;
m_texCoordOffset = 0;
m_numAttributes = 0;
m_attribs = NULL;
m_numGPUAttributeSlotsUsed = 0;
}
@ -28,163 +29,23 @@ VertexBuffer::~VertexBuffer()
STACK_TRACE;
}
BOOL VertexBuffer::AddAttribute(uint32_t size, VERTEX_ATTRIBS standardType)
BOOL VertexBuffer::Initialize(const VERTEX_ATTRIBS *attributes, uint32_t numAttributes, uint32_t numVertices, BUFFEROBJECT_USAGE usage)
{
STACK_TRACE;
ASSERT(standardType == VERTEX_GENERIC || HasStandardAttrib(standardType) == FALSE);
ASSERT(size <= 16);
if (standardType != VERTEX_GENERIC && HasStandardAttrib(standardType))
return FALSE;
if (size > 16)
return FALSE;
// using integer division that rounds up (so given size = 13, result is 4, not 3)
uint32_t numGPUAttributeSlotsUsed = (size + (FLOATS_PER_GPU_ATTRIB_SLOT - 1)) / FLOATS_PER_GPU_ATTRIB_SLOT;
ASSERT(m_numGPUAttributeSlotsUsed + numGPUAttributeSlotsUsed <= MAX_GPU_ATTRIB_SLOTS);
if (m_numGPUAttributeSlotsUsed + numGPUAttributeSlotsUsed > MAX_GPU_ATTRIB_SLOTS)
return FALSE;
VertexBufferAttribute newAttrib;
newAttrib.standardType = standardType;
newAttrib.size = size;
newAttrib.offset = m_elementWidth;
switch (standardType)
{
case VERTEX_POS_2D:
ASSERT(size == 2);
if (size != 2)
return FALSE;
m_position2Offset = newAttrib.offset;
break;
case VERTEX_POS_3D:
ASSERT(size == 3);
if (size != 3)
return FALSE;
m_position3Offset = newAttrib.offset;
break;
case VERTEX_NORMAL:
ASSERT(size == 3);
if (size != 3)
return FALSE;
m_normalOffset = newAttrib.offset;
break;
case VERTEX_COLOR:
ASSERT(size == 4);
if (size != 4)
return FALSE;
m_colorOffset = newAttrib.offset;
break;
case VERTEX_TEXCOORD:
ASSERT(size == 2);
if (size != 2)
return FALSE;
m_texCoordOffset = newAttrib.offset;
break;
case VERTEX_GENERIC:
break;
}
m_attribs.push_back(newAttrib);
m_elementWidth += size;
m_numGPUAttributeSlotsUsed += numGPUAttributeSlotsUsed;
SetBit(standardType, m_standardTypeAttribs);
return TRUE;
return Initialize(NULL, attributes, numAttributes, numVertices, usage);
}
BOOL VertexBuffer::AddAttribute(VERTEX_ATTRIBS standardType)
BOOL VertexBuffer::Initialize(GraphicsDevice *graphicsDevice, const VERTEX_ATTRIBS *attributes, uint32_t numAttributes, uint32_t numVertices, BUFFEROBJECT_USAGE usage)
{
STACK_TRACE;
ASSERT(standardType != VERTEX_GENERIC);
if (standardType == VERTEX_GENERIC)
return FALSE;
ASSERT(HasStandardAttrib(standardType) == FALSE);
if (HasStandardAttrib(standardType))
return FALSE;
BOOL result = FALSE;
switch (standardType)
{
case VERTEX_POS_2D:
result = AddAttribute(ATTRIB_SIZE_VEC2, VERTEX_POS_2D);
break;
case VERTEX_POS_3D:
result = AddAttribute(ATTRIB_SIZE_VEC3, VERTEX_POS_3D);
break;
case VERTEX_NORMAL:
result = AddAttribute(ATTRIB_SIZE_VEC3, VERTEX_NORMAL);
break;
case VERTEX_COLOR:
result = AddAttribute(ATTRIB_SIZE_VEC4, VERTEX_COLOR);
break;
case VERTEX_TEXCOORD:
result = AddAttribute(ATTRIB_SIZE_VEC2, VERTEX_TEXCOORD);
break;
case VERTEX_GENERIC:
break;
}
return result;
}
BOOL VertexBuffer::CopyAttributesFrom(const VertexBuffer *source)
{
STACK_TRACE;
ASSERT(source != NULL);
if (source == NULL)
return FALSE;
ASSERT(source->GetNumAttributes() != 0);
ASSERT(m_buffer.size() == 0);
if (source->GetNumAttributes() == 0)
return FALSE;
if (m_buffer.size() > 0)
return FALSE;
m_attribs.clear();
for (uint32_t i = 0; i < source->GetNumAttributes(); ++i)
{
const VertexBufferAttribute *sourceAttrib = source->GetAttributeInfo(i);
AddAttribute(sourceAttrib->size, sourceAttrib->standardType);
}
return TRUE;
}
int32_t VertexBuffer::GetIndexOfStandardAttrib(VERTEX_ATTRIBS standardAttrib) const
{
STACK_TRACE;
ASSERT(standardAttrib != VERTEX_GENERIC);
if (standardAttrib == VERTEX_GENERIC)
return -1;
for (uint32_t i = 0; i < m_attribs.size(); ++i)
{
if (m_attribs[i].standardType == standardAttrib)
return (int32_t)i;
}
return -1;
}
BOOL VertexBuffer::Create(uint32_t numVertices)
{
STACK_TRACE;
ASSERT(m_attribs.size() > 0);
ASSERT(m_buffer.size() == 0);
ASSERT(m_elementWidth > 0);
if (m_attribs.size() == 0)
if (!BufferObject::Initialize(graphicsDevice, BUFFEROBJECT_TYPE_VERTEX, usage))
return FALSE;
if (m_buffer.size() > 0)
return FALSE;
if (m_elementWidth == 0)
if (!SetSizesAndOffsets(attributes, numAttributes))
return FALSE;
Resize(numVertices);
@ -192,36 +53,162 @@ BOOL VertexBuffer::Create(uint32_t numVertices)
return TRUE;
}
BOOL VertexBuffer::CreateCopyOf(const VertexBuffer *source)
BOOL VertexBuffer::Initialize(const VertexBuffer *source)
{
STACK_TRACE;
return Initialize(NULL, source);
}
BOOL VertexBuffer::Initialize(GraphicsDevice *graphicsDevice, const VertexBuffer *source)
{
STACK_TRACE;
ASSERT(m_buffer.size() == 0);
if (m_buffer.size() > 0)
return FALSE;
ASSERT(source != NULL);
if (source == NULL)
return FALSE;
ASSERT(source->GetNumElements() != 0);
ASSERT(m_buffer.size() == 0);
ASSERT(source->GetNumElements() > 0);
if (source->GetNumElements() == 0)
return FALSE;
if (!BufferObject::Initialize(graphicsDevice, BUFFEROBJECT_TYPE_VERTEX, source->GetUsage()))
return FALSE;
uint32_t numAttribs = source->GetNumAttributes();
VERTEX_ATTRIBS *attribs = new VERTEX_ATTRIBS[numAttribs];
for (uint32_t i = 0; i < numAttribs; ++i)
attribs[i] = source->GetAttributeInfo(i)->standardType;
BOOL success = SetSizesAndOffsets(attribs, numAttribs);
if (success)
{
Resize(source->GetNumElements());
Copy(source, 0);
}
SAFE_DELETE_ARRAY(attribs);
return success;
}
BOOL VertexBuffer::SetSizesAndOffsets(const VERTEX_ATTRIBS *attributes, uint32_t numAttributes)
{
STACK_TRACE;
ASSERT(attributes != NULL);
ASSERT(numAttributes > 0);
ASSERT(m_buffer.size() == 0);
ASSERT(m_attribs == NULL);
if (attributes == NULL)
return FALSE;
if (numAttributes == 0)
return FALSE;
if (m_buffer.size() > 0)
return FALSE;
BOOL attribCopyResult = CopyAttributesFrom(source);
if (!attribCopyResult)
if (m_attribs != NULL)
return FALSE;
Resize(source->GetNumElements());
uint32_t numGpuSlotsUsed = 0;
uint32_t offset = 0;
memcpy(&m_buffer[0], source->GetBuffer(), GetNumElements() * GetElementWidthInBytes());
VertexBufferAttribute *attribsInfo = new VertexBufferAttribute[numAttributes];
BOOL success = TRUE;
return TRUE;
for (uint32_t i = 0; i < numAttributes; ++i)
{
VERTEX_ATTRIBS attrib = attributes[i];
// TODO: endianness
uint8_t size = (uint8_t)attrib; // low byte
uint8_t standardTypeBitMask = (uint8_t)((uint16_t)attrib >> 8);
// using integer division that rounds up (so given size = 13, result is 4, not 3)
uint32_t thisAttribsGpuSlotSize = ((uint32_t)size + (FLOATS_PER_GPU_ATTRIB_SLOT - 1)) / FLOATS_PER_GPU_ATTRIB_SLOT;
ASSERT(numGpuSlotsUsed + thisAttribsGpuSlotSize <= MAX_GPU_ATTRIB_SLOTS);
if (numGpuSlotsUsed + thisAttribsGpuSlotSize > MAX_GPU_ATTRIB_SLOTS)
{
success = FALSE;
break;
}
if (standardTypeBitMask > 0)
{
// ensure no duplicate standard attribute types are specified
ASSERT(IsBitSet(standardTypeBitMask, m_standardTypeAttribs) == FALSE);
if (IsBitSet(standardTypeBitMask, m_standardTypeAttribs))
{
success = FALSE;
break;
}
SetBit(standardTypeBitMask, m_standardTypeAttribs);
// record offset position for each standard type attribute
switch ((VERTEX_STANDARD_ATTRIBS)attrib)
{
case VERTEX_STD_POS_2D: m_position2Offset = offset; break;
case VERTEX_STD_POS_3D: m_position3Offset = offset; break;
case VERTEX_STD_NORMAL: m_normalOffset = offset; break;
case VERTEX_STD_COLOR: m_colorOffset = offset; break;
case VERTEX_STD_TEXCOORD: m_texCoordOffset = offset; break;
}
}
// set attribute info
attribsInfo[i].offset = offset;
attribsInfo[i].size = size;
attribsInfo[i].standardType = attrib;
// advance to the next spot
m_elementWidth += size;
offset += size;
numGpuSlotsUsed += thisAttribsGpuSlotSize;
}
if (!success)
{
SAFE_DELETE_ARRAY(attribsInfo)
m_attribs = NULL;
m_numAttributes = 0;
m_elementWidth = 0;
m_position2Offset = 0;
m_position3Offset = 0;
m_normalOffset = 0;
m_colorOffset = 0;
m_texCoordOffset = 0;
}
else
{
m_attribs = attribsInfo;
m_numAttributes = numAttributes;
}
return success;
}
int32_t VertexBuffer::GetIndexOfStandardAttrib(VERTEX_STANDARD_ATTRIBS standardAttrib) const
{
STACK_TRACE;
for (uint32_t i = 0; i < m_numAttributes; ++i)
{
if ((uint32_t)m_attribs[i].standardType == (uint32_t)standardAttrib)
return (int32_t)i;
}
return -1;
}
void VertexBuffer::Resize(uint32_t numVertices)
{
STACK_TRACE;
ASSERT(numVertices > 0);
if (numVertices == 0)
return;
m_buffer.resize(numVertices * m_elementWidth, 0.0f);
m_numVertices = numVertices;

View file

@ -16,6 +16,8 @@
#include "vertexattribs.h"
class GraphicsDevice;
/**
* Wraps management of an array of vertices stored either completely
* in main memory (client-side) or in video memory.
@ -23,61 +25,53 @@
class VertexBuffer : public BufferObject
{
public:
/**
* Creates an uninitialized vertex buffer object.
* @param usage the expected usage pattern of this vertex buffer
*/
VertexBuffer(BUFFEROBJECT_USAGE usage);
/**
* Creates a vertex buffer.
* @param source the source buffer to copy during creation of this buffer
*/
VertexBuffer(const VertexBuffer *source);
VertexBuffer();
virtual ~VertexBuffer();
/**
* Adds an attribute to the vertex buffer.
* @param size the size of the attribute's data (specified in number of floats)
* @param standardType the standard type mapping for ease of use (allowing
* use of special get/set methods for type safety)
* Initializes the vertex buffer.
* @param attributes the vertex attributes this buffer will contain
* @param numAttributes the number of vertex attributes
* @param numVertices the initial number of vertices this buffer will contain
* @param usage the expected usage pattern of this vertex buffer
* @return TRUE if successful, FALSE if not
*/
BOOL AddAttribute(uint32_t size, VERTEX_ATTRIBS standardType = VERTEX_GENERIC);
BOOL Initialize(const VERTEX_ATTRIBS *attributes, uint32_t numAttributes, uint32_t numVertices, BUFFEROBJECT_USAGE usage);
/**
* Adds an attribute to the vertex buffer.
* @param size the size of the attribute's data
* @param standardType the standard type mapping for ease of use (allowing
* use of special get/set methods for type safety)
* Initializes the vertex buffer.
* @param graphicsDevice the graphics device to use to create this buffer
* on the GPU
* @param attributes the vertex attributes this buffer will contain
* @param numAttributes the number of vertex attributes
* @param numVertices the initial number of vertices this buffer will contain
* @param usage the expected usage pattern of this vertex buffer
* @return TRUE if successful, FALSE if not
*/
BOOL AddAttribute(VERTEX_ATTRIB_SIZES size, VERTEX_ATTRIBS standardType = VERTEX_GENERIC);
BOOL Initialize(GraphicsDevice *graphicsDevice, const VERTEX_ATTRIBS *attributes, uint32_t numAttributes, uint32_t numVertices, BUFFEROBJECT_USAGE usage);
/**
* Adds an attribute which will be used for one of the standard types of
* data (e.g. 2D/3D vertex position, color, texture coordinates, etc). The
* other attribute information, like size, will be automatically set.
* @param standardType the standard type of the attribute. Cannot be
* VERTEX_GENERIC.
* Initializes the vertex buffer.
* @param source the source buffer to create this buffer from. it's
* properties and vertex data will be used to create this one
* @return TRUE if successful, FALSE if not
*/
BOOL AddAttribute(VERTEX_ATTRIBS standardType);
BOOL Initialize(const VertexBuffer *source);
/**
* Sets this vertex buffer's attributes to match those from a source
* vertex buffer. Any existing attribute information that has been set
* in this vertex buffer will be cleared.
* @param source the source buffer to copy attribute information from
* Initializes the vertex buffer.
* @param graphicsDevice the graphics device to use to create this buffer
* on the GPU
* @param source the source buffer to create this buffer from. it's
* properties and vertex data will be used to create this one
* @return TRUE if successful, FALSE if not
*/
BOOL CopyAttributesFrom(const VertexBuffer *source);
BOOL Initialize(GraphicsDevice *graphicsDevice, const VertexBuffer *source);
/**
* @return the number of attributes in this vertex buffer
*/
uint32_t GetNumAttributes() const { return m_attribs.size(); }
uint32_t GetNumAttributes() const { return m_numAttributes; }
/**
* Returns information about the specified attribute.
@ -100,33 +94,14 @@ public:
* @return TRUE if the vertex data in this buffer contains this standard
* attribute
*/
BOOL HasStandardAttrib(VERTEX_ATTRIBS standardAttrib) const { return (m_standardTypeAttribs & standardAttrib) > 0; }
BOOL HasStandardAttrib(VERTEX_STANDARD_ATTRIBS standardAttrib) const { return (m_standardTypeAttribs & (uint32_t)standardAttrib) > 0; }
/**
* Returns the index of the specified standard attribute.
* @param standardAttrib the standard attribute to get the index of
* @return the index of the attribute, or -1 if it is not present
*/
int32_t GetIndexOfStandardAttrib(VERTEX_ATTRIBS standardAttrib) const;
/**
* Allocates the client-side memory buffer for this vertex buffer. All
* attributes must have been added via AddAttribute() before this call. No
* more can be added after this call.
* @param numVertices the initial number of vertices this buffer should hold
* @return TRUE if successful, FALSE if not
*/
BOOL Create(uint32_t numVertices);
/**
* Sets up attributes and data to match a source vertex buffer, making an
* exact copy. Any existing attribute definitions made via AddAttribute()
* before this call will be ignored. No more attributes can be added after
* this call.
* @param source the source buffer to copy
* @return TRUE if successful, FALSE if not
*/
BOOL CreateCopyOf(const VertexBuffer *source);
int32_t GetIndexOfStandardAttrib(VERTEX_STANDARD_ATTRIBS standardAttrib) const;
/**
* @return the offset from the start of a single vertex's data that the
@ -549,6 +524,8 @@ public:
uint32_t GetRemainingSpace() const { return (GetNumElements() - 1) - GetCurrentPosition(); }
private:
BOOL SetSizesAndOffsets(const VERTEX_ATTRIBS *attributes, uint32_t numAttributes);
BOOL IsBufferAllocated() const { return m_buffer.size() > 0; }
uint32_t GetVertexPosition(uint32_t index) const { return (index * m_elementWidth); }
@ -572,16 +549,12 @@ private:
uint32_t m_texCoordOffset;
// ---
stl::vector<VertexBufferAttribute> m_attribs;
VertexBufferAttribute *m_attribs;
uint32_t m_numAttributes;
uint32_t m_numGPUAttributeSlotsUsed;
stl::vector<float> m_buffer;
};
inline BOOL VertexBuffer::AddAttribute(VERTEX_ATTRIB_SIZES size, VERTEX_ATTRIBS standardType)
{
return AddAttribute((uint32_t)size, standardType);
}
inline Color VertexBuffer::GetColor(uint32_t index) const
{
uint32_t p = GetColorBufferPosition(index);