Files
OpenSceneGraph/src/osgPlugins/flt/LocalVertexPoolRecord.cpp
2004-10-24 17:50:54 +00:00

543 lines
15 KiB
C++

// LocalVertexPoolRecords.cpp
#ifdef _WIN32
#pragma warning(disable:4786) // Truncated debug names.
#endif
#include "LocalVertexPoolRecord.h"
#include "Registry.h"
#include <assert.h>
// The sizes (in bytes) of the various attribute sections of the vertex data.
#define SIZE_POSITION 24 // 3 * float64 = 3 * 8
#define SIZE_COLOR 4 // 1 uint32
#define SIZE_NORMAL 12 // 3 * float32 = 3 * 4
#define SIZE_BASE_UV 8 // 2 * float32 = 2 * 4
#define SIZE_UV_1 SIZE_BASE_UV
#define SIZE_UV_2 SIZE_BASE_UV
#define SIZE_UV_3 SIZE_BASE_UV
#define SIZE_UV_4 SIZE_BASE_UV
#define SIZE_UV_5 SIZE_BASE_UV
#define SIZE_UV_6 SIZE_BASE_UV
#define SIZE_UV_7 SIZE_BASE_UV
using namespace flt;
////////////////////////////////////////////////////////////////////
//
// LocalVertexPoolRecord
//
////////////////////////////////////////////////////////////////////
RegisterRecordProxy<LocalVertexPoolRecord> g_LocalVertexPoolProxy;
LocalVertexPoolRecord *_current = NULL;
LocalVertexPoolRecord::LocalVertexPoolRecord()
: AncillaryRecord(),
_vertexSizeBytesCache(0)
{
}
// virtual
LocalVertexPoolRecord::~LocalVertexPoolRecord()
{
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the address of the beginning of the vertices.
//
///////////////////////////////////////////////////////////////////////////////
char *LocalVertexPoolRecord::_getStartOfVertices() const
{
SLocalVertexPool *pool = (SLocalVertexPool *) this->getData();
char *vertex = (char *) (&(pool[1]));
return vertex;
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the address of the beginning of the specified vertex attribute.
//
///////////////////////////////////////////////////////////////////////////////
char *LocalVertexPoolRecord::_getStartOfAttribute ( const uint32 &whichVertex, const uint32 &offset ) const
{
assert ( whichVertex < this->getNumVertices() );
// Get pointer to start of vertex data.
char *startOfVertices = (char *) this->_getStartOfVertices();
// The number of vertices.
//uint32 numVertices = this->getNumVertices();
// NOTE This function formerly computed sizeOfVertex by taking the record length and dividing
// by the number of vertices. This is wrong in 15.7 and beyond, as the record could
// exceed 65535 bytes and be continued, in which case the "original" record length
// field does not contain the actual length of the data.
// The size of each individual vertex depends on its attributes, and is cached.
size_t sizeOfVertex = this->_getVertexSizeBytes();
// Set the start of the desired vertex's data.
char *startOfAttribute = &startOfVertices[whichVertex * sizeOfVertex];
// Now adjust for the offset within this vertex.
startOfAttribute += offset;
// Return the pointer.
return startOfAttribute;
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the specified vertex attribute.
//
///////////////////////////////////////////////////////////////////////////////
bool LocalVertexPoolRecord::getColorIndex ( const uint32 &whichVertex, uint32 &colorIndex ) const
{
ARGUMENT_CHECK_FOR_GET_FUNCTION ( whichVertex, COLOR_INDEX );
// Offset to the start of the color.
uint32 *color = (uint32 *) this->_getStartOfAttribute ( whichVertex, _offset.color );
if ( NULL == color )
return false;
// Set the color index and return.
colorIndex = *color;
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the specified vertex attribute.
//
///////////////////////////////////////////////////////////////////////////////
bool LocalVertexPoolRecord::getColorRGBA ( const uint32 &whichVertex, float32 &r, float32 &g, float32 &b, float32 &a ) const
{
ARGUMENT_CHECK_FOR_GET_FUNCTION ( whichVertex, RGB_COLOR );
// Offset to the start of the color.
uint32 *color = (uint32 *) this->_getStartOfAttribute ( whichVertex, _offset.color );
if ( NULL == color )
return false;
// Since we already byte-swapped, we have to check the endian of this
// machine so that we know how to grab the channels.
uint32 red, green, blue, alpha;
// If this machine is little-endian...
if ( flt::isLittleEndianMachine() )
{
red = ( ( (*color) & 0xFF000000 ) >> 0 );
green = ( ( (*color) & 0x00FF0000 ) >> 8 );
blue = ( ( (*color) & 0x0000FF00 ) >> 16 );
alpha = ( ( (*color) & 0x000000FF ) >> 24 );
}
// Otherwise, big-endian...
else
{
red = ( ( (*color) & 0x000000FF ) >> 0 );
green = ( ( (*color) & 0x0000FF00 ) >> 8 );
blue = ( ( (*color) & 0x00FF0000 ) >> 16 );
alpha = ( ( (*color) & 0xFF000000 ) >> 24 );
}
// Normalize.
float32 scale = 1.0f / 255.0f;
r = scale * red;
g = scale * green;
b = scale * blue;
a = scale * alpha;
// It worked.
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the specified vertex attribute.
//
///////////////////////////////////////////////////////////////////////////////
bool LocalVertexPoolRecord::getNormal ( const uint32 &whichVertex, float32 &nx, float32 &ny, float32 &nz ) const
{
ARGUMENT_CHECK_FOR_GET_FUNCTION ( whichVertex, NORMAL );
// Offset to the start of the normals.
float32 *vec = (float32 *) this->_getStartOfAttribute ( whichVertex, _offset.normal );
if ( NULL == vec )
return false;
// Set the normal vector and return.
nx = vec[0];
ny = vec[1];
nz = vec[2];
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the specified vertex attribute.
//
///////////////////////////////////////////////////////////////////////////////
bool LocalVertexPoolRecord::getPosition ( const uint32 &whichVertex, float64 &px, float64 &py, float64 &pz ) const
{
ARGUMENT_CHECK_FOR_GET_FUNCTION ( whichVertex, POSITION );
// Offset to the start of the normals.
float64 *point = (float64 *) this->_getStartOfAttribute ( whichVertex, _offset.position );
if ( NULL == point )
return false;
// Set the normal vector and return.
px = point[0];
py = point[1];
pz = point[2];
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Return the specified vertex attribute.
//
///////////////////////////////////////////////////////////////////////////////
bool LocalVertexPoolRecord::getUV ( const uint32 &whichVertex, const AttributeMask &whichUV, float32 &u, float32 &v ) const
{
ARGUMENT_CHECK_FOR_GET_FUNCTION ( whichVertex, (uint32) whichUV );
// Offset to the start of the normals.
float32 *uv = (float32 *) this->_getStartOfAttribute ( whichVertex, this->_getOffset ( whichUV ) );
if ( NULL == uv )
return false;
// Set the normal vector and return.
u = uv[0];
v = uv[1];
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Getthe offset that corresponds to the given attribute.
//
///////////////////////////////////////////////////////////////////////////////
uint32 LocalVertexPoolRecord::_getOffset ( const AttributeMask &attribute ) const
{
switch ( attribute )
{
case POSITION: return _offset.position;
case COLOR_INDEX: return _offset.color;
case RGB_COLOR: return _offset.color;
case NORMAL: return _offset.normal;
case BASE_UV: return _offset.baseUV;
case UV_1: return _offset.uv1;
case UV_2: return _offset.uv2;
case UV_3: return _offset.uv3;
case UV_4: return _offset.uv4;
case UV_5: return _offset.uv5;
case UV_6: return _offset.uv6;
case UV_7: return _offset.uv7;
default:
assert ( 0 );
return 0;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Convert the data from big-endian to little-endian.
//
///////////////////////////////////////////////////////////////////////////////
void LocalVertexPoolRecord::endian()
{
// Should only be in here for little-endian machines.
assert ( flt::isLittleEndianMachine() );
// Get a pointer to the vertex pool structure. Note: The members of
// SLocalVertexPool have already been endian-corrected in
// _initAttributeOffsets().
SLocalVertexPool *pool = (SLocalVertexPool *) this->getData();
// Get pointer to start of vertex data.
char *vertex = this->_getStartOfVertices();
// Loop through the vertices and byte-swap the data.
for ( uint32 i = 0; i < pool->numVerts; ++i )
{
if ( this->hasAttribute ( POSITION ) )
{
// Get the size of the coordinates.
size_t size = sizeof ( float64 );
// Get the values.
float64 *x = (float64 *) vertex;
float64 *y = &(x[1]);
float64 *z = &(y[1]);
// Swap the data.
flt::swapBytes ( size, x );
flt::swapBytes ( size, y );
flt::swapBytes ( size, z );
// Move pointer to the end of this chunk of data.
vertex = (char *) ( &(z[1]) );
}
if ( this->hasAttribute ( COLOR_INDEX ) ||
this->hasAttribute ( RGB_COLOR ) )
{
// Get the size of the coordinates.
size_t size = sizeof ( uint32 );
// Get the value.
uint32 *color = (uint32 *) vertex;
// Swap the data.
flt::swapBytes ( size, color );
// Move pointer to the end of this chunk of data.
vertex = (char *) ( &(color[1]) );
}
if ( this->hasAttribute ( NORMAL ) )
{
// Get the size of the elements.
size_t size = sizeof ( float32 );
// Get the values.
float32 *x = (float32 *) vertex;
float32 *y = &(x[1]);
float32 *z = &(y[1]);
// Swap the data.
flt::swapBytes ( size, x );
flt::swapBytes ( size, y );
flt::swapBytes ( size, z );
// Move pointer to the end of this chunk of data.
vertex = (char *) ( &(z[1]) );
}
if ( this->hasAttribute ( BASE_UV ) ||
this->hasAttribute ( UV_1 ) ||
this->hasAttribute ( UV_2 ) ||
this->hasAttribute ( UV_3 ) ||
this->hasAttribute ( UV_4 ) ||
this->hasAttribute ( UV_5 ) ||
this->hasAttribute ( UV_6 ) ||
this->hasAttribute ( UV_7 ) )
{
// Get the size of the elements.
size_t size = sizeof ( float32 );
// Get the values.
float32 *u = (float32 *) vertex;
float32 *v = &(u[1]);
// Swap the data.
flt::swapBytes ( size, u );
flt::swapBytes ( size, v );
// Move pointer to the end of this chunk of data.
vertex = (char *) ( &(v[1]) );
}
}
// Should be true. It means that we walked the pointer "vertex" to the
// end of the record, but not past it.
// If equal, vertex pool record was not continued.
// If 16bit record length is less than length of vertex pool, then the original vertex
// pool record was continued with one or more CONTINUATION_OP records.
assert ( pool->RecHeader._wLength <= ( ( (unsigned long) vertex ) - ( (unsigned long) pool ) ) );
}
///////////////////////////////////////////////////////////////////////////////
//
// The offsets to the start of each attribute depends on the what attributes
// are in the vertices. Here we initialize those integer data members.
//
///////////////////////////////////////////////////////////////////////////////
void LocalVertexPoolRecord::_initAttributeOffsets()
{
// When we get to here we just got done reading the data (i.e., it is still
// big-endian). Correct the endian of the members of SLocalVertexPool
// because we need the SLocalVertexPool::attributeMask to determine the
// offsets (but do not endian-correct the vertex data that follows). The
// rest of the data (the vertices) will be endian-corrected in endian().
// If we are on a little-endian machine...
if ( flt::isLittleEndianMachine() )
{
// Fix these data members.
SLocalVertexPool *pool = (SLocalVertexPool *) this->getData();
ENDIAN ( pool->numVerts );
ENDIAN ( pool->attributeMask );
}
// Initialize.
uint32 current = 0;
// The order is important because the data will be in this order. We drop
// down through here and set the offsets. Each time we update the current
// position so that we can set the next one.
if ( this->hasAttribute ( POSITION ) )
{
_offset.position = current;
current += SIZE_POSITION;
}
if ( this->hasAttribute ( COLOR_INDEX ) || this->hasAttribute ( RGB_COLOR ) )
{
// According to 15.7 manual, we should not have both flags.
assert ( false == ( this->hasAttribute ( COLOR_INDEX ) && this->hasAttribute ( RGB_COLOR ) ) );
_offset.color = current;
current += SIZE_COLOR;
}
if ( this->hasAttribute ( NORMAL ) )
{
_offset.normal = current;
current += SIZE_NORMAL;
}
if ( this->hasAttribute ( BASE_UV ) )
{
_offset.baseUV = current;
current += SIZE_BASE_UV;
}
if ( this->hasAttribute ( UV_1 ) )
{
_offset.uv1 = current;
current += SIZE_UV_1;
}
if ( this->hasAttribute ( UV_2 ) )
{
_offset.uv2 = current;
current += SIZE_UV_2;
}
if ( this->hasAttribute ( UV_3 ) )
{
_offset.uv3 = current;
current += SIZE_UV_3;
}
if ( this->hasAttribute ( UV_4 ) )
{
_offset.uv4 = current;
current += SIZE_UV_4;
}
if ( this->hasAttribute ( UV_5 ) )
{
_offset.uv5 = current;
current += SIZE_UV_5;
}
if ( this->hasAttribute ( UV_6 ) )
{
_offset.uv6 = current;
current += SIZE_UV_6;
}
if ( this->hasAttribute ( UV_7 ) )
{
_offset.uv7 = current;
current += SIZE_UV_7;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Compute the size of each vertex based on its attributes. Cache the
// result for later reference.
//
///////////////////////////////////////////////////////////////////////////////
int LocalVertexPoolRecord::_getVertexSizeBytes() const
{
if (_vertexSizeBytesCache == 0)
{
if ( hasAttribute ( POSITION ) )
_vertexSizeBytesCache += SIZE_POSITION;
if ( hasAttribute ( COLOR_INDEX ) || hasAttribute ( RGB_COLOR ) )
_vertexSizeBytesCache += SIZE_COLOR;
if ( hasAttribute ( NORMAL ) )
_vertexSizeBytesCache += SIZE_NORMAL;
if ( hasAttribute ( BASE_UV ) )
_vertexSizeBytesCache += SIZE_BASE_UV;
if ( hasAttribute ( UV_1 ) )
_vertexSizeBytesCache += SIZE_UV_1;
if ( hasAttribute ( UV_2 ) )
_vertexSizeBytesCache += SIZE_UV_2;
if ( hasAttribute ( UV_3 ) )
_vertexSizeBytesCache += SIZE_UV_3;
if ( hasAttribute ( UV_4 ) )
_vertexSizeBytesCache += SIZE_UV_4;
if ( hasAttribute ( UV_5 ) )
_vertexSizeBytesCache += SIZE_UV_5;
if ( hasAttribute ( UV_6 ) )
_vertexSizeBytesCache += SIZE_UV_6;
if ( hasAttribute ( UV_7 ) )
_vertexSizeBytesCache += SIZE_UV_7;
}
return _vertexSizeBytesCache;
}
///////////////////////////////////////////////////////////////////////////////
//
// This is called after the record is read.
//
///////////////////////////////////////////////////////////////////////////////
void LocalVertexPoolRecord::postReadInit()
{
// Initialize the attribute offsets.
this->_initAttributeOffsets();
// Call the base class's function.
AncillaryRecord::postReadInit();
}