640 lines
13 KiB
C++
640 lines
13 KiB
C++
/*
|
|
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 "btHashMap.h"
|
|
|
|
#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__)
|
|
#include <memory.h>
|
|
#endif
|
|
#include <string.h>
|
|
|
|
|
|
|
|
///only the 32bit versions for now
|
|
extern char sBulletDNAstr[];
|
|
extern int sBulletDNAlen;
|
|
extern char sBulletDNAstr64[];
|
|
extern int sBulletDNAlen64;
|
|
|
|
SIMD_FORCE_INLINE int btStrLen(const char* str)
|
|
{
|
|
if (!str)
|
|
return(0);
|
|
int len = 0;
|
|
|
|
while (*str != 0)
|
|
{
|
|
str++;
|
|
len++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
class btChunk
|
|
{
|
|
public:
|
|
int m_chunkCode;
|
|
int m_length;
|
|
void *m_oldPtr;
|
|
int m_dna_nr;
|
|
int m_number;
|
|
};
|
|
|
|
enum btSerializationFlags
|
|
{
|
|
BT_SERIALIZE_NO_BVH = 1,
|
|
BT_SERIALIZE_NO_TRIANGLEINFOMAP = 2,
|
|
BT_SERIALIZE_NO_DUPLICATE_ASSERT = 4
|
|
};
|
|
|
|
class btSerializer
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~btSerializer() {}
|
|
|
|
virtual const unsigned char* getBufferPointer() const = 0;
|
|
|
|
virtual int getCurrentBufferSize() const = 0;
|
|
|
|
virtual btChunk* allocate(size_t size, int numElements) = 0;
|
|
|
|
virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)= 0;
|
|
|
|
virtual void* findPointer(void* oldPtr) = 0;
|
|
|
|
virtual void* getUniquePointer(void*oldPtr) = 0;
|
|
|
|
virtual void startSerialization() = 0;
|
|
|
|
virtual void finishSerialization() = 0;
|
|
|
|
virtual const char* findNameForPointer(const void* ptr) const = 0;
|
|
|
|
virtual void registerNameForPointer(const void* ptr, const char* name) = 0;
|
|
|
|
virtual void serializeName(const char* ptr) = 0;
|
|
|
|
virtual int getSerializationFlags() const = 0;
|
|
|
|
virtual void setSerializationFlags(int flags) = 0;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#define BT_HEADER_LENGTH 12
|
|
#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
|
|
# define BT_MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
|
|
#else
|
|
# define BT_MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
|
|
#endif
|
|
|
|
#define BT_SOFTBODY_CODE BT_MAKE_ID('S','B','D','Y')
|
|
#define BT_COLLISIONOBJECT_CODE BT_MAKE_ID('C','O','B','J')
|
|
#define BT_RIGIDBODY_CODE BT_MAKE_ID('R','B','D','Y')
|
|
#define BT_CONSTRAINT_CODE BT_MAKE_ID('C','O','N','S')
|
|
#define BT_BOXSHAPE_CODE BT_MAKE_ID('B','O','X','S')
|
|
#define BT_QUANTIZED_BVH_CODE BT_MAKE_ID('Q','B','V','H')
|
|
#define BT_TRIANLGE_INFO_MAP BT_MAKE_ID('T','M','A','P')
|
|
#define BT_SHAPE_CODE BT_MAKE_ID('S','H','A','P')
|
|
#define BT_ARRAY_CODE BT_MAKE_ID('A','R','A','Y')
|
|
#define BT_SBMATERIAL_CODE BT_MAKE_ID('S','B','M','T')
|
|
#define BT_SBNODE_CODE BT_MAKE_ID('S','B','N','D')
|
|
#define BT_DYNAMICSWORLD_CODE BT_MAKE_ID('D','W','L','D')
|
|
#define BT_DNA_CODE BT_MAKE_ID('D','N','A','1')
|
|
|
|
|
|
struct btPointerUid
|
|
{
|
|
union
|
|
{
|
|
void* m_ptr;
|
|
int m_uniqueIds[2];
|
|
};
|
|
};
|
|
|
|
///The btDefaultSerializer is the main Bullet serialization class.
|
|
///The constructor takes an optional argument for backwards compatibility, it is recommended to leave this empty/zero.
|
|
class btDefaultSerializer : public btSerializer
|
|
{
|
|
|
|
|
|
btAlignedObjectArray<char*> mTypes;
|
|
btAlignedObjectArray<short*> mStructs;
|
|
btAlignedObjectArray<short> mTlens;
|
|
btHashMap<btHashInt, int> mStructReverse;
|
|
btHashMap<btHashString,int> mTypeLookup;
|
|
|
|
|
|
btHashMap<btHashPtr,void*> m_chunkP;
|
|
|
|
btHashMap<btHashPtr,const char*> m_nameMap;
|
|
|
|
btHashMap<btHashPtr,btPointerUid> m_uniquePointers;
|
|
int m_uniqueIdGenerator;
|
|
|
|
int m_totalSize;
|
|
unsigned char* m_buffer;
|
|
int m_currentSize;
|
|
void* m_dna;
|
|
int m_dnaLength;
|
|
|
|
int m_serializationFlags;
|
|
|
|
|
|
btAlignedObjectArray<btChunk*> m_chunkPtrs;
|
|
|
|
protected:
|
|
|
|
virtual void* findPointer(void* oldPtr)
|
|
{
|
|
void** ptr = m_chunkP.find(oldPtr);
|
|
if (ptr && *ptr)
|
|
return *ptr;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void writeDNA()
|
|
{
|
|
btChunk* dnaChunk = allocate(m_dnaLength,1);
|
|
memcpy(dnaChunk->m_oldPtr,m_dna,m_dnaLength);
|
|
finalizeChunk(dnaChunk,"DNA1",BT_DNA_CODE, m_dna);
|
|
}
|
|
|
|
int getReverseType(const char *type) const
|
|
{
|
|
|
|
btHashString key(type);
|
|
const int* valuePtr = mTypeLookup.find(key);
|
|
if (valuePtr)
|
|
return *valuePtr;
|
|
|
|
return -1;
|
|
}
|
|
|
|
void initDNA(const char* bdnaOrg,int dnalen)
|
|
{
|
|
///was already initialized
|
|
if (m_dna)
|
|
return;
|
|
|
|
int littleEndian= 1;
|
|
littleEndian= ((char*)&littleEndian)[0];
|
|
|
|
|
|
m_dna = btAlignedAlloc(dnalen,16);
|
|
memcpy(m_dna,bdnaOrg,dnalen);
|
|
m_dnaLength = dnalen;
|
|
|
|
int *intPtr=0;
|
|
short *shtPtr=0;
|
|
char *cp = 0;int dataLen =0;
|
|
intPtr = (int*)m_dna;
|
|
|
|
/*
|
|
SDNA (4 bytes) (magic number)
|
|
NAME (4 bytes)
|
|
<nr> (4 bytes) amount of names (int)
|
|
<string>
|
|
<string>
|
|
*/
|
|
|
|
if (strncmp((const char*)m_dna, "SDNA", 4)==0)
|
|
{
|
|
// skip ++ NAME
|
|
intPtr++; intPtr++;
|
|
}
|
|
|
|
// Parse names
|
|
if (!littleEndian)
|
|
*intPtr = btSwapEndian(*intPtr);
|
|
|
|
dataLen = *intPtr;
|
|
|
|
intPtr++;
|
|
|
|
cp = (char*)intPtr;
|
|
int i;
|
|
for ( i=0; i<dataLen; i++)
|
|
{
|
|
|
|
while (*cp)cp++;
|
|
cp++;
|
|
}
|
|
cp = btAlignPointer(cp,4);
|
|
|
|
/*
|
|
TYPE (4 bytes)
|
|
<nr> amount of types (int)
|
|
<string>
|
|
<string>
|
|
*/
|
|
|
|
intPtr = (int*)cp;
|
|
btAssert(strncmp(cp, "TYPE", 4)==0); intPtr++;
|
|
|
|
if (!littleEndian)
|
|
*intPtr = btSwapEndian(*intPtr);
|
|
|
|
dataLen = *intPtr;
|
|
intPtr++;
|
|
|
|
|
|
cp = (char*)intPtr;
|
|
for (i=0; i<dataLen; i++)
|
|
{
|
|
mTypes.push_back(cp);
|
|
while (*cp)cp++;
|
|
cp++;
|
|
}
|
|
|
|
cp = btAlignPointer(cp,4);
|
|
|
|
|
|
/*
|
|
TLEN (4 bytes)
|
|
<len> (short) the lengths of types
|
|
<len>
|
|
*/
|
|
|
|
// Parse type lens
|
|
intPtr = (int*)cp;
|
|
btAssert(strncmp(cp, "TLEN", 4)==0); intPtr++;
|
|
|
|
dataLen = (int)mTypes.size();
|
|
|
|
shtPtr = (short*)intPtr;
|
|
for (i=0; i<dataLen; i++, shtPtr++)
|
|
{
|
|
if (!littleEndian)
|
|
shtPtr[0] = btSwapEndian(shtPtr[0]);
|
|
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;
|
|
btAssert(strncmp(cp, "STRC", 4)==0); intPtr++;
|
|
|
|
if (!littleEndian)
|
|
*intPtr = btSwapEndian(*intPtr);
|
|
dataLen = *intPtr ;
|
|
intPtr++;
|
|
|
|
|
|
shtPtr = (short*)intPtr;
|
|
for (i=0; i<dataLen; i++)
|
|
{
|
|
mStructs.push_back (shtPtr);
|
|
|
|
if (!littleEndian)
|
|
{
|
|
shtPtr[0]= btSwapEndian(shtPtr[0]);
|
|
shtPtr[1]= btSwapEndian(shtPtr[1]);
|
|
|
|
int len = shtPtr[1];
|
|
shtPtr+= 2;
|
|
|
|
for (int a=0; a<len; a++, shtPtr+=2)
|
|
{
|
|
shtPtr[0]= btSwapEndian(shtPtr[0]);
|
|
shtPtr[1]= btSwapEndian(shtPtr[1]);
|
|
}
|
|
|
|
} else
|
|
{
|
|
shtPtr+= (2*shtPtr[1])+2;
|
|
}
|
|
}
|
|
|
|
// build reverse lookups
|
|
for (i=0; i<(int)mStructs.size(); i++)
|
|
{
|
|
short *strc = mStructs.at(i);
|
|
mStructReverse.insert(strc[0], i);
|
|
mTypeLookup.insert(btHashString(mTypes[strc[0]]),i);
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
btDefaultSerializer(int totalSize=0)
|
|
:m_totalSize(totalSize),
|
|
m_currentSize(0),
|
|
m_dna(0),
|
|
m_dnaLength(0),
|
|
m_serializationFlags(0)
|
|
{
|
|
m_buffer = m_totalSize?(unsigned char*)btAlignedAlloc(totalSize,16):0;
|
|
|
|
const bool VOID_IS_8 = ((sizeof(void*)==8));
|
|
|
|
#ifdef BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
|
|
if (VOID_IS_8)
|
|
{
|
|
#if _WIN64
|
|
initDNA((const char*)sBulletDNAstr64,sBulletDNAlen64);
|
|
#else
|
|
btAssert(0);
|
|
#endif
|
|
} else
|
|
{
|
|
#ifndef _WIN64
|
|
initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
|
|
#else
|
|
btAssert(0);
|
|
#endif
|
|
}
|
|
|
|
#else //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
|
|
if (VOID_IS_8)
|
|
{
|
|
initDNA((const char*)sBulletDNAstr64,sBulletDNAlen64);
|
|
} else
|
|
{
|
|
initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
|
|
}
|
|
#endif //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
|
|
|
|
}
|
|
|
|
virtual ~btDefaultSerializer()
|
|
{
|
|
if (m_buffer)
|
|
btAlignedFree(m_buffer);
|
|
if (m_dna)
|
|
btAlignedFree(m_dna);
|
|
}
|
|
|
|
void writeHeader(unsigned char* buffer) const
|
|
{
|
|
|
|
|
|
#ifdef BT_USE_DOUBLE_PRECISION
|
|
memcpy(buffer, "BULLETd", 7);
|
|
#else
|
|
memcpy(buffer, "BULLETf", 7);
|
|
#endif //BT_USE_DOUBLE_PRECISION
|
|
|
|
int littleEndian= 1;
|
|
littleEndian= ((char*)&littleEndian)[0];
|
|
|
|
if (sizeof(void*)==8)
|
|
{
|
|
buffer[7] = '-';
|
|
} else
|
|
{
|
|
buffer[7] = '_';
|
|
}
|
|
|
|
if (littleEndian)
|
|
{
|
|
buffer[8]='v';
|
|
} else
|
|
{
|
|
buffer[8]='V';
|
|
}
|
|
|
|
|
|
buffer[9] = '2';
|
|
buffer[10] = '8';
|
|
buffer[11] = '2';
|
|
|
|
}
|
|
|
|
virtual void startSerialization()
|
|
{
|
|
m_uniqueIdGenerator= 1;
|
|
if (m_totalSize)
|
|
{
|
|
unsigned char* buffer = internalAlloc(BT_HEADER_LENGTH);
|
|
writeHeader(buffer);
|
|
}
|
|
|
|
}
|
|
|
|
virtual void finishSerialization()
|
|
{
|
|
writeDNA();
|
|
|
|
//if we didn't pre-allocate a buffer, we need to create a contiguous buffer now
|
|
int mysize = 0;
|
|
if (!m_totalSize)
|
|
{
|
|
if (m_buffer)
|
|
btAlignedFree(m_buffer);
|
|
|
|
m_currentSize += BT_HEADER_LENGTH;
|
|
m_buffer = (unsigned char*)btAlignedAlloc(m_currentSize,16);
|
|
|
|
unsigned char* currentPtr = m_buffer;
|
|
writeHeader(m_buffer);
|
|
currentPtr += BT_HEADER_LENGTH;
|
|
mysize+=BT_HEADER_LENGTH;
|
|
for (int i=0;i< m_chunkPtrs.size();i++)
|
|
{
|
|
int curLength = sizeof(btChunk)+m_chunkPtrs[i]->m_length;
|
|
memcpy(currentPtr,m_chunkPtrs[i], curLength);
|
|
btAlignedFree(m_chunkPtrs[i]);
|
|
currentPtr+=curLength;
|
|
mysize+=curLength;
|
|
}
|
|
}
|
|
|
|
mTypes.clear();
|
|
mStructs.clear();
|
|
mTlens.clear();
|
|
mStructReverse.clear();
|
|
mTypeLookup.clear();
|
|
m_chunkP.clear();
|
|
m_nameMap.clear();
|
|
m_uniquePointers.clear();
|
|
m_chunkPtrs.clear();
|
|
}
|
|
|
|
virtual void* getUniquePointer(void*oldPtr)
|
|
{
|
|
if (!oldPtr)
|
|
return 0;
|
|
|
|
btPointerUid* uptr = (btPointerUid*)m_uniquePointers.find(oldPtr);
|
|
if (uptr)
|
|
{
|
|
return uptr->m_ptr;
|
|
}
|
|
m_uniqueIdGenerator++;
|
|
|
|
btPointerUid uid;
|
|
uid.m_uniqueIds[0] = m_uniqueIdGenerator;
|
|
uid.m_uniqueIds[1] = m_uniqueIdGenerator;
|
|
m_uniquePointers.insert(oldPtr,uid);
|
|
return uid.m_ptr;
|
|
|
|
}
|
|
|
|
virtual const unsigned char* getBufferPointer() const
|
|
{
|
|
return m_buffer;
|
|
}
|
|
|
|
virtual int getCurrentBufferSize() const
|
|
{
|
|
return m_currentSize;
|
|
}
|
|
|
|
virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)
|
|
{
|
|
if (!(m_serializationFlags&BT_SERIALIZE_NO_DUPLICATE_ASSERT))
|
|
{
|
|
btAssert(!findPointer(oldPtr));
|
|
}
|
|
|
|
chunk->m_dna_nr = getReverseType(structType);
|
|
|
|
chunk->m_chunkCode = chunkCode;
|
|
|
|
void* uniquePtr = getUniquePointer(oldPtr);
|
|
|
|
m_chunkP.insert(oldPtr,uniquePtr);//chunk->m_oldPtr);
|
|
chunk->m_oldPtr = uniquePtr;//oldPtr;
|
|
|
|
}
|
|
|
|
|
|
virtual unsigned char* internalAlloc(size_t size)
|
|
{
|
|
unsigned char* ptr = 0;
|
|
|
|
if (m_totalSize)
|
|
{
|
|
ptr = m_buffer+m_currentSize;
|
|
m_currentSize += int(size);
|
|
btAssert(m_currentSize<m_totalSize);
|
|
} else
|
|
{
|
|
ptr = (unsigned char*)btAlignedAlloc(size,16);
|
|
m_currentSize += int(size);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
|
|
|
|
virtual btChunk* allocate(size_t size, int numElements)
|
|
{
|
|
|
|
unsigned char* ptr = internalAlloc(int(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 = int(size)*numElements;
|
|
chunk->m_number = numElements;
|
|
|
|
m_chunkPtrs.push_back(chunk);
|
|
|
|
|
|
return chunk;
|
|
}
|
|
|
|
virtual const char* findNameForPointer(const void* ptr) const
|
|
{
|
|
const char*const * namePtr = m_nameMap.find(ptr);
|
|
if (namePtr && *namePtr)
|
|
return *namePtr;
|
|
return 0;
|
|
|
|
}
|
|
|
|
virtual void registerNameForPointer(const void* ptr, const char* name)
|
|
{
|
|
m_nameMap.insert(ptr,name);
|
|
}
|
|
|
|
virtual void serializeName(const char* name)
|
|
{
|
|
if (name)
|
|
{
|
|
//don't serialize name twice
|
|
if (findPointer((void*)name))
|
|
return;
|
|
|
|
int len = btStrLen(name);
|
|
if (len)
|
|
{
|
|
|
|
int newLen = len+1;
|
|
int padding = ((newLen+3)&~3)-newLen;
|
|
newLen += padding;
|
|
|
|
//serialize name string now
|
|
btChunk* chunk = allocate(sizeof(char),newLen);
|
|
char* destinationName = (char*)chunk->m_oldPtr;
|
|
for (int i=0;i<len;i++)
|
|
{
|
|
destinationName[i] = name[i];
|
|
}
|
|
destinationName[len] = 0;
|
|
finalizeChunk(chunk,"char",BT_ARRAY_CODE,(void*)name);
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual int getSerializationFlags() const
|
|
{
|
|
return m_serializationFlags;
|
|
}
|
|
|
|
virtual void setSerializationFlags(int flags)
|
|
{
|
|
m_serializationFlags = flags;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
#endif //BT_SERIALIZER_H
|
|
|