Make .bullet serialization mode robust:

Deal with broken DNA serialization. Bullet 2.76 release revision 2035 - 2046 was broken, and this includes the Maya Dynamica plugin.
Added some workaround to deal with the broken .bullet files, instead of crashing.
This commit is contained in:
erwin.coumans
2010-03-02 09:32:34 +00:00
parent c517f14dd4
commit 8fbe399ea4
19 changed files with 741 additions and 577 deletions

View File

@@ -40,6 +40,7 @@
#include "bullet_btPositionAndRadius.h"
#include "bullet_btMultiSphereShapeData.h"
#include "bullet_btIntIndexData.h"
#include "bullet_btShortIntIndexData.h"
#include "bullet_btShortIntIndexTripletData.h"
#include "bullet_btMeshPartData.h"
#include "bullet_btStridingMeshInterfaceData.h"

View File

@@ -47,6 +47,7 @@ namespace Bullet {
class btPositionAndRadius;
class btMultiSphereShapeData;
class btIntIndexData;
class btShortIntIndexData;
class btShortIntIndexTripletData;
class btMeshPartData;
class btStridingMeshInterfaceData;

View File

@@ -35,6 +35,7 @@ namespace Bullet {
btVector3DoubleData *m_vertices3d;
btIntIndexData *m_indices32;
btShortIntIndexTripletData *m_3indices16;
btShortIntIndexData *m_indices16;
int m_numTriangles;
int m_numVertices;
};

View File

@@ -37,6 +37,7 @@ namespace Bullet {
int m_escapeIndex;
int m_subPart;
int m_triangleIndex;
char m_pad[4];
};
}

View File

@@ -37,6 +37,7 @@ namespace Bullet {
int m_escapeIndex;
int m_subPart;
int m_triangleIndex;
char m_pad[4];
};
}

View File

@@ -41,9 +41,9 @@ namespace Bullet {
int m_numQuantizedContiguousNodes;
btOptimizedBvhNodeFloatData *m_contiguousNodesPtr;
btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr;
btBvhSubtreeInfoData *m_subTreeInfoPtr;
int m_traversalMode;
int m_numSubtreeHeaders;
btBvhSubtreeInfoData *m_subTreeInfoPtr;
};
}

View File

@@ -0,0 +1,40 @@
/* Copyright (C) 2006-2009 Erwin Coumans & Charlie C
*
* 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.
*/
// Auto generated from makesdna dna.c
#ifndef __BULLET_BTSHORTINTINDEXDATA__H__
#define __BULLET_BTSHORTINTINDEXDATA__H__
// -------------------------------------------------- //
#include "bullet_Common.h"
namespace Bullet {
// ---------------------------------------------- //
class btShortIntIndexData
{
public:
short m_value;
char m_pad[2];
};
}
#endif//__BULLET_BTSHORTINTINDEXDATA__H__

View File

@@ -99,6 +99,7 @@ namespace bParse {
btHashMap<btHashString,int> mTypeLookup;
int mPtrLen;

View File

@@ -200,6 +200,24 @@ void bFile::parseInternal(bool verboseDumpAllTypes, char* memDna,int memDnaLengt
mFileDNA = new bDNA();
mFileDNA->init(blenderData+sdnaPos, mFileLen-sdnaPos, (mFlags & FD_ENDIAN_SWAP)!=0);
if (mVersion==276)
{
int i;
for (i=0;i<mFileDNA->getNumNames();i++)
{
if (strcmp(mFileDNA->getName(i),"int")==0)
{
mFlags |= FD_BROKEN_DNA;
}
}
if ((mFlags&FD_BROKEN_DNA)!=0)
{
printf("warning: fixing some broken DNA version\n");
}
}
if (verboseDumpAllTypes)
{
mFileDNA->dumpTypeDefinitions();
@@ -211,7 +229,7 @@ void bFile::parseInternal(bool verboseDumpAllTypes, char* memDna,int memDnaLengt
mMemoryDNA->init(memDna,memDnaLength,littleEndian==0);
///@todo we need a better version check, add version/sub version info from FileGlobal into memory DNA/header files
@@ -276,6 +294,34 @@ char* bFile::readStruct(char *head, bChunkInd& dataChunk)
oldType = mFileDNA->getType(oldStruct[0]);
oldLen = mFileDNA->getLength(oldStruct[0]);
if ((mFlags&FD_BROKEN_DNA)!=0)
{
if ((strcmp(oldType,"btQuantizedBvhNodeData")==0)&&oldLen==20)
{
return 0;
}
if ((strcmp(oldType,"btShortIntIndexData")==0))
{
int allocLen = 2;
char *dataAlloc = new char[(dataChunk.nr*allocLen)+1];
memset(dataAlloc, 0, (dataChunk.nr*allocLen)+1);
short* dest = (short*) dataAlloc;
const short* src = (short*) head;
for (int i=0;i<dataChunk.nr;i++)
{
dest[i] = src[i];
if (mFlags &FD_ENDIAN_SWAP)
{
SWITCH_SHORT(dest[i]);
}
}
addDataBlock(dataAlloc);
return dataAlloc;
}
}
///don't try to convert Link block data, just memcpy it. Other data can be converted.
if (strcmp("Link",oldType)!=0)
{
@@ -507,7 +553,7 @@ void bFile::swapData(char *data, short type, int arraySize)
void bFile::safeSwapPtr(char *dst, char *src)
void bFile::safeSwapPtr(char *dst, const char *src)
{
int ptrFile = mFileDNA->getPointerSize();
int ptrMem = mMemoryDNA->getPointerSize();
@@ -535,8 +581,12 @@ void bFile::safeSwapPtr(char *dst, char *src)
//deal with pointers the Blender .blend style way, see
//readfile.c in the Blender source tree
long64 longValue = *((long64*)src);
//endian swap for 64bit pointer otherwise truncation will fail due to trailing zeros
if (mFlags & FD_ENDIAN_SWAP)
SWITCH_LONGINT(longValue);
*((int*)dst) = (int)(longValue>>3);
}
}
else if (ptrMem==8 && ptrFile==4)
{
@@ -576,9 +626,18 @@ void bFile::getMatchingFileDNA(short* dna_addr, const char* lookupName, const c
const char* type = mFileDNA->getType(dna_addr[0]);
const char* name = mFileDNA->getName(dna_addr[1]);
int eleLen = mFileDNA->getElementSize(dna_addr[0], dna_addr[1]);
int eleLen = mFileDNA->getElementSize(dna_addr[0], dna_addr[1]);
if ((mFlags&FD_BROKEN_DNA)!=0)
{
if ((strcmp(type,"short")==0)&&(strcmp(name,"int")==0))
{
eleLen = 0;
}
}
if (strcmp(lookupName, name)==0)
{
//int arrayLenold = mFileDNA->getArraySize((char*)name.c_str());
@@ -739,7 +798,7 @@ void bFile::resolvePointersMismatch()
// printf("pointer not found: %x\n",cur);
}
}
for (i=0;i< m_pointerPtrFixupArray.size();i++)
for (i=0;i< m_pointerPtrFixupArray.size();i++)
{
char* cur= m_pointerPtrFixupArray.at(i);
void** ptrptr = (void**)cur;
@@ -751,30 +810,32 @@ void bFile::resolvePointersMismatch()
void **array= (void**)(*(ptrptr));
int ptrMem = mMemoryDNA->getPointerSize();
int ptrFile = mFileDNA->getPointerSize();
int n=0, n2=0;
int swapoffs = 2;
void *np = array[n];
while(np)
int n=0;
void *lookup = array[n];
if (lookup)
{
if (ptrMem > ptrFile)
char *oldPtr = (char*)array;
btAlignedObjectArray<btPointerUid> pointers;
while(lookup)
{
safeSwapPtr((char*)&array[n2], (char*)&array[n]);
np = findLibPointer(array[n2]);
btPointerUid dp = {0};
safeSwapPtr((char*)dp.m_uniqueIds, (char*)(oldPtr + (n * ptrFile)));
lookup = findLibPointer(dp.m_ptr);
if (!lookup) break;
pointers.push_back(dp);
++n;
}
else if (ptrMem < ptrFile)
{
safeSwapPtr((char*)&array[n], (char*)&array[n2]);
np = findLibPointer(array[n]);
}
else
np = findLibPointer(array[n]);
if (np)
array[n] = np;
++n;
n2 += swapoffs;
for (int j=0; j<n; ++j)
{
array[j] = findLibPointer(pointers[j].m_ptr);
assert(array[j]);
}
}
}
}
@@ -1202,8 +1263,11 @@ int bFile::getNextBlock(bChunkInd *dataChunk, const char *dataPtr, const int fl
{
long64 oldPtr =0;
memcpy(&oldPtr, &head.m_uniqueInts[0], 8);
if (swap)
SWITCH_LONGINT(oldPtr);
chunk.m_uniqueInt = (int)(oldPtr >> 3);
}
chunk.dna_nr = head.dna_nr;
chunk.nr = head.nr;

View File

@@ -32,7 +32,8 @@ namespace bParse {
FD_FILE_64 =8,
FD_BITS_VARIES =16,
FD_VERSION_VARIES = 32,
FD_DOUBLE_PRECISION =64
FD_DOUBLE_PRECISION =64,
FD_BROKEN_DNA = 128
};
@@ -71,7 +72,7 @@ namespace bParse {
// buffer offset util
int getNextBlock(bChunkInd *dataChunk, const char *dataPtr, const int flags);
void safeSwapPtr(char *dst, char *src);
void safeSwapPtr(char *dst, const char *src);
virtual void parseHeader();

View File

@@ -108,6 +108,8 @@ void btBulletFile::parseData()
printf ("Chunk size = %d",CHUNK_HEADER_LEN);
printf ("File chunk size = %d",ChunkUtils::getOffset(mFlags));
const bool brokenDNA = (mFlags&FD_BROKEN_DNA)!=0;
//const bool swap = (mFlags&FD_ENDIAN_SWAP)!=0;
@@ -126,71 +128,74 @@ void btBulletFile::parseData()
while (dataChunk.code != DNA1)
{
// one behind
if (dataChunk.code == SDNA) break;
//if (dataChunk.code == DNA1) break;
// same as (BHEAD+DATA dependency)
dataPtrHead = dataPtr+ChunkUtils::getOffset(mFlags);
if (dataChunk.dna_nr>=0)
if (!brokenDNA || (dataChunk.code != BT_QUANTIZED_BVH_CODE) )
{
char *id = readStruct(dataPtrHead, dataChunk);
// lookup maps
if (id)
// one behind
if (dataChunk.code == SDNA) break;
//if (dataChunk.code == DNA1) break;
// same as (BHEAD+DATA dependency)
dataPtrHead = dataPtr+ChunkUtils::getOffset(mFlags);
if (dataChunk.dna_nr>=0)
{
mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)id);
char *id = readStruct(dataPtrHead, dataChunk);
m_chunks.push_back(dataChunk);
// block it
//bListBasePtr *listID = mMain->getListBasePtr(dataChunk.code);
//if (listID)
// listID->push_back((bStructHandle*)id);
}
// lookup maps
if (id)
{
mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)id);
if (dataChunk.code == BT_RIGIDBODY_CODE)
m_chunks.push_back(dataChunk);
// block it
//bListBasePtr *listID = mMain->getListBasePtr(dataChunk.code);
//if (listID)
// listID->push_back((bStructHandle*)id);
}
if (dataChunk.code == BT_RIGIDBODY_CODE)
{
m_rigidBodies.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_CONSTRAINT_CODE)
{
m_constraints.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_QUANTIZED_BVH_CODE)
{
m_bvhs.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_TRIANLGE_INFO_MAP)
{
m_triangleInfoMaps.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_COLLISIONOBJECT_CODE)
{
m_collisionObjects.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_SHAPE_CODE)
{
m_collisionShapes.push_back((bStructHandle*) id);
}
// if (dataChunk.code == GLOB)
// {
// m_glob = (bStructHandle*) id;
// }
} else
{
m_rigidBodies.push_back((bStructHandle*) id);
}
printf("unknown chunk\n");
if (dataChunk.code == BT_CONSTRAINT_CODE)
{
m_constraints.push_back((bStructHandle*) id);
mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)dataPtrHead);
}
if (dataChunk.code == BT_QUANTIZED_BVH_CODE)
{
m_bvhs.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_TRIANLGE_INFO_MAP)
{
m_triangleInfoMaps.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_COLLISIONOBJECT_CODE)
{
m_collisionObjects.push_back((bStructHandle*) id);
}
if (dataChunk.code == BT_SHAPE_CODE)
{
m_collisionShapes.push_back((bStructHandle*) id);
}
// if (dataChunk.code == GLOB)
// {
// m_glob = (bStructHandle*) id;
// }
} else
{
printf("unknown chunk\n");
mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)dataPtrHead);
printf("skipping BT_QUANTIZED_BVH_CODE due to broken DNA\n");
}
// next please!

View File

@@ -5,6 +5,7 @@
#include "btBulletDynamicsCommon.h"
#include "BulletCollision/Gimpact/btGImpactShape.h"
//#define USE_INTERNAL_EDGE_UTILITY
#ifdef USE_INTERNAL_EDGE_UTILITY
#include "BulletCollision/CollisionDispatch/btInternalEdgeUtility.h"
@@ -106,8 +107,17 @@ btTriangleIndexVertexArray* btBulletWorldImporter::createMeshInterface(btStridin
} else
{
meshPart.m_indexType = PHY_SHORT;
meshPart.m_triangleIndexStride = sizeof(btShortIntIndexTripletData);
meshPart.m_triangleIndexBase = (const unsigned char*)meshData.m_meshPartsPtr[i].m_3indices16;
if (meshData.m_meshPartsPtr[i].m_3indices16)
{
meshPart.m_triangleIndexStride = sizeof(btShortIntIndexTripletData);
meshPart.m_triangleIndexBase = (const unsigned char*)meshData.m_meshPartsPtr[i].m_3indices16;
}
if (meshData.m_meshPartsPtr[i].m_indices16)
{
meshPart.m_triangleIndexStride = 3*sizeof(short int);
meshPart.m_triangleIndexBase = (const unsigned char*)meshData.m_meshPartsPtr[i].m_indices16;
}
}
if (meshData.m_meshPartsPtr[i].m_vertices3f)
@@ -124,8 +134,10 @@ btTriangleIndexVertexArray* btBulletWorldImporter::createMeshInterface(btStridin
meshPart.m_numTriangles = meshData.m_meshPartsPtr[i].m_numTriangles;
meshPart.m_numVertices = meshData.m_meshPartsPtr[i].m_numVertices;
meshInterface->addIndexedMesh(meshPart,meshPart.m_indexType);
if (meshPart.m_triangleIndexBase && meshPart.m_vertexBase)
{
meshInterface->addIndexedMesh(meshPart,meshPart.m_indexType);
}
}
return meshInterface;
@@ -338,13 +350,17 @@ btCollisionShape* btBulletWorldImporter::convertCollisionShape( btCollisionShap
{
btTriangleMeshShapeData* trimesh = (btTriangleMeshShapeData*)shapeData;
btTriangleIndexVertexArray* meshInterface = createMeshInterface(trimesh->m_meshInterface);
if (!meshInterface->getNumSubParts())
{
return 0;
}
btVector3 scaling; scaling.deSerializeFloat(trimesh->m_meshInterface.m_scaling);
meshInterface->setScaling(scaling);
btOptimizedBvh* bvh = 0;
#if 1
#if 0
if (trimesh->m_quantizedFloatBvh)
{
btOptimizedBvh** bvhPtr = m_bvhMap.find(trimesh->m_quantizedFloatBvh);
@@ -512,6 +528,11 @@ bool btBulletWorldImporter::loadFileFromMemory( bParse::btBulletFile* bulletFil
startTransform.deSerializeDouble(colObjData->m_collisionObjectData.m_worldTransform);
// startTransform.setBasis(btMatrix3x3::getIdentity());
btCollisionShape* shape = (btCollisionShape*)*shapePtr;
if (shape->isNonMoving())
{
mass = 0.f;
}
if (mass)
{
shape->calculateLocalInertia(mass,localInertia);
@@ -548,6 +569,10 @@ bool btBulletWorldImporter::loadFileFromMemory( bParse::btBulletFile* bulletFil
startTransform.deSerializeFloat(colObjData->m_collisionObjectData.m_worldTransform);
// startTransform.setBasis(btMatrix3x3::getIdentity());
btCollisionShape* shape = (btCollisionShape*)*shapePtr;
if (shape->isNonMoving())
{
mass = 0.f;
}
if (mass)
{
shape->calculateLocalInertia(mass,localInertia);