Bullet Collision Detection & Physics Library
btSerializer.h
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
16 #ifndef BT_SERIALIZER_H
17 #define BT_SERIALIZER_H
18 
19 #include "btScalar.h" // has definitions like SIMD_FORCE_INLINE
20 #include "btStackAlloc.h"
21 #include "btHashMap.h"
22 
23 #if !defined( __CELLOS_LV2__) && !defined(__MWERKS__)
24 #include <memory.h>
25 #endif
26 #include <string.h>
27 
28 
29 
31 extern char sBulletDNAstr[];
32 extern int sBulletDNAlen;
33 extern char sBulletDNAstr64[];
34 extern int sBulletDNAlen64;
35 
36 SIMD_FORCE_INLINE int btStrLen(const char* str)
37 {
38  if (!str)
39  return(0);
40  int len = 0;
41 
42  while (*str != 0)
43  {
44  str++;
45  len++;
46  }
47 
48  return len;
49 }
50 
51 
52 class btChunk
53 {
54 public:
56  int m_length;
57  void *m_oldPtr;
58  int m_dna_nr;
59  int m_number;
60 };
61 
63 {
67 };
68 
70 {
71 
72 public:
73 
74  virtual ~btSerializer() {}
75 
76  virtual const unsigned char* getBufferPointer() const = 0;
77 
78  virtual int getCurrentBufferSize() const = 0;
79 
80  virtual btChunk* allocate(size_t size, int numElements) = 0;
81 
82  virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)= 0;
83 
84  virtual void* findPointer(void* oldPtr) = 0;
85 
86  virtual void* getUniquePointer(void*oldPtr) = 0;
87 
88  virtual void startSerialization() = 0;
89 
90  virtual void finishSerialization() = 0;
91 
92  virtual const char* findNameForPointer(const void* ptr) const = 0;
93 
94  virtual void registerNameForPointer(const void* ptr, const char* name) = 0;
95 
96  virtual void serializeName(const char* ptr) = 0;
97 
98  virtual int getSerializationFlags() const = 0;
99 
100  virtual void setSerializationFlags(int flags) = 0;
101 
102 
103 };
104 
105 
106 
107 #define BT_HEADER_LENGTH 12
108 #if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
109 # define BT_MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
110 #else
111 # define BT_MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
112 #endif
113 
114 #define BT_SOFTBODY_CODE BT_MAKE_ID('S','B','D','Y')
115 #define BT_COLLISIONOBJECT_CODE BT_MAKE_ID('C','O','B','J')
116 #define BT_RIGIDBODY_CODE BT_MAKE_ID('R','B','D','Y')
117 #define BT_CONSTRAINT_CODE BT_MAKE_ID('C','O','N','S')
118 #define BT_BOXSHAPE_CODE BT_MAKE_ID('B','O','X','S')
119 #define BT_QUANTIZED_BVH_CODE BT_MAKE_ID('Q','B','V','H')
120 #define BT_TRIANLGE_INFO_MAP BT_MAKE_ID('T','M','A','P')
121 #define BT_SHAPE_CODE BT_MAKE_ID('S','H','A','P')
122 #define BT_ARRAY_CODE BT_MAKE_ID('A','R','A','Y')
123 #define BT_SBMATERIAL_CODE BT_MAKE_ID('S','B','M','T')
124 #define BT_SBNODE_CODE BT_MAKE_ID('S','B','N','D')
125 #define BT_DYNAMICSWORLD_CODE BT_MAKE_ID('D','W','L','D')
126 #define BT_DNA_CODE BT_MAKE_ID('D','N','A','1')
127 
128 
130 {
131  union
132  {
133  void* m_ptr;
134  int m_uniqueIds[2];
135  };
136 };
137 
141 {
142 
143 
149 
150 
152 
154 
157 
159  unsigned char* m_buffer;
161  void* m_dna;
163 
165 
166 
168 
169 protected:
170 
171  virtual void* findPointer(void* oldPtr)
172  {
173  void** ptr = m_chunkP.find(oldPtr);
174  if (ptr && *ptr)
175  return *ptr;
176  return 0;
177  }
178 
179 
180 
181 
182 
183  void writeDNA()
184  {
185  btChunk* dnaChunk = allocate(m_dnaLength,1);
186  memcpy(dnaChunk->m_oldPtr,m_dna,m_dnaLength);
187  finalizeChunk(dnaChunk,"DNA1",BT_DNA_CODE, m_dna);
188  }
189 
190  int getReverseType(const char *type) const
191  {
192 
193  btHashString key(type);
194  const int* valuePtr = mTypeLookup.find(key);
195  if (valuePtr)
196  return *valuePtr;
197 
198  return -1;
199  }
200 
201  void initDNA(const char* bdnaOrg,int dnalen)
202  {
204  if (m_dna)
205  return;
206 
207  int littleEndian= 1;
208  littleEndian= ((char*)&littleEndian)[0];
209 
210 
211  m_dna = btAlignedAlloc(dnalen,16);
212  memcpy(m_dna,bdnaOrg,dnalen);
213  m_dnaLength = dnalen;
214 
215  int *intPtr=0;
216  short *shtPtr=0;
217  char *cp = 0;int dataLen =0;
218  intPtr = (int*)m_dna;
219 
220  /*
221  SDNA (4 bytes) (magic number)
222  NAME (4 bytes)
223  <nr> (4 bytes) amount of names (int)
224  <string>
225  <string>
226  */
227 
228  if (strncmp((const char*)m_dna, "SDNA", 4)==0)
229  {
230  // skip ++ NAME
231  intPtr++; intPtr++;
232  }
233 
234  // Parse names
235  if (!littleEndian)
236  *intPtr = btSwapEndian(*intPtr);
237 
238  dataLen = *intPtr;
239 
240  intPtr++;
241 
242  cp = (char*)intPtr;
243  int i;
244  for ( i=0; i<dataLen; i++)
245  {
246 
247  while (*cp)cp++;
248  cp++;
249  }
250  cp = btAlignPointer(cp,4);
251 
252  /*
253  TYPE (4 bytes)
254  <nr> amount of types (int)
255  <string>
256  <string>
257  */
258 
259  intPtr = (int*)cp;
260  btAssert(strncmp(cp, "TYPE", 4)==0); intPtr++;
261 
262  if (!littleEndian)
263  *intPtr = btSwapEndian(*intPtr);
264 
265  dataLen = *intPtr;
266  intPtr++;
267 
268 
269  cp = (char*)intPtr;
270  for (i=0; i<dataLen; i++)
271  {
272  mTypes.push_back(cp);
273  while (*cp)cp++;
274  cp++;
275  }
276 
277  cp = btAlignPointer(cp,4);
278 
279 
280  /*
281  TLEN (4 bytes)
282  <len> (short) the lengths of types
283  <len>
284  */
285 
286  // Parse type lens
287  intPtr = (int*)cp;
288  btAssert(strncmp(cp, "TLEN", 4)==0); intPtr++;
289 
290  dataLen = (int)mTypes.size();
291 
292  shtPtr = (short*)intPtr;
293  for (i=0; i<dataLen; i++, shtPtr++)
294  {
295  if (!littleEndian)
296  shtPtr[0] = btSwapEndian(shtPtr[0]);
297  mTlens.push_back(shtPtr[0]);
298  }
299 
300  if (dataLen & 1) shtPtr++;
301 
302  /*
303  STRC (4 bytes)
304  <nr> amount of structs (int)
305  <typenr>
306  <nr_of_elems>
307  <typenr>
308  <namenr>
309  <typenr>
310  <namenr>
311  */
312 
313  intPtr = (int*)shtPtr;
314  cp = (char*)intPtr;
315  btAssert(strncmp(cp, "STRC", 4)==0); intPtr++;
316 
317  if (!littleEndian)
318  *intPtr = btSwapEndian(*intPtr);
319  dataLen = *intPtr ;
320  intPtr++;
321 
322 
323  shtPtr = (short*)intPtr;
324  for (i=0; i<dataLen; i++)
325  {
326  mStructs.push_back (shtPtr);
327 
328  if (!littleEndian)
329  {
330  shtPtr[0]= btSwapEndian(shtPtr[0]);
331  shtPtr[1]= btSwapEndian(shtPtr[1]);
332 
333  int len = shtPtr[1];
334  shtPtr+= 2;
335 
336  for (int a=0; a<len; a++, shtPtr+=2)
337  {
338  shtPtr[0]= btSwapEndian(shtPtr[0]);
339  shtPtr[1]= btSwapEndian(shtPtr[1]);
340  }
341 
342  } else
343  {
344  shtPtr+= (2*shtPtr[1])+2;
345  }
346  }
347 
348  // build reverse lookups
349  for (i=0; i<(int)mStructs.size(); i++)
350  {
351  short *strc = mStructs.at(i);
352  mStructReverse.insert(strc[0], i);
353  mTypeLookup.insert(btHashString(mTypes[strc[0]]),i);
354  }
355  }
356 
357 public:
358 
359 
360 
361 
362  btDefaultSerializer(int totalSize=0)
363  :m_totalSize(totalSize),
364  m_currentSize(0),
365  m_dna(0),
366  m_dnaLength(0),
368  {
369  m_buffer = m_totalSize?(unsigned char*)btAlignedAlloc(totalSize,16):0;
370 
371  const bool VOID_IS_8 = ((sizeof(void*)==8));
372 
373 #ifdef BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
374  if (VOID_IS_8)
375  {
376 #if _WIN64
378 #else
379  btAssert(0);
380 #endif
381  } else
382  {
383 #ifndef _WIN64
384  initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
385 #else
386  btAssert(0);
387 #endif
388  }
389 
390 #else //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
391  if (VOID_IS_8)
392  {
394  } else
395  {
396  initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
397  }
398 #endif //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
399 
400  }
401 
403  {
404  if (m_buffer)
406  if (m_dna)
408  }
409 
410  void writeHeader(unsigned char* buffer) const
411  {
412 
413 
414 #ifdef BT_USE_DOUBLE_PRECISION
415  memcpy(buffer, "BULLETd", 7);
416 #else
417  memcpy(buffer, "BULLETf", 7);
418 #endif //BT_USE_DOUBLE_PRECISION
419 
420  int littleEndian= 1;
421  littleEndian= ((char*)&littleEndian)[0];
422 
423  if (sizeof(void*)==8)
424  {
425  buffer[7] = '-';
426  } else
427  {
428  buffer[7] = '_';
429  }
430 
431  if (littleEndian)
432  {
433  buffer[8]='v';
434  } else
435  {
436  buffer[8]='V';
437  }
438 
439 
440  buffer[9] = '2';
441  buffer[10] = '8';
442  buffer[11] = '1';
443 
444  }
445 
446  virtual void startSerialization()
447  {
449  if (m_totalSize)
450  {
451  unsigned char* buffer = internalAlloc(BT_HEADER_LENGTH);
452  writeHeader(buffer);
453  }
454 
455  }
456 
457  virtual void finishSerialization()
458  {
459  writeDNA();
460 
461  //if we didn't pre-allocate a buffer, we need to create a contiguous buffer now
462  int mysize = 0;
463  if (!m_totalSize)
464  {
465  if (m_buffer)
467 
469  m_buffer = (unsigned char*)btAlignedAlloc(m_currentSize,16);
470 
471  unsigned char* currentPtr = m_buffer;
473  currentPtr += BT_HEADER_LENGTH;
474  mysize+=BT_HEADER_LENGTH;
475  for (int i=0;i< m_chunkPtrs.size();i++)
476  {
477  int curLength = sizeof(btChunk)+m_chunkPtrs[i]->m_length;
478  memcpy(currentPtr,m_chunkPtrs[i], curLength);
480  currentPtr+=curLength;
481  mysize+=curLength;
482  }
483  }
484 
485  mTypes.clear();
486  mStructs.clear();
487  mTlens.clear();
489  mTypeLookup.clear();
490  m_chunkP.clear();
491  m_nameMap.clear();
493  m_chunkPtrs.clear();
494  }
495 
496  virtual void* getUniquePointer(void*oldPtr)
497  {
498  if (!oldPtr)
499  return 0;
500 
502  if (uptr)
503  {
504  return uptr->m_ptr;
505  }
507 
508  btPointerUid uid;
511  m_uniquePointers.insert(oldPtr,uid);
512  return uid.m_ptr;
513 
514  }
515 
516  virtual const unsigned char* getBufferPointer() const
517  {
518  return m_buffer;
519  }
520 
521  virtual int getCurrentBufferSize() const
522  {
523  return m_currentSize;
524  }
525 
526  virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)
527  {
529  {
530  btAssert(!findPointer(oldPtr));
531  }
532 
533  chunk->m_dna_nr = getReverseType(structType);
534 
535  chunk->m_chunkCode = chunkCode;
536 
537  void* uniquePtr = getUniquePointer(oldPtr);
538 
539  m_chunkP.insert(oldPtr,uniquePtr);//chunk->m_oldPtr);
540  chunk->m_oldPtr = uniquePtr;//oldPtr;
541 
542  }
543 
544 
545  virtual unsigned char* internalAlloc(size_t size)
546  {
547  unsigned char* ptr = 0;
548 
549  if (m_totalSize)
550  {
551  ptr = m_buffer+m_currentSize;
552  m_currentSize += int(size);
553  btAssert(m_currentSize<m_totalSize);
554  } else
555  {
556  ptr = (unsigned char*)btAlignedAlloc(size,16);
557  m_currentSize += int(size);
558  }
559  return ptr;
560  }
561 
562 
563 
564  virtual btChunk* allocate(size_t size, int numElements)
565  {
566 
567  unsigned char* ptr = internalAlloc(int(size)*numElements+sizeof(btChunk));
568 
569  unsigned char* data = ptr + sizeof(btChunk);
570 
571  btChunk* chunk = (btChunk*)ptr;
572  chunk->m_chunkCode = 0;
573  chunk->m_oldPtr = data;
574  chunk->m_length = int(size)*numElements;
575  chunk->m_number = numElements;
576 
577  m_chunkPtrs.push_back(chunk);
578 
579 
580  return chunk;
581  }
582 
583  virtual const char* findNameForPointer(const void* ptr) const
584  {
585  const char*const * namePtr = m_nameMap.find(ptr);
586  if (namePtr && *namePtr)
587  return *namePtr;
588  return 0;
589 
590  }
591 
592  virtual void registerNameForPointer(const void* ptr, const char* name)
593  {
594  m_nameMap.insert(ptr,name);
595  }
596 
597  virtual void serializeName(const char* name)
598  {
599  if (name)
600  {
601  //don't serialize name twice
602  if (findPointer((void*)name))
603  return;
604 
605  int len = btStrLen(name);
606  if (len)
607  {
608 
609  int newLen = len+1;
610  int padding = ((newLen+3)&~3)-newLen;
611  newLen += padding;
612 
613  //serialize name string now
614  btChunk* chunk = allocate(sizeof(char),newLen);
615  char* destinationName = (char*)chunk->m_oldPtr;
616  for (int i=0;i<len;i++)
617  {
618  destinationName[i] = name[i];
619  }
620  destinationName[len] = 0;
621  finalizeChunk(chunk,"char",BT_ARRAY_CODE,(void*)name);
622  }
623  }
624  }
625 
626  virtual int getSerializationFlags() const
627  {
628  return m_serializationFlags;
629  }
630 
631  virtual void setSerializationFlags(int flags)
632  {
633  m_serializationFlags = flags;
634  }
635 
636 };
637 
638 
639 #endif //BT_SERIALIZER_H
640