909 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			909 lines
		
	
	
		
			20 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>
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	virtual int getNumChunks() const = 0;
 | 
						|
 | 
						|
	virtual const btChunk* getChunk(int chunkIndex) const = 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_MULTIBODY_CODE       BT_MAKE_ID('M','B','D','Y')
 | 
						|
#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];
 | 
						|
	};
 | 
						|
};
 | 
						|
 | 
						|
struct btBulletSerializedArrays
 | 
						|
{
 | 
						|
	btBulletSerializedArrays()
 | 
						|
	{
 | 
						|
	}
 | 
						|
	btAlignedObjectArray<struct btQuantizedBvhDoubleData*>	m_bvhsDouble;
 | 
						|
	btAlignedObjectArray<struct btQuantizedBvhFloatData*>	m_bvhsFloat;
 | 
						|
	btAlignedObjectArray<struct btCollisionShapeData*> m_colShapeData;
 | 
						|
	btAlignedObjectArray<struct btDynamicsWorldDoubleData*> m_dynamicWorldInfoDataDouble;
 | 
						|
	btAlignedObjectArray<struct btDynamicsWorldFloatData*> m_dynamicWorldInfoDataFloat;
 | 
						|
	btAlignedObjectArray<struct btRigidBodyDoubleData*> m_rigidBodyDataDouble;
 | 
						|
	btAlignedObjectArray<struct btRigidBodyFloatData*> m_rigidBodyDataFloat;
 | 
						|
	btAlignedObjectArray<struct btCollisionObjectDoubleData*> m_collisionObjectDataDouble;
 | 
						|
	btAlignedObjectArray<struct btCollisionObjectFloatData*> m_collisionObjectDataFloat;
 | 
						|
	btAlignedObjectArray<struct btTypedConstraintFloatData*> m_constraintDataFloat;
 | 
						|
	btAlignedObjectArray<struct btTypedConstraintDoubleData*> m_constraintDataDouble;
 | 
						|
	btAlignedObjectArray<struct btTypedConstraintData*> m_constraintData;//for backwards compatibility
 | 
						|
	btAlignedObjectArray<struct btSoftBodyFloatData*> m_softBodyFloatData;
 | 
						|
	btAlignedObjectArray<struct btSoftBodyDoubleData*> m_softBodyDoubleData;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
///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
 | 
						|
{
 | 
						|
 | 
						|
protected:
 | 
						|
 | 
						|
	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;
 | 
						|
	bool                m_ownsBuffer;
 | 
						|
	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;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
		virtual 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:
 | 
						|
 | 
						|
	btHashMap<btHashPtr,void*> m_skipPointers;
 | 
						|
 | 
						|
 | 
						|
		btDefaultSerializer(int totalSize=0, unsigned char*	buffer=0)
 | 
						|
			:m_uniqueIdGenerator(0),
 | 
						|
			m_totalSize(totalSize),
 | 
						|
			m_currentSize(0),
 | 
						|
			m_dna(0),
 | 
						|
			m_dnaLength(0),
 | 
						|
			m_serializationFlags(0)
 | 
						|
		{
 | 
						|
		    if (buffer==0)
 | 
						|
            {
 | 
						|
                m_buffer = m_totalSize?(unsigned char*)btAlignedAlloc(totalSize,16):0;
 | 
						|
                m_ownsBuffer = true;
 | 
						|
            } else
 | 
						|
            {
 | 
						|
                m_buffer = buffer;
 | 
						|
                m_ownsBuffer = false;
 | 
						|
            }
 | 
						|
 | 
						|
			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 && m_ownsBuffer)
 | 
						|
				btAlignedFree(m_buffer);
 | 
						|
			if (m_dna)
 | 
						|
				btAlignedFree(m_dna);
 | 
						|
		}
 | 
						|
 | 
						|
		static int getMemoryDnaSizeInBytes()
 | 
						|
		{
 | 
						|
			const bool VOID_IS_8 = ((sizeof(void*) == 8));
 | 
						|
 | 
						|
			if (VOID_IS_8)
 | 
						|
			{
 | 
						|
				return sBulletDNAlen64;
 | 
						|
			}
 | 
						|
			return sBulletDNAlen;
 | 
						|
		}
 | 
						|
		static const char* getMemoryDna()
 | 
						|
		{
 | 
						|
			const bool VOID_IS_8 = ((sizeof(void*) == 8));
 | 
						|
			if (VOID_IS_8)
 | 
						|
			{
 | 
						|
				return (const char*)sBulletDNAstr64;
 | 
						|
			}
 | 
						|
			return (const char*)sBulletDNAstr;
 | 
						|
		}
 | 
						|
 | 
						|
		void	insertHeader()
 | 
						|
		{
 | 
						|
			writeHeader(m_buffer);
 | 
						|
			m_currentSize += BT_HEADER_LENGTH;
 | 
						|
		}
 | 
						|
 | 
						|
		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] = '7';
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
		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_skipPointers.clear();
 | 
						|
			m_chunkP.clear();
 | 
						|
			m_nameMap.clear();
 | 
						|
			m_uniquePointers.clear();
 | 
						|
			m_chunkPtrs.clear();
 | 
						|
		}
 | 
						|
 | 
						|
		virtual	void*	getUniquePointer(void*oldPtr)
 | 
						|
		{
 | 
						|
			btAssert(m_uniqueIdGenerator >= 0);
 | 
						|
			if (!oldPtr)
 | 
						|
				return 0;
 | 
						|
 | 
						|
			btPointerUid* uptr = (btPointerUid*)m_uniquePointers.find(oldPtr);
 | 
						|
			if (uptr)
 | 
						|
			{
 | 
						|
				return uptr->m_ptr;
 | 
						|
			}
 | 
						|
 | 
						|
			void** ptr2 = m_skipPointers[oldPtr];
 | 
						|
            if (ptr2)
 | 
						|
			{
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
 | 
						|
			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;
 | 
						|
		}
 | 
						|
		int getNumChunks() const
 | 
						|
		{
 | 
						|
			return m_chunkPtrs.size();
 | 
						|
		}
 | 
						|
 | 
						|
		const btChunk* getChunk(int chunkIndex) const
 | 
						|
		{
 | 
						|
			return m_chunkPtrs[chunkIndex];
 | 
						|
		}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
///In general it is best to use btDefaultSerializer,
 | 
						|
///in particular when writing the data to disk or sending it over the network.
 | 
						|
///The btInMemorySerializer is experimental and only suitable in a few cases.
 | 
						|
///The btInMemorySerializer takes a shortcut and can be useful to create a deep-copy
 | 
						|
///of objects. There will be a demo on how to use the btInMemorySerializer.
 | 
						|
#ifdef ENABLE_INMEMORY_SERIALIZER
 | 
						|
 | 
						|
struct btInMemorySerializer : public btDefaultSerializer
 | 
						|
{
 | 
						|
    btHashMap<btHashPtr,btChunk*> m_uid2ChunkPtr;
 | 
						|
    btHashMap<btHashPtr,void*> m_orgPtr2UniqueDataPtr;
 | 
						|
    btHashMap<btHashString,const void*> m_names2Ptr;
 | 
						|
    
 | 
						|
 | 
						|
    btBulletSerializedArrays    m_arrays;
 | 
						|
 | 
						|
    btInMemorySerializer(int totalSize=0, unsigned char*	buffer=0)
 | 
						|
    :btDefaultSerializer(totalSize,buffer)
 | 
						|
    {
 | 
						|
        
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void startSerialization()
 | 
						|
    {
 | 
						|
        m_uid2ChunkPtr.clear();
 | 
						|
        //todo: m_arrays.clear();
 | 
						|
        btDefaultSerializer::startSerialization();
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
 | 
						|
    btChunk* findChunkFromUniquePointer(void* uniquePointer)
 | 
						|
    {
 | 
						|
        btChunk** chkPtr = m_uid2ChunkPtr[uniquePointer];
 | 
						|
        if (chkPtr)
 | 
						|
        {
 | 
						|
            return *chkPtr;
 | 
						|
        }
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
	virtual	void	registerNameForPointer(const void* ptr, const char* name)
 | 
						|
    {
 | 
						|
       btDefaultSerializer::registerNameForPointer(ptr,name);
 | 
						|
       m_names2Ptr.insert(name,ptr);
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void finishSerialization()
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void* getUniquePointer(void*oldPtr)
 | 
						|
    {
 | 
						|
        if (oldPtr==0)
 | 
						|
            return 0;
 | 
						|
 | 
						|
        // void* uniquePtr = getUniquePointer(oldPtr);
 | 
						|
        btChunk* chunk = findChunkFromUniquePointer(oldPtr);
 | 
						|
        if (chunk)
 | 
						|
        {
 | 
						|
            return chunk->m_oldPtr;
 | 
						|
        } else
 | 
						|
        {
 | 
						|
            const char* n = (const char*) oldPtr;
 | 
						|
            const void** ptr = m_names2Ptr[n];
 | 
						|
            if (ptr)
 | 
						|
            {
 | 
						|
                return oldPtr;
 | 
						|
            } else
 | 
						|
            {
 | 
						|
            		void** ptr2 = m_skipPointers[oldPtr];
 | 
						|
            		if (ptr2)
 | 
						|
								{
 | 
						|
									return 0;
 | 
						|
								} else
 | 
						|
								{
 | 
						|
									//If this assert hit, serialization happened in the wrong order
 | 
						|
									// 'getUniquePointer'
 | 
						|
									btAssert(0);
 | 
						|
								}
 | 
						|
 | 
						|
            }
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
				return oldPtr;
 | 
						|
    }
 | 
						|
 | 
						|
    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,oldPtr);//chunk->m_oldPtr);
 | 
						|
        // chunk->m_oldPtr = uniquePtr;//oldPtr;
 | 
						|
 | 
						|
        void* uid = findPointer(oldPtr);
 | 
						|
        m_uid2ChunkPtr.insert(uid,chunk);
 | 
						|
 | 
						|
        switch (chunk->m_chunkCode)
 | 
						|
			{
 | 
						|
			case BT_SOFTBODY_CODE:
 | 
						|
			{
 | 
						|
	#ifdef BT_USE_DOUBLE_PRECISION
 | 
						|
					m_arrays.m_softBodyDoubleData.push_back((btSoftBodyDoubleData*) chunk->m_oldPtr);
 | 
						|
	#else
 | 
						|
					m_arrays.m_softBodyFloatData.push_back((btSoftBodyFloatData*) chunk->m_oldPtr);
 | 
						|
	#endif
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			case BT_COLLISIONOBJECT_CODE:
 | 
						|
				{
 | 
						|
	#ifdef BT_USE_DOUBLE_PRECISION
 | 
						|
					m_arrays.m_collisionObjectDataDouble.push_back((btCollisionObjectDoubleData*)chunk->m_oldPtr);
 | 
						|
	#else//BT_USE_DOUBLE_PRECISION
 | 
						|
					m_arrays.m_collisionObjectDataFloat.push_back((btCollisionObjectFloatData*)chunk->m_oldPtr);
 | 
						|
	#endif //BT_USE_DOUBLE_PRECISION
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			case BT_RIGIDBODY_CODE:
 | 
						|
				{
 | 
						|
	#ifdef BT_USE_DOUBLE_PRECISION
 | 
						|
					m_arrays.m_rigidBodyDataDouble.push_back((btRigidBodyDoubleData*)chunk->m_oldPtr);
 | 
						|
	#else
 | 
						|
					m_arrays.m_rigidBodyDataFloat.push_back((btRigidBodyFloatData*)chunk->m_oldPtr);
 | 
						|
	#endif//BT_USE_DOUBLE_PRECISION
 | 
						|
					break;
 | 
						|
				};
 | 
						|
			case BT_CONSTRAINT_CODE:
 | 
						|
				{
 | 
						|
	#ifdef BT_USE_DOUBLE_PRECISION
 | 
						|
					m_arrays.m_constraintDataDouble.push_back((btTypedConstraintDoubleData*)chunk->m_oldPtr);
 | 
						|
	#else
 | 
						|
					m_arrays.m_constraintDataFloat.push_back((btTypedConstraintFloatData*)chunk->m_oldPtr);
 | 
						|
	#endif
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			case BT_QUANTIZED_BVH_CODE:
 | 
						|
				{
 | 
						|
	#ifdef BT_USE_DOUBLE_PRECISION
 | 
						|
					m_arrays.m_bvhsDouble.push_back((btQuantizedBvhDoubleData*) chunk->m_oldPtr);
 | 
						|
	#else
 | 
						|
					m_arrays.m_bvhsFloat.push_back((btQuantizedBvhFloatData*) chunk->m_oldPtr);
 | 
						|
	#endif
 | 
						|
					break;
 | 
						|
				}
 | 
						|
 | 
						|
			case BT_SHAPE_CODE:
 | 
						|
				{
 | 
						|
					btCollisionShapeData* shapeData = (btCollisionShapeData*) chunk->m_oldPtr;
 | 
						|
					m_arrays.m_colShapeData.push_back(shapeData);
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			case BT_TRIANLGE_INFO_MAP:
 | 
						|
			case BT_ARRAY_CODE:
 | 
						|
			case BT_SBMATERIAL_CODE:
 | 
						|
			case BT_SBNODE_CODE:
 | 
						|
			case BT_DYNAMICSWORLD_CODE:
 | 
						|
			case BT_DNA_CODE:
 | 
						|
				{
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			default:
 | 
						|
				{
 | 
						|
				}
 | 
						|
			};
 | 
						|
    }
 | 
						|
 | 
						|
    int getNumChunks() const
 | 
						|
    {
 | 
						|
        return m_uid2ChunkPtr.size();
 | 
						|
    }
 | 
						|
 | 
						|
    const btChunk* getChunk(int chunkIndex) const
 | 
						|
    {
 | 
						|
        return *m_uid2ChunkPtr.getAtIndex(chunkIndex);
 | 
						|
    }
 | 
						|
 | 
						|
};
 | 
						|
#endif //ENABLE_INMEMORY_SERIALIZER
 | 
						|
 | 
						|
#endif //BT_SERIALIZER_H
 | 
						|
 |