prefect
6fc1f45fa6
Added float-to-byte color conversion, including an SSE assembler version. Model renderer: Push UV coordinates into a shared vertex array and use bytes instead of floats for the color array, thereby, significantly reducing the total size of vertex arrays. This was SVN commit r2827.
207 lines
4.2 KiB
C++
207 lines
4.2 KiB
C++
#include "precompiled.h"
|
|
|
|
#include "ogl.h"
|
|
#include "Vector3D.h"
|
|
#include "Vector4D.h"
|
|
#include "graphics/Color.h"
|
|
#include "renderer/VertexArray.h"
|
|
#include "renderer/VertexBuffer.h"
|
|
#include "renderer/VertexBufferManager.h"
|
|
|
|
|
|
VertexArray::VertexArray(bool dynamic)
|
|
{
|
|
m_Dynamic = dynamic;
|
|
m_NumVertices = 0;
|
|
|
|
m_VB = 0;
|
|
m_BackingStore = 0;
|
|
m_Stride = 0;
|
|
}
|
|
|
|
|
|
VertexArray::~VertexArray()
|
|
{
|
|
Free();
|
|
}
|
|
|
|
// Free all resources on destruction or when a layout parameter changes
|
|
void VertexArray::Free()
|
|
{
|
|
delete[] m_BackingStore;
|
|
m_BackingStore = 0;
|
|
|
|
if (m_VB)
|
|
{
|
|
g_VBMan.Release(m_VB);
|
|
m_VB = 0;
|
|
}
|
|
}
|
|
|
|
|
|
// Set the number of vertices stored in the array
|
|
void VertexArray::SetNumVertices(size_t num)
|
|
{
|
|
if (num == m_NumVertices)
|
|
return;
|
|
|
|
Free();
|
|
m_NumVertices = num;
|
|
}
|
|
|
|
|
|
// Add vertex attributes like Position, Normal, UV
|
|
void VertexArray::AddAttribute(Attribute* attr)
|
|
{
|
|
debug_assert((attr->type == GL_FLOAT || attr->type == GL_UNSIGNED_BYTE) && "Unsupported attribute type");
|
|
debug_assert(attr->elems >= 1 && attr->elems <= 4);
|
|
|
|
attr->vertexArray = this;
|
|
m_Attributes.push_back(attr);
|
|
|
|
Free();
|
|
}
|
|
|
|
|
|
// Template specialization for GetIterator().
|
|
// We can put this into the source file because only a fixed set of types
|
|
// is supported for type safety.
|
|
template<>
|
|
VertexArrayIterator<CVector3D> VertexArray::Attribute::GetIterator<CVector3D>() const
|
|
{
|
|
debug_assert(vertexArray);
|
|
debug_assert(type == GL_FLOAT);
|
|
debug_assert(elems >= 3);
|
|
|
|
return vertexArray->MakeIterator<CVector3D>(this);
|
|
}
|
|
|
|
template<>
|
|
VertexArrayIterator<CVector4D> VertexArray::Attribute::GetIterator<CVector4D>() const
|
|
{
|
|
debug_assert(vertexArray);
|
|
debug_assert(type == GL_FLOAT);
|
|
debug_assert(elems >= 4);
|
|
|
|
return vertexArray->MakeIterator<CVector4D>(this);
|
|
}
|
|
|
|
template<>
|
|
VertexArrayIterator<float[2]> VertexArray::Attribute::GetIterator<float[2]>() const
|
|
{
|
|
debug_assert(vertexArray);
|
|
debug_assert(type == GL_FLOAT);
|
|
debug_assert(elems >= 2);
|
|
|
|
return vertexArray->MakeIterator<float[2]>(this);
|
|
}
|
|
|
|
template<>
|
|
VertexArrayIterator<SColor3ub> VertexArray::Attribute::GetIterator<SColor3ub>() const
|
|
{
|
|
debug_assert(vertexArray);
|
|
debug_assert(type == GL_UNSIGNED_BYTE);
|
|
debug_assert(elems >= 3);
|
|
|
|
return vertexArray->MakeIterator<SColor3ub>(this);
|
|
}
|
|
|
|
template<>
|
|
VertexArrayIterator<SColor4ub> VertexArray::Attribute::GetIterator<SColor4ub>() const
|
|
{
|
|
debug_assert(vertexArray);
|
|
debug_assert(type == GL_UNSIGNED_BYTE);
|
|
debug_assert(elems >= 4);
|
|
|
|
return vertexArray->MakeIterator<SColor4ub>(this);
|
|
}
|
|
|
|
|
|
|
|
static size_t RoundStride(size_t stride)
|
|
{
|
|
if (stride <= 0)
|
|
return 0;
|
|
if (stride <= 4)
|
|
return 4;
|
|
if (stride <= 8)
|
|
return 8;
|
|
if (stride <= 16)
|
|
return 16;
|
|
|
|
return (stride + 31) & ~31;
|
|
}
|
|
|
|
// Re-layout by assigning offsets on a first-come first-serve basis,
|
|
// then round up to a reasonable stride.
|
|
// Backing store is also created here, VBOs are created on upload.
|
|
void VertexArray::Layout()
|
|
{
|
|
Free();
|
|
|
|
m_Stride = 0;
|
|
|
|
//debug_printf("Layouting VertexArray\n");
|
|
|
|
for(int idx = m_Attributes.size()-1; idx >= 0; --idx)
|
|
{
|
|
Attribute* attr = m_Attributes[idx];
|
|
|
|
if (!attr->type || !attr->elems)
|
|
continue;
|
|
|
|
size_t attrSize;
|
|
|
|
switch(attr->type) {
|
|
case GL_UNSIGNED_BYTE: attrSize = sizeof(GLubyte); break;
|
|
case GL_FLOAT: attrSize = sizeof(GLfloat); break;
|
|
default: debug_warn("Bad AttributeInfo::Type"); break;
|
|
}
|
|
|
|
attrSize *= attr->elems;
|
|
|
|
attr->offset = m_Stride;
|
|
m_Stride = (m_Stride + attrSize + 3) & ~3;
|
|
|
|
//debug_printf("%i: offset: %u\n", idx, attr->offset);
|
|
}
|
|
|
|
m_Stride = RoundStride(m_Stride);
|
|
|
|
//debug_printf("Stride: %u\n", m_Stride);
|
|
|
|
if (m_Stride)
|
|
m_BackingStore = new char[m_Stride * m_NumVertices];
|
|
}
|
|
|
|
|
|
// (Re-)Upload the attributes.
|
|
// Create the VBO if necessary.
|
|
void VertexArray::Upload()
|
|
{
|
|
debug_assert(m_BackingStore);
|
|
|
|
if (!m_VB)
|
|
m_VB = g_VBMan.Allocate(m_Stride, m_NumVertices, m_Dynamic);
|
|
|
|
m_VB->m_Owner->UpdateChunkVertices(m_VB, m_BackingStore);
|
|
}
|
|
|
|
|
|
// Bind this array, returns the base address for calls to glVertexPointer etc.
|
|
u8* VertexArray::Bind()
|
|
{
|
|
u8* base = m_VB->m_Owner->Bind();
|
|
base += m_VB->m_Index*m_Stride;
|
|
return base;
|
|
}
|
|
|
|
|
|
// Free the backing store to save some memory
|
|
void VertexArray::FreeBackingStore()
|
|
{
|
|
delete[] m_BackingStore;
|
|
m_BackingStore = 0;
|
|
}
|
|
|