btSerializer.h

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 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.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #ifndef BT_SERIALIZER_H
00017 #define BT_SERIALIZER_H
00018 
00019 #include "btScalar.h" // has definitions like SIMD_FORCE_INLINE
00020 #include "btStackAlloc.h"
00021 #include "btHashMap.h"
00022 
00023 #if !defined( __CELLOS_LV2__) && !defined(__MWERKS__)
00024 #include <memory.h>
00025 #endif
00026 #include <string.h>
00027 
00028 
00029 
00031 extern char sBulletDNAstr[];
00032 extern int sBulletDNAlen;
00033 extern char sBulletDNAstr64[];
00034 extern int sBulletDNAlen64;
00035 
00036 SIMD_FORCE_INLINE       int btStrLen(const char* str) 
00037 {
00038     if (!str) 
00039                 return(0);
00040         int len = 0;
00041     
00042         while (*str != 0)
00043         {
00044         str++;
00045         len++;
00046     }
00047 
00048     return len;
00049 }
00050 
00051 
00052 class btChunk
00053 {
00054 public:
00055         int             m_chunkCode;
00056         int             m_length;
00057         void    *m_oldPtr;
00058         int             m_dna_nr;
00059         int             m_number;
00060 };
00061 
00062 enum    btSerializationFlags
00063 {
00064         BT_SERIALIZE_NO_BVH = 1,
00065         BT_SERIALIZE_NO_TRIANGLEINFOMAP = 2,
00066         BT_SERIALIZE_NO_DUPLICATE_ASSERT = 4
00067 };
00068 
00069 class   btSerializer
00070 {
00071 
00072 public:
00073 
00074         virtual ~btSerializer() {}
00075 
00076         virtual const unsigned char*            getBufferPointer() const = 0;
00077 
00078         virtual int             getCurrentBufferSize() const = 0;
00079 
00080         virtual btChunk*        allocate(size_t size, int numElements) = 0;
00081 
00082         virtual void    finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)= 0;
00083 
00084         virtual  void*  findPointer(void* oldPtr)  = 0;
00085 
00086         virtual void*   getUniquePointer(void*oldPtr) = 0;
00087 
00088         virtual void    startSerialization() = 0;
00089         
00090         virtual void    finishSerialization() = 0;
00091 
00092         virtual const char*     findNameForPointer(const void* ptr) const = 0;
00093 
00094         virtual void    registerNameForPointer(const void* ptr, const char* name) = 0;
00095 
00096         virtual void    serializeName(const char* ptr) = 0;
00097 
00098         virtual int             getSerializationFlags() const = 0;
00099 
00100         virtual void    setSerializationFlags(int flags) = 0;
00101 
00102 
00103 };
00104 
00105 
00106 
00107 #define BT_HEADER_LENGTH 12
00108 #if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
00109 #       define BT_MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
00110 #else
00111 #       define BT_MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
00112 #endif
00113 
00114 #define BT_SOFTBODY_CODE                BT_MAKE_ID('S','B','D','Y')
00115 #define BT_COLLISIONOBJECT_CODE BT_MAKE_ID('C','O','B','J')
00116 #define BT_RIGIDBODY_CODE               BT_MAKE_ID('R','B','D','Y')
00117 #define BT_CONSTRAINT_CODE              BT_MAKE_ID('C','O','N','S')
00118 #define BT_BOXSHAPE_CODE                BT_MAKE_ID('B','O','X','S')
00119 #define BT_QUANTIZED_BVH_CODE   BT_MAKE_ID('Q','B','V','H')
00120 #define BT_TRIANLGE_INFO_MAP    BT_MAKE_ID('T','M','A','P')
00121 #define BT_SHAPE_CODE                   BT_MAKE_ID('S','H','A','P')
00122 #define BT_ARRAY_CODE                   BT_MAKE_ID('A','R','A','Y')
00123 #define BT_SBMATERIAL_CODE              BT_MAKE_ID('S','B','M','T')
00124 #define BT_SBNODE_CODE                  BT_MAKE_ID('S','B','N','D')
00125 #define BT_DYNAMICSWORLD_CODE   BT_MAKE_ID('D','W','L','D')
00126 #define BT_DNA_CODE                             BT_MAKE_ID('D','N','A','1')
00127 
00128 
00129 struct  btPointerUid
00130 {
00131         union
00132         {
00133                 void*   m_ptr;
00134                 int             m_uniqueIds[2];
00135         };
00136 };
00137 
00140 class btDefaultSerializer       :       public btSerializer
00141 {
00142 
00143 
00144         btAlignedObjectArray<char*>                     mTypes;
00145         btAlignedObjectArray<short*>                    mStructs;
00146         btAlignedObjectArray<short>                     mTlens;
00147         btHashMap<btHashInt, int>                       mStructReverse;
00148         btHashMap<btHashString,int>     mTypeLookup;
00149 
00150         
00151         btHashMap<btHashPtr,void*>      m_chunkP;
00152         
00153         btHashMap<btHashPtr,const char*>        m_nameMap;
00154 
00155         btHashMap<btHashPtr,btPointerUid>       m_uniquePointers;
00156         int     m_uniqueIdGenerator;
00157 
00158         int                                     m_totalSize;
00159         unsigned char*          m_buffer;
00160         int                                     m_currentSize;
00161         void*                           m_dna;
00162         int                                     m_dnaLength;
00163 
00164         int                                     m_serializationFlags;
00165 
00166 
00167         btAlignedObjectArray<btChunk*>  m_chunkPtrs;
00168         
00169 protected:
00170 
00171         virtual void*   findPointer(void* oldPtr) 
00172         {
00173                 void** ptr = m_chunkP.find(oldPtr);
00174                 if (ptr && *ptr)
00175                         return *ptr;
00176                 return 0;
00177         }
00178 
00179         
00180 
00181 
00182 
00183                 void    writeDNA()
00184                 {
00185                         btChunk* dnaChunk = allocate(m_dnaLength,1);
00186                         memcpy(dnaChunk->m_oldPtr,m_dna,m_dnaLength);
00187                         finalizeChunk(dnaChunk,"DNA1",BT_DNA_CODE, m_dna);
00188                 }
00189 
00190                 int getReverseType(const char *type) const
00191                 {
00192 
00193                         btHashString key(type);
00194                         const int* valuePtr = mTypeLookup.find(key);
00195                         if (valuePtr)
00196                                 return *valuePtr;
00197                         
00198                         return -1;
00199                 }
00200 
00201                 void initDNA(const char* bdnaOrg,int dnalen)
00202                 {
00204                         if (m_dna)
00205                                 return;
00206 
00207                         int littleEndian= 1;
00208                         littleEndian= ((char*)&littleEndian)[0];
00209                         
00210 
00211                         m_dna = btAlignedAlloc(dnalen,16);
00212                         memcpy(m_dna,bdnaOrg,dnalen);
00213                         m_dnaLength = dnalen;
00214 
00215                         int *intPtr=0;
00216                         short *shtPtr=0;
00217                         char *cp = 0;int dataLen =0;
00218                         intPtr = (int*)m_dna;
00219 
00220                         /*
00221                                 SDNA (4 bytes) (magic number)
00222                                 NAME (4 bytes)
00223                                 <nr> (4 bytes) amount of names (int)
00224                                 <string>
00225                                 <string>
00226                         */
00227 
00228                         if (strncmp((const char*)m_dna, "SDNA", 4)==0)
00229                         {
00230                                 // skip ++ NAME
00231                                 intPtr++; intPtr++;
00232                         }
00233 
00234                         // Parse names
00235                         if (!littleEndian)
00236                                 *intPtr = btSwapEndian(*intPtr);
00237                                 
00238                         dataLen = *intPtr;
00239                         
00240                         intPtr++;
00241 
00242                         cp = (char*)intPtr;
00243                         int i;
00244                         for ( i=0; i<dataLen; i++)
00245                         {
00246                                 
00247                                 while (*cp)cp++;
00248                                 cp++;
00249                         }
00250                         cp = btAlignPointer(cp,4);
00251 
00252                         /*
00253                                 TYPE (4 bytes)
00254                                 <nr> amount of types (int)
00255                                 <string>
00256                                 <string>
00257                         */
00258 
00259                         intPtr = (int*)cp;
00260                         btAssert(strncmp(cp, "TYPE", 4)==0); intPtr++;
00261 
00262                         if (!littleEndian)
00263                                 *intPtr =  btSwapEndian(*intPtr);
00264                         
00265                         dataLen = *intPtr;
00266                         intPtr++;
00267 
00268                         
00269                         cp = (char*)intPtr;
00270                         for (i=0; i<dataLen; i++)
00271                         {
00272                                 mTypes.push_back(cp);
00273                                 while (*cp)cp++;
00274                                 cp++;
00275                         }
00276 
00277                         cp = btAlignPointer(cp,4);
00278 
00279 
00280                         /*
00281                                 TLEN (4 bytes)
00282                                 <len> (short) the lengths of types
00283                                 <len>
00284                         */
00285 
00286                         // Parse type lens
00287                         intPtr = (int*)cp;
00288                         btAssert(strncmp(cp, "TLEN", 4)==0); intPtr++;
00289 
00290                         dataLen = (int)mTypes.size();
00291 
00292                         shtPtr = (short*)intPtr;
00293                         for (i=0; i<dataLen; i++, shtPtr++)
00294                         {
00295                                 if (!littleEndian)
00296                                         shtPtr[0] = btSwapEndian(shtPtr[0]);
00297                                 mTlens.push_back(shtPtr[0]);
00298                         }
00299 
00300                         if (dataLen & 1) shtPtr++;
00301 
00302                         /*
00303                                 STRC (4 bytes)
00304                                 <nr> amount of structs (int)
00305                                 <typenr>
00306                                 <nr_of_elems>
00307                                 <typenr>
00308                                 <namenr>
00309                                 <typenr>
00310                                 <namenr>
00311                         */
00312 
00313                         intPtr = (int*)shtPtr;
00314                         cp = (char*)intPtr;
00315                         btAssert(strncmp(cp, "STRC", 4)==0); intPtr++;
00316 
00317                         if (!littleEndian)
00318                                 *intPtr = btSwapEndian(*intPtr);
00319                         dataLen = *intPtr ; 
00320                         intPtr++;
00321 
00322 
00323                         shtPtr = (short*)intPtr;
00324                         for (i=0; i<dataLen; i++)
00325                         {
00326                                 mStructs.push_back (shtPtr);
00327                                 
00328                                 if (!littleEndian)
00329                                 {
00330                                         shtPtr[0]= btSwapEndian(shtPtr[0]);
00331                                         shtPtr[1]= btSwapEndian(shtPtr[1]);
00332 
00333                                         int len = shtPtr[1];
00334                                         shtPtr+= 2;
00335 
00336                                         for (int a=0; a<len; a++, shtPtr+=2)
00337                                         {
00338                                                         shtPtr[0]= btSwapEndian(shtPtr[0]);
00339                                                         shtPtr[1]= btSwapEndian(shtPtr[1]);
00340                                         }
00341 
00342                                 } else
00343                                 {
00344                                         shtPtr+= (2*shtPtr[1])+2;
00345                                 }
00346                         }
00347 
00348                         // build reverse lookups
00349                         for (i=0; i<(int)mStructs.size(); i++)
00350                         {
00351                                 short *strc = mStructs.at(i);
00352                                 mStructReverse.insert(strc[0], i);
00353                                 mTypeLookup.insert(btHashString(mTypes[strc[0]]),i);
00354                         }
00355                 }
00356 
00357 public: 
00358         
00359 
00360         
00361 
00362                 btDefaultSerializer(int totalSize=0)
00363                         :m_totalSize(totalSize),
00364                         m_currentSize(0),
00365                         m_dna(0),
00366                         m_dnaLength(0),
00367                         m_serializationFlags(0)
00368                 {
00369                         m_buffer = m_totalSize?(unsigned char*)btAlignedAlloc(totalSize,16):0;
00370                         
00371                         const bool VOID_IS_8 = ((sizeof(void*)==8));
00372 
00373 #ifdef BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
00374                         if (VOID_IS_8)
00375                         {
00376 #if _WIN64
00377                                 initDNA((const char*)sBulletDNAstr64,sBulletDNAlen64);
00378 #else
00379                                 btAssert(0);
00380 #endif
00381                         } else
00382                         {
00383 #ifndef _WIN64
00384                                 initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
00385 #else
00386                                 btAssert(0);
00387 #endif
00388                         }
00389         
00390 #else //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
00391                         if (VOID_IS_8)
00392                         {
00393                                 initDNA((const char*)sBulletDNAstr64,sBulletDNAlen64);
00394                         } else
00395                         {
00396                                 initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
00397                         }
00398 #endif //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
00399         
00400                 }
00401 
00402                 virtual ~btDefaultSerializer() 
00403                 {
00404                         if (m_buffer)
00405                                 btAlignedFree(m_buffer);
00406                         if (m_dna)
00407                                 btAlignedFree(m_dna);
00408                 }
00409 
00410                 void    writeHeader(unsigned char* buffer) const
00411                 {
00412                         
00413 
00414 #ifdef  BT_USE_DOUBLE_PRECISION
00415                         memcpy(buffer, "BULLETd", 7);
00416 #else
00417                         memcpy(buffer, "BULLETf", 7);
00418 #endif //BT_USE_DOUBLE_PRECISION
00419         
00420                         int littleEndian= 1;
00421                         littleEndian= ((char*)&littleEndian)[0];
00422 
00423                         if (sizeof(void*)==8)
00424                         {
00425                                 buffer[7] = '-';
00426                         } else
00427                         {
00428                                 buffer[7] = '_';
00429                         }
00430 
00431                         if (littleEndian)
00432                         {
00433                                 buffer[8]='v';                          
00434                         } else
00435                         {
00436                                 buffer[8]='V';
00437                         }
00438 
00439 
00440                         buffer[9] = '2';
00441                         buffer[10] = '8';
00442                         buffer[11] = '1';
00443 
00444                 }
00445 
00446                 virtual void    startSerialization()
00447                 {
00448                         m_uniqueIdGenerator= 1;
00449                         if (m_totalSize)
00450                         {
00451                                 unsigned char* buffer = internalAlloc(BT_HEADER_LENGTH);
00452                                 writeHeader(buffer);
00453                         }
00454                         
00455                 }
00456 
00457                 virtual void    finishSerialization()
00458                 {
00459                         writeDNA();
00460 
00461                         //if we didn't pre-allocate a buffer, we need to create a contiguous buffer now
00462                         int mysize = 0;
00463                         if (!m_totalSize)
00464                         {
00465                                 if (m_buffer)
00466                                         btAlignedFree(m_buffer);
00467 
00468                                 m_currentSize += BT_HEADER_LENGTH;
00469                                 m_buffer = (unsigned char*)btAlignedAlloc(m_currentSize,16);
00470 
00471                                 unsigned char* currentPtr = m_buffer;
00472                                 writeHeader(m_buffer);
00473                                 currentPtr += BT_HEADER_LENGTH;
00474                                 mysize+=BT_HEADER_LENGTH;
00475                                 for (int i=0;i< m_chunkPtrs.size();i++)
00476                                 {
00477                                         int curLength = sizeof(btChunk)+m_chunkPtrs[i]->m_length;
00478                                         memcpy(currentPtr,m_chunkPtrs[i], curLength);
00479                                         btAlignedFree(m_chunkPtrs[i]);
00480                                         currentPtr+=curLength;
00481                                         mysize+=curLength;
00482                                 }
00483                         }
00484 
00485                         mTypes.clear();
00486                         mStructs.clear();
00487                         mTlens.clear();
00488                         mStructReverse.clear();
00489                         mTypeLookup.clear();
00490                         m_chunkP.clear();
00491                         m_nameMap.clear();
00492                         m_uniquePointers.clear();
00493                         m_chunkPtrs.clear();
00494                 }
00495 
00496                 virtual void*   getUniquePointer(void*oldPtr)
00497                 {
00498                         if (!oldPtr)
00499                                 return 0;
00500 
00501                         btPointerUid* uptr = (btPointerUid*)m_uniquePointers.find(oldPtr);
00502                         if (uptr)
00503                         {
00504                                 return uptr->m_ptr;
00505                         }
00506                         m_uniqueIdGenerator++;
00507                         
00508                         btPointerUid uid;
00509                         uid.m_uniqueIds[0] = m_uniqueIdGenerator;
00510                         uid.m_uniqueIds[1] = m_uniqueIdGenerator;
00511                         m_uniquePointers.insert(oldPtr,uid);
00512                         return uid.m_ptr;
00513 
00514                 }
00515 
00516                 virtual const unsigned char*            getBufferPointer() const
00517                 {
00518                         return m_buffer;
00519                 }
00520 
00521                 virtual int                                     getCurrentBufferSize() const
00522                 {
00523                         return  m_currentSize;
00524                 }
00525 
00526                 virtual void    finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)
00527                 {
00528                         if (!(m_serializationFlags&BT_SERIALIZE_NO_DUPLICATE_ASSERT))
00529                         {
00530                                 btAssert(!findPointer(oldPtr));
00531                         }
00532 
00533                         chunk->m_dna_nr = getReverseType(structType);
00534                         
00535                         chunk->m_chunkCode = chunkCode;
00536                         
00537                         void* uniquePtr = getUniquePointer(oldPtr);
00538                         
00539                         m_chunkP.insert(oldPtr,uniquePtr);//chunk->m_oldPtr);
00540                         chunk->m_oldPtr = uniquePtr;//oldPtr;
00541                         
00542                 }
00543 
00544                 
00545                 virtual unsigned char* internalAlloc(size_t size)
00546                 {
00547                         unsigned char* ptr = 0;
00548 
00549                         if (m_totalSize)
00550                         {
00551                                 ptr = m_buffer+m_currentSize;
00552                                 m_currentSize += int(size);
00553                                 btAssert(m_currentSize<m_totalSize);
00554                         } else
00555                         {
00556                                 ptr = (unsigned char*)btAlignedAlloc(size,16);
00557                                 m_currentSize += int(size);
00558                         }
00559                         return ptr;
00560                 }
00561 
00562                 
00563 
00564                 virtual btChunk*        allocate(size_t size, int numElements)
00565                 {
00566 
00567                         unsigned char* ptr = internalAlloc(int(size)*numElements+sizeof(btChunk));
00568 
00569                         unsigned char* data = ptr + sizeof(btChunk);
00570                         
00571                         btChunk* chunk = (btChunk*)ptr;
00572                         chunk->m_chunkCode = 0;
00573                         chunk->m_oldPtr = data;
00574                         chunk->m_length = int(size)*numElements;
00575                         chunk->m_number = numElements;
00576                         
00577                         m_chunkPtrs.push_back(chunk);
00578                         
00579 
00580                         return chunk;
00581                 }
00582 
00583                 virtual const char*     findNameForPointer(const void* ptr) const
00584                 {
00585                         const char*const * namePtr = m_nameMap.find(ptr);
00586                         if (namePtr && *namePtr)
00587                                 return *namePtr;
00588                         return 0;
00589 
00590                 }
00591 
00592                 virtual void    registerNameForPointer(const void* ptr, const char* name)
00593                 {
00594                         m_nameMap.insert(ptr,name);
00595                 }
00596 
00597                 virtual void    serializeName(const char* name)
00598                 {
00599                         if (name)
00600                         {
00601                                 //don't serialize name twice
00602                                 if (findPointer((void*)name))
00603                                         return;
00604 
00605                                 int len = btStrLen(name);
00606                                 if (len)
00607                                 {
00608 
00609                                         int newLen = len+1;
00610                                         int padding = ((newLen+3)&~3)-newLen;
00611                                         newLen += padding;
00612 
00613                                         //serialize name string now
00614                                         btChunk* chunk = allocate(sizeof(char),newLen);
00615                                         char* destinationName = (char*)chunk->m_oldPtr;
00616                                         for (int i=0;i<len;i++)
00617                                         {
00618                                                 destinationName[i] = name[i];
00619                                         }
00620                                         destinationName[len] = 0;
00621                                         finalizeChunk(chunk,"char",BT_ARRAY_CODE,(void*)name);
00622                                 }
00623                         }
00624                 }
00625 
00626                 virtual int             getSerializationFlags() const
00627                 {
00628                         return m_serializationFlags;
00629                 }
00630 
00631                 virtual void    setSerializationFlags(int flags)
00632                 {
00633                         m_serializationFlags = flags;
00634                 }
00635 
00636 };
00637 
00638 
00639 #endif //BT_SERIALIZER_H
00640