mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			869 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			869 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,
 | 
						|
	BT_SERIALIZE_CONTACT_MANIFOLDS = 8,
 | 
						|
};
 | 
						|
 | 
						|
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_MB_LINKCOLLIDER_CODE BT_MAKE_ID('M', 'B', 'L', 'C')
 | 
						|
#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_CONTACTMANIFOLD_CODE BT_MAKE_ID('C', 'O', 'N', 'T')
 | 
						|
#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] = '3';
 | 
						|
		buffer[10] = '0';
 | 
						|
		buffer[11] = '8';
 | 
						|
	}
 | 
						|
 | 
						|
	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
 |