Binary serialization in the .bullet file format (work-in-progress)

This commit is contained in:
erwin.coumans
2009-12-08 18:02:37 +00:00
parent 385c16e309
commit 3edd806b88
14 changed files with 1057 additions and 522 deletions

View File

@@ -830,7 +830,7 @@ unsigned int btQuantizedBvh::getAlignmentSerializationPadding()
return 0;//BVH_ALIGNMENT_BLOCKS * BVH_ALIGNMENT;
}
unsigned btQuantizedBvh::calculateSerializeBufferSize()
unsigned btQuantizedBvh::calculateSerializeBufferSize() const
{
unsigned baseSize = sizeof(btQuantizedBvh) + getAlignmentSerializationPadding();
baseSize += sizeof(btBvhSubtreeInfo) * m_subtreeHeaderCount;
@@ -841,7 +841,7 @@ unsigned btQuantizedBvh::calculateSerializeBufferSize()
return baseSize + m_curNodeIndex * sizeof(btOptimizedBvhNode);
}
bool btQuantizedBvh::serialize(void *o_alignedDataBuffer, unsigned /*i_dataBufferSize */, bool i_swapEndian)
bool btQuantizedBvh::serialize(void *o_alignedDataBuffer, unsigned /*i_dataBufferSize */, bool i_swapEndian) const
{
btAssert(m_subtreeHeaderCount == m_SubtreeHeaders.size());
m_subtreeHeaderCount = m_SubtreeHeaders.size();

View File

@@ -190,7 +190,7 @@ protected:
BvhSubtreeInfoArray m_SubtreeHeaders;
//This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray
int m_subtreeHeaderCount;
mutable int m_subtreeHeaderCount;
@@ -445,10 +445,10 @@ public:
/////Calculate space needed to store BVH for serialization
unsigned calculateSerializeBufferSize();
unsigned calculateSerializeBufferSize() const;
/// Data buffer MUST be 16 byte aligned
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian);
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const;
///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
static btQuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian);

View File

@@ -27,11 +27,11 @@ subject to the following restrictions:
struct btBroadphaseProxy;
class btCollisionShape;
struct btCollisionShapeData;
#include "LinearMath/btMotionState.h"
#include "LinearMath/btAlignedAllocator.h"
#include "LinearMath/btAlignedObjectArray.h"
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray;
@@ -54,7 +54,7 @@ protected:
btVector3 m_interpolationAngularVelocity;
btVector3 m_anisotropicFriction;
bool m_hasAnisotropicFriction;
int m_hasAnisotropicFriction;
btScalar m_contactProcessingThreshold;
btBroadphaseProxy* m_broadphaseHandle;
@@ -76,13 +76,13 @@ protected:
btScalar m_friction;
btScalar m_restitution;
///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer
void* m_userObjectPointer;
///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc.
///do not assign your own m_internalType unless you write a new dynamics object class.
int m_internalType;
///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer
void* m_userObjectPointer;
///time of impact calculation
btScalar m_hitFraction;
@@ -93,9 +93,7 @@ protected:
btScalar m_ccdMotionThreshold;
/// If some object should have elaborate collision filtering by sub-classes
bool m_checkCollideWith;
char m_pad[7];
int m_checkCollideWith;
virtual bool checkCollideWithOverride(btCollisionObject* /* co */)
{
@@ -143,7 +141,7 @@ public:
}
bool hasAnisotropicFriction() const
{
return m_hasAnisotropicFriction;
return m_hasAnisotropicFriction!=0;
}
///the constraint solver can discard solving contacts, if the distance is above this threshold. 0 by default.
@@ -416,6 +414,85 @@ public:
return true;
}
virtual int calculateSerializeBufferSize() const;
///fills the dataBuffer and returns the struct name (and 0 on failure)
virtual const char* serialize(void* dataBuffer) const;
};
///using offsetof for m_vtablePadding might break some compilers, in that case define m_vtablePadding manually
///for serialization
struct btCollisionObjectData
{
btTransformData m_worldTransform;
btTransformData m_interpolationWorldTransform;
btVector3Data m_interpolationLinearVelocity;
btVector3Data m_interpolationAngularVelocity;
btVector3Data m_anisotropicFriction;
int m_hasAnisotropicFriction;
btScalar m_contactProcessingThreshold;
void *m_broadphaseHandle;
void *m_collisionShape;
btCollisionShapeData *m_rootCollisionShape;
int m_collisionFlags;
int m_islandTag1;
int m_companionId;
int m_activationState1;
btScalar m_deactivationTime;
btScalar m_friction;
btScalar m_restitution;
int m_internalType;
void *m_userObjectPointer;
btScalar m_hitFraction;
btScalar m_ccdSweptSphereRadius;
btScalar m_ccdMotionThreshold;
int m_checkCollideWith;
};
SIMD_FORCE_INLINE int btCollisionObject::calculateSerializeBufferSize() const
{
return sizeof(btCollisionObjectData);
}
SIMD_FORCE_INLINE const char* btCollisionObject::serialize(void* dataBuffer) const
{
btCollisionObjectData* dataOut = (btCollisionObjectData*)dataBuffer;
m_worldTransform.serialize(dataOut->m_worldTransform);
m_interpolationWorldTransform.serialize(dataOut->m_interpolationWorldTransform);
m_interpolationLinearVelocity.serialize(dataOut->m_interpolationLinearVelocity);
m_interpolationAngularVelocity.serialize(dataOut->m_interpolationAngularVelocity);
m_anisotropicFriction.serialize(dataOut->m_anisotropicFriction);
dataOut->m_hasAnisotropicFriction = m_hasAnisotropicFriction;
dataOut->m_contactProcessingThreshold = m_contactProcessingThreshold;
dataOut->m_broadphaseHandle = 0;
dataOut->m_collisionShape = m_collisionShape; //@todo
dataOut->m_rootCollisionShape = 0;//@todo
dataOut->m_collisionFlags = m_collisionFlags;
dataOut->m_islandTag1 = m_islandTag1;
dataOut->m_companionId = m_companionId;
dataOut->m_activationState1 = m_activationState1;
dataOut->m_activationState1 = m_activationState1;
dataOut->m_deactivationTime = m_deactivationTime;
dataOut->m_friction = m_friction;
dataOut->m_restitution = m_restitution;
dataOut->m_internalType = m_internalType;
dataOut->m_userObjectPointer = m_userObjectPointer;
dataOut->m_hitFraction = m_hitFraction;
dataOut->m_ccdSweptSphereRadius = m_ccdSweptSphereRadius;
dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold;
dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold;
dataOut->m_checkCollideWith = m_checkCollideWith;
return "btCollisionObjectData";
}
#endif //COLLISION_OBJECT_H

View File

@@ -310,8 +310,41 @@ public:
}
}
virtual int calculateSerializeBufferSize();
///fills the dataBuffer and returns the struct name (and 0 on failure)
virtual const char* serialize(void* dataBuffer) const;
};
struct btBoxShapeData
{
btVector3Data m_halfExtents;
btVector3Data m_localScaling;
};
SIMD_FORCE_INLINE int btBoxShape::calculateSerializeBufferSize()
{
return sizeof(btBoxShapeData);
}
///fills the dataBuffer and returns the struct name (and 0 on failure)
SIMD_FORCE_INLINE const char* btBoxShape::serialize(void* dataBuffer) const
{
btBoxShapeData* boxData = (btBoxShapeData*) dataBuffer;
m_implicitShapeDimensions.serialize(boxData->m_halfExtents);
m_localScaling.serialize(boxData->m_localScaling);
return "btBoxShapeData";
}
#endif //OBB_BOX_MINKOWSKI_H

View File

@@ -21,6 +21,8 @@ subject to the following restrictions:
#include "LinearMath/btMatrix3x3.h"
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" //for the shape types
///The btCollisionShape class provides an interface for collision shapes that can be shared among btCollisionObjects.
class btCollisionShape
{
@@ -113,5 +115,14 @@ public:
};
///for serialization
struct btCollisionShapeData
{
void *m_userPointer;
int m_shapeType;
char m_padding[4];
};
#endif //COLLISION_SHAPE_H

View File

@@ -47,7 +47,7 @@ public:
void updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index);
/// Data buffer MUST be 16 byte aligned
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian)
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const
{
return btQuantizedBvh::serialize(o_alignedDataBuffer,i_dataBufferSize,i_swapEndian);

View File

@@ -29,6 +29,7 @@ SET(LinearMath_HDRS
btQuickprof.h
btRandom.h
btScalar.h
btSerializer.h
btStackAlloc.h
btTransform.h
btTransformUtil.h

View File

@@ -138,6 +138,16 @@ class btAlignedObjectArray
return m_size;
}
SIMD_FORCE_INLINE const T& at(int n) const
{
return m_data[n];
}
SIMD_FORCE_INLINE T& at(int n)
{
return m_data[n];
}
SIMD_FORCE_INLINE const T& operator[](int n) const
{
return m_data[n];

View File

@@ -1,6 +1,8 @@
#ifndef DEFAULT_MOTION_STATE_H
#define DEFAULT_MOTION_STATE_H
#include "btMotionState.h"
///The btDefaultMotionState provides a common implementation to synchronize world transforms with offsets.
struct btDefaultMotionState : public btMotionState
{

View File

@@ -95,14 +95,12 @@ public:
};
template <class Value>
class btHashKeyPtr
class btHashInt
{
int m_uid;
public:
btHashKeyPtr(int uid)
btHashInt(int uid)
:m_uid(uid)
{
}
@@ -112,11 +110,10 @@ public:
return m_uid;
}
bool equals(const btHashKeyPtr<Value>& other) const
bool equals(const btHashInt& other) const
{
return getUid1() == other.getUid1();
}
//to our success
SIMD_FORCE_INLINE unsigned int getHash()const
{
@@ -130,6 +127,46 @@ public:
key ^= (key >> 16);
return key;
}
};
class btHashKeyPtr
{
void* m_pointer;
public:
btHashKeyPtr(void* ptr)
:m_pointer(ptr)
{
}
const void* getPointer() const
{
return m_pointer;
}
bool equals(const btHashKeyPtr& other) const
{
return getPointer() == other.getPointer();
}
//to our success
SIMD_FORCE_INLINE unsigned int getHash()const
{
const bool VOID_IS_8 = ((sizeof(void*)==8));
int* intPtr = (int*)&m_pointer;
int key = VOID_IS_8? intPtr[0]+intPtr[1] : intPtr[0];
// Thomas Wang's hash
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
};

View File

@@ -13,10 +13,8 @@ subject to the following restrictions:
*/
#ifndef btMatrix3x3_H
#define btMatrix3x3_H
#include "btScalar.h"
#ifndef BT_MATRIX3x3_H
#define BT_MATRIX3x3_H
#include "btVector3.h"
#include "btQuaternion.h"
@@ -26,6 +24,10 @@ subject to the following restrictions:
/**@brief The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with btQuaternion, btTransform and btVector3.
* Make sure to only include a pure orthogonal matrix without scaling. */
class btMatrix3x3 {
///Data storage for the matrix, each vector is a row of the matrix
btVector3 m_el[3];
public:
/** @brief No initializaion constructor */
btMatrix3x3 () {}
@@ -290,7 +292,13 @@ class btMatrix3x3 {
* @param solution_number Which solution of two possible solutions ( 1 or 2) are possible values*/
void getEulerZYX(btScalar& yaw, btScalar& pitch, btScalar& roll, unsigned int solution_number = 1) const
{
struct Euler{btScalar yaw, pitch, roll;};
struct Euler
{
btScalar yaw;
btScalar pitch;
btScalar roll;
};
Euler euler_out;
Euler euler_out2; //second solution
//get the pointer to the raw data
@@ -475,7 +483,7 @@ class btMatrix3x3 {
protected:
/**@brief Calculate the matrix cofactor
* @param r1 The first row to use for calculating the cofactor
* @param c1 The first column to use for calculating the cofactor
@@ -487,10 +495,14 @@ class btMatrix3x3 {
{
return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1];
}
///Data storage for the matrix, each vector is a row of the matrix
btVector3 m_el[3];
virtual void serialize(struct btMatrix3x3Data& dataOut) const;
virtual void deSerialize(const struct btMatrix3x3Data& dataIn);
};
SIMD_FORCE_INLINE btMatrix3x3&
btMatrix3x3::operator*=(const btMatrix3x3& m)
{
@@ -615,4 +627,24 @@ SIMD_FORCE_INLINE bool operator==(const btMatrix3x3& m1, const btMatrix3x3& m2)
m1[0][2] == m2[0][2] && m1[1][2] == m2[1][2] && m1[2][2] == m2[2][2] );
}
#endif
///for serialization
struct btMatrix3x3Data
{
btVector3Data m_el[3];
};
SIMD_FORCE_INLINE void btMatrix3x3::serialize(struct btMatrix3x3Data& dataOut) const
{
for (int i=0;i<3;i++)
m_el[i].serialize(dataOut.m_el[i]);
}
SIMD_FORCE_INLINE void btMatrix3x3::deSerialize(const struct btMatrix3x3Data& dataIn)
{
for (int i=0;i<3;i++)
m_el[i].deSerialize(dataIn.m_el[i]);
}
#endif //BT_MATRIX3x3_H

View File

@@ -0,0 +1,288 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SERIALIZER_H
#define BT_SERIALIZER_H
#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE
#include "btStackAlloc.h"
class btChunk
{
public:
int m_chunkCode;
int m_length;
void *m_oldPtr;
int m_dna_nr;
int m_number;
};
///Allow to serialize data in a chunk format
class btSerializer
{
public:
virtual ~btSerializer() {}
virtual btChunk* allocate(size_t size,int numElements) = 0;
};
#define BT_HEADER_LENGTH 12
class btDefaultSerializer
{
public:
btAlignedObjectArray<char*> mTypes;
btAlignedObjectArray<short*> mStructs;
btAlignedObjectArray<short> mTlens;
btHashMap<btHashInt, int> mStructReverse;
btHashMap<btHashString,int> mTypeLookup;
btAlignedObjectArray<btChunk*> m_chunkPtrs;
int m_totalSize;
unsigned char* m_buffer;
int m_bufferPointer;
void* m_dna;
int m_dnaLength;
btDefaultSerializer(int totalSize)
:m_totalSize(totalSize),
m_bufferPointer(0)
// m_dna(0),
// m_dnaLength(0)
{
m_buffer = (unsigned char*)btAlignedAlloc(16,totalSize);
m_bufferPointer += BT_HEADER_LENGTH;
memcpy(m_buffer, "BULLET ", 7);
int endian= 1;
endian= ((char*)&endian)[0];
if (endian)
{
m_buffer[7] = '_';
} else
{
m_buffer[7] = '-';
}
if (sizeof(void*)==8)
{
m_buffer[8]='V';
} else
{
m_buffer[8]='v';
}
m_buffer[9] = '2';
m_buffer[10] = '7';
m_buffer[11] = '5';
}
virtual ~btDefaultSerializer()
{
btAlignedFree(m_buffer);
}
int getReverseType(const char *type) const
{
btHashString key(type);
const int* valuePtr = mTypeLookup.find(key);
if (valuePtr)
return *valuePtr;
return -1;
}
void writeDNA()
{
unsigned char* dnaTarget = m_buffer+m_bufferPointer;
memcpy(dnaTarget,m_dna,m_dnaLength);
m_bufferPointer += m_dnaLength;
}
virtual btChunk* allocate(size_t size, int numElements)
{
unsigned char* ptr = m_buffer+m_bufferPointer;
m_bufferPointer += size*numElements+sizeof(btChunk);
unsigned char* data = ptr + sizeof(btChunk);
btChunk* chunk = (btChunk*)ptr;
chunk->m_chunkCode = 0;
chunk->m_oldPtr = data;
chunk->m_length = size;
chunk->m_number = numElements;
m_chunkPtrs.push_back(chunk);
return chunk;
}
void initDNA(const char* bdna,int dnalen)
{
m_dna = btAlignedAlloc(dnalen,16);
memcpy(m_dna,bdna,dnalen);
m_dnaLength = dnalen;
int *intPtr=0;short *shtPtr=0;
char *cp = 0;int dataLen =0;long nr=0;
intPtr = (int*)bdna;
/*
SDNA (4 bytes) (magic number)
NAME (4 bytes)
<nr> (4 bytes) amount of names (int)
<string>
<string>
*/
if (strncmp((const char*)bdna, "SDNA", 4)==0)
{
// skip ++ NAME
intPtr++; intPtr++;
}
// Parse names
dataLen = *intPtr;
intPtr++;
cp = (char*)intPtr;
for (int i=0; i<dataLen; i++)
{
while (*cp)cp++;
cp++;
}
{
nr= (long)cp;
long mask=3;
nr= ((nr+3)&~3)-nr;
while (nr--)
{
cp++;
}
}
/*
TYPE (4 bytes)
<nr> amount of types (int)
<string>
<string>
*/
intPtr = (int*)cp;
assert(strncmp(cp, "TYPE", 4)==0); intPtr++;
dataLen = *intPtr;
intPtr++;
cp = (char*)intPtr;
for (int i=0; i<dataLen; i++)
{
mTypes.push_back(cp);
while (*cp)cp++;
cp++;
}
{
nr= (long)cp;
long mask=3;
nr= ((nr+3)&~3)-nr;
while (nr--)
{
cp++;
}
}
/*
TLEN (4 bytes)
<len> (short) the lengths of types
<len>
*/
// Parse type lens
intPtr = (int*)cp;
assert(strncmp(cp, "TLEN", 4)==0); intPtr++;
dataLen = (int)mTypes.size();
shtPtr = (short*)intPtr;
for (int i=0; i<dataLen; i++, shtPtr++)
{
mTlens.push_back(shtPtr[0]);
}
if (dataLen & 1) shtPtr++;
/*
STRC (4 bytes)
<nr> amount of structs (int)
<typenr>
<nr_of_elems>
<typenr>
<namenr>
<typenr>
<namenr>
*/
intPtr = (int*)shtPtr;
cp = (char*)intPtr;
assert(strncmp(cp, "STRC", 4)==0); intPtr++;
dataLen = *intPtr;
intPtr++;
shtPtr = (short*)intPtr;
for (int i=0; i<dataLen; i++)
{
mStructs.push_back (shtPtr);
shtPtr+= (2*shtPtr[1])+2;
}
// build reverse lookups
for (int i=0; i<(int)mStructs.size(); i++)
{
short *strc = mStructs.at(i);
mStructReverse.insert(strc[0], i);
mTypeLookup.insert(btHashString(mTypes[strc[0]]),i);
}
}
};
#endif //BT_SERIALIZER_H

View File

@@ -17,14 +17,19 @@ subject to the following restrictions:
#ifndef btTransform_H
#define btTransform_H
#include "btVector3.h"
#include "btMatrix3x3.h"
/**@brief The btTransform class supports rigid transforms with only translation and rotation and no scaling/shear.
*It can be used in combination with btVector3, btQuaternion and btMatrix3x3 linear algebra classes. */
class btTransform {
///Storage for the rotation
btMatrix3x3 m_basis;
///Storage for the translation
btVector3 m_origin;
public:
@@ -196,11 +201,10 @@ public:
return identityTransform;
}
private:
///Storage for the rotation
btMatrix3x3 m_basis;
///Storage for the translation
btVector3 m_origin;
virtual void serialize(struct btTransformData& dataOut) const;
virtual void deSerialize(const struct btTransformData& dataIn);
};
@@ -233,6 +237,24 @@ SIMD_FORCE_INLINE bool operator==(const btTransform& t1, const btTransform& t2)
t1.getOrigin() == t2.getOrigin() );
}
///for serialization
struct btTransformData
{
btMatrix3x3Data m_basis;
btVector3Data m_origin;
};
SIMD_FORCE_INLINE void btTransform::serialize(btTransformData& dataOut) const
{
m_basis.serialize(dataOut.m_basis);
m_origin.serialize(dataOut.m_origin);
}
SIMD_FORCE_INLINE void btTransform::deSerialize(const btTransformData& dataIn)
{
m_basis.deSerialize(dataIn.m_basis);
m_origin.deSerialize(dataIn.m_origin);
}
#endif

View File

@@ -18,14 +18,16 @@ subject to the following restrictions:
#define SIMD__VECTOR3_H
#include "btScalar.h"
#include "btScalar.h"
#include "btMinMax.h"
/**@brief btVector3 can be used to represent 3D points and vectors.
* It has an un-used w component to suit 16-byte alignment when btVector3 is stored in containers. This extra component can be used by derived classes (Quaternion?) or by user
* Ideally, this class should be replaced by a platform optimized SIMD version that keeps the data in registers
*/
ATTRIBUTE_ALIGNED16(class) btVector3
{
public:
@@ -318,6 +320,9 @@ public:
setValue(btScalar(0.),btScalar(0.),btScalar(0.));
}
SIMD_FORCE_INLINE void serialize(struct btVector3Data& dataOut) const;
SIMD_FORCE_INLINE void deSerialize(const struct btVector3Data& dataIn);
};
/**@brief Return the sum of two vectors (Point symantics)*/
@@ -587,8 +592,6 @@ public:
}
};
@@ -657,4 +660,23 @@ SIMD_FORCE_INLINE void btPlaneSpace1 (const btVector3& n, btVector3& p, btVector
}
}
struct btVector3Data
{
btScalar m_floats[4];
};
SIMD_FORCE_INLINE void btVector3::serialize(struct btVector3Data& dataOut) const
{
///could also do a memcpy, check if it is worth it
for (int i=0;i<4;i++)
dataOut.m_floats[i] = m_floats[i];
}
SIMD_FORCE_INLINE void btVector3::deSerialize(const struct btVector3Data& dataIn)
{
for (int i=0;i<4;i++)
m_floats[i] = dataIn.m_floats[i];
}
#endif //SIMD__VECTOR3_H