forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			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
 | |
| 
 |