1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2014 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 #include "btCollisionWorldImporter.h"
17 #include "btBulletCollisionCommon.h"
18 #include "LinearMath/btSerializer.h" //for btBulletSerializedArrays definition
19 
20 #ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
21 #include "BulletCollision/Gimpact/btGImpactShape.h"
22 #endif //SUPPORT_GIMPACT_SHAPE_IMPORT
23 
btCollisionWorldImporter(btCollisionWorld * world)24 btCollisionWorldImporter::btCollisionWorldImporter(btCollisionWorld* world)
25 :m_collisionWorld(world),
26 m_verboseMode(0)
27 {
28 
29 }
30 
~btCollisionWorldImporter()31 btCollisionWorldImporter::~btCollisionWorldImporter()
32 {
33 }
34 
35 
36 
37 
38 
convertAllObjects(btBulletSerializedArrays * arrays)39 bool	btCollisionWorldImporter::convertAllObjects( btBulletSerializedArrays* arrays)
40 {
41 
42 	m_shapeMap.clear();
43 	m_bodyMap.clear();
44 
45 	int i;
46 
47 	for (i=0;i<arrays->m_bvhsDouble.size();i++)
48 	{
49 		btOptimizedBvh* bvh = createOptimizedBvh();
50 		btQuantizedBvhDoubleData* bvhData = arrays->m_bvhsDouble[i];
51 		bvh->deSerializeDouble(*bvhData);
52 		m_bvhMap.insert(arrays->m_bvhsDouble[i],bvh);
53 	}
54 	for (i=0;i<arrays->m_bvhsFloat.size();i++)
55     {
56         btOptimizedBvh* bvh = createOptimizedBvh();
57    		btQuantizedBvhFloatData* bvhData = arrays->m_bvhsFloat[i];
58 		bvh->deSerializeFloat(*bvhData);
59 		m_bvhMap.insert(arrays->m_bvhsFloat[i],bvh);
60 	}
61 
62 
63 
64 
65 
66 	for (i=0;i<arrays->m_colShapeData.size();i++)
67 	{
68 		btCollisionShapeData* shapeData = arrays->m_colShapeData[i];
69 		btCollisionShape* shape = convertCollisionShape(shapeData);
70 		if (shape)
71 		{
72 	//		printf("shapeMap.insert(%x,%x)\n",shapeData,shape);
73 			m_shapeMap.insert(shapeData,shape);
74 		}
75 
76 		if (shape&& shapeData->m_name)
77 		{
78 			char* newname = duplicateName(shapeData->m_name);
79 			m_objectNameMap.insert(shape,newname);
80 			m_nameShapeMap.insert(newname,shape);
81 		}
82 	}
83 
84 
85 	for (i=0;i<arrays->m_collisionObjectDataDouble.size();i++)
86 	{
87         btCollisionObjectDoubleData* colObjData = arrays->m_collisionObjectDataDouble[i];
88         btCollisionShape** shapePtr = m_shapeMap.find(colObjData->m_collisionShape);
89         if (shapePtr && *shapePtr)
90         {
91             btTransform startTransform;
92             colObjData->m_worldTransform.m_origin.m_floats[3] = 0.f;
93             startTransform.deSerializeDouble(colObjData->m_worldTransform);
94 
95             btCollisionShape* shape = (btCollisionShape*)*shapePtr;
96             btCollisionObject* body = createCollisionObject(startTransform,shape,colObjData->m_name);
97             body->setFriction(btScalar(colObjData->m_friction));
98             body->setRestitution(btScalar(colObjData->m_restitution));
99 
100 #ifdef USE_INTERNAL_EDGE_UTILITY
101             if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
102             {
103                 btBvhTriangleMeshShape* trimesh = (btBvhTriangleMeshShape*)shape;
104                 if (trimesh->getTriangleInfoMap())
105                 {
106                     body->setCollisionFlags(body->getCollisionFlags()  | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
107                 }
108             }
109 #endif //USE_INTERNAL_EDGE_UTILITY
110             m_bodyMap.insert(colObjData,body);
111         } else
112         {
113             printf("error: no shape found\n");
114         }
115 	}
116 	for (i=0;i<arrays->m_collisionObjectDataFloat.size();i++)
117 	{
118         btCollisionObjectFloatData* colObjData = arrays->m_collisionObjectDataFloat[i];
119         btCollisionShape** shapePtr = m_shapeMap.find(colObjData->m_collisionShape);
120         if (shapePtr && *shapePtr)
121         {
122             btTransform startTransform;
123             colObjData->m_worldTransform.m_origin.m_floats[3] = 0.f;
124             startTransform.deSerializeFloat(colObjData->m_worldTransform);
125 
126             btCollisionShape* shape = (btCollisionShape*)*shapePtr;
127             btCollisionObject* body = createCollisionObject(startTransform,shape,colObjData->m_name);
128 
129 #ifdef USE_INTERNAL_EDGE_UTILITY
130             if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
131             {
132                 btBvhTriangleMeshShape* trimesh = (btBvhTriangleMeshShape*)shape;
133                 if (trimesh->getTriangleInfoMap())
134                 {
135                     body->setCollisionFlags(body->getCollisionFlags()  | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
136                 }
137             }
138 #endif //USE_INTERNAL_EDGE_UTILITY
139             m_bodyMap.insert(colObjData,body);
140         } else
141         {
142             printf("error: no shape found\n");
143         }
144     }
145 
146 	return true;
147 }
148 
149 
150 
deleteAllData()151 void btCollisionWorldImporter::deleteAllData()
152 {
153 	int i;
154 
155 	for (i=0;i<m_allocatedCollisionObjects.size();i++)
156 	{
157 		if(m_collisionWorld)
158 			m_collisionWorld->removeCollisionObject(m_allocatedCollisionObjects[i]);
159 		delete m_allocatedCollisionObjects[i];
160 	}
161 
162 	m_allocatedCollisionObjects.clear();
163 
164 
165 	for (i=0;i<m_allocatedCollisionShapes.size();i++)
166 	{
167 		delete m_allocatedCollisionShapes[i];
168 	}
169 	m_allocatedCollisionShapes.clear();
170 
171 
172 	for (i=0;i<m_allocatedBvhs.size();i++)
173 	{
174 		delete m_allocatedBvhs[i];
175 	}
176 	m_allocatedBvhs.clear();
177 
178 	for (i=0;i<m_allocatedTriangleInfoMaps.size();i++)
179 	{
180 		delete m_allocatedTriangleInfoMaps[i];
181 	}
182 	m_allocatedTriangleInfoMaps.clear();
183 	for (i=0;i<m_allocatedTriangleIndexArrays.size();i++)
184 	{
185 		delete m_allocatedTriangleIndexArrays[i];
186 	}
187 	m_allocatedTriangleIndexArrays.clear();
188 	for (i=0;i<m_allocatedNames.size();i++)
189 	{
190 		delete[] m_allocatedNames[i];
191 	}
192 	m_allocatedNames.clear();
193 
194 	for (i=0;i<m_allocatedbtStridingMeshInterfaceDatas.size();i++)
195 	{
196 		btStridingMeshInterfaceData* curData = m_allocatedbtStridingMeshInterfaceDatas[i];
197 
198 		for(int a = 0;a < curData->m_numMeshParts;a++)
199 		{
200 			btMeshPartData* curPart = &curData->m_meshPartsPtr[a];
201 			if(curPart->m_vertices3f)
202 				delete [] curPart->m_vertices3f;
203 
204 			if(curPart->m_vertices3d)
205 				delete [] curPart->m_vertices3d;
206 
207 			if(curPart->m_indices32)
208 				delete [] curPart->m_indices32;
209 
210 			if(curPart->m_3indices16)
211 				delete [] curPart->m_3indices16;
212 
213 			if(curPart->m_indices16)
214 				delete [] curPart->m_indices16;
215 
216 			if (curPart->m_3indices8)
217 				delete [] curPart->m_3indices8;
218 
219 		}
220 		delete [] curData->m_meshPartsPtr;
221 		delete curData;
222 	}
223 	m_allocatedbtStridingMeshInterfaceDatas.clear();
224 
225 	for (i=0;i<m_indexArrays.size();i++)
226 	{
227 		btAlignedFree(m_indexArrays[i]);
228 	}
229   m_indexArrays.clear();
230 
231 	for (i=0;i<m_shortIndexArrays.size();i++)
232 	{
233 		btAlignedFree(m_shortIndexArrays[i]);
234 	}
235   m_shortIndexArrays.clear();
236 
237 	for (i=0;i<m_charIndexArrays.size();i++)
238 	{
239 		btAlignedFree(m_charIndexArrays[i]);
240 	}
241   m_charIndexArrays.clear();
242 
243 	for (i=0;i<m_floatVertexArrays.size();i++)
244 	{
245 		btAlignedFree(m_floatVertexArrays[i]);
246 	}
247   m_floatVertexArrays.clear();
248 
249 	for (i=0;i<m_doubleVertexArrays.size();i++)
250 	{
251 		btAlignedFree(m_doubleVertexArrays[i]);
252 	}
253    m_doubleVertexArrays.clear();
254 
255 
256 }
257 
258 
259 
convertCollisionShape(btCollisionShapeData * shapeData)260 btCollisionShape* btCollisionWorldImporter::convertCollisionShape(  btCollisionShapeData* shapeData  )
261 {
262 	btCollisionShape* shape = 0;
263 
264 	switch (shapeData->m_shapeType)
265 		{
266 	case STATIC_PLANE_PROXYTYPE:
267 		{
268 			btStaticPlaneShapeData* planeData = (btStaticPlaneShapeData*)shapeData;
269 			btVector3 planeNormal,localScaling;
270 			planeNormal.deSerializeFloat(planeData->m_planeNormal);
271 			localScaling.deSerializeFloat(planeData->m_localScaling);
272 			shape = createPlaneShape(planeNormal,planeData->m_planeConstant);
273 			shape->setLocalScaling(localScaling);
274 
275 			break;
276 		}
277 	case SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
278 		{
279 			btScaledTriangleMeshShapeData* scaledMesh = (btScaledTriangleMeshShapeData*) shapeData;
280 			btCollisionShapeData* colShapeData = (btCollisionShapeData*) &scaledMesh->m_trimeshShapeData;
281 			colShapeData->m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE;
282 			btCollisionShape* childShape = convertCollisionShape(colShapeData);
283 			btBvhTriangleMeshShape* meshShape = (btBvhTriangleMeshShape*)childShape;
284 			btVector3 localScaling;
285 			localScaling.deSerializeFloat(scaledMesh->m_localScaling);
286 
287 			shape = createScaledTrangleMeshShape(meshShape, localScaling);
288 			break;
289 		}
290 #ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
291 	case GIMPACT_SHAPE_PROXYTYPE:
292 		{
293 			btGImpactMeshShapeData* gimpactData = (btGImpactMeshShapeData*) shapeData;
294 			if (gimpactData->m_gimpactSubType == CONST_GIMPACT_TRIMESH_SHAPE)
295 			{
296 				btStridingMeshInterfaceData* interfaceData = createStridingMeshInterfaceData(&gimpactData->m_meshInterface);
297 				btTriangleIndexVertexArray* meshInterface = createMeshInterface(*interfaceData);
298 
299 
300 				btGImpactMeshShape* gimpactShape = createGimpactShape(meshInterface);
301 				btVector3 localScaling;
302 				localScaling.deSerializeFloat(gimpactData->m_localScaling);
303 				gimpactShape->setLocalScaling(localScaling);
304 				gimpactShape->setMargin(btScalar(gimpactData->m_collisionMargin));
305 				gimpactShape->updateBound();
306 				shape = gimpactShape;
307 			} else
308 			{
309 				printf("unsupported gimpact sub type\n");
310 			}
311 			break;
312 		}
313 #endif //SUPPORT_GIMPACT_SHAPE_IMPORT
314 	//The btCapsuleShape* API has issue passing the margin/scaling/halfextents unmodified through the API
315 	//so deal with this
316 		case CAPSULE_SHAPE_PROXYTYPE:
317 		{
318 			btCapsuleShapeData* capData = (btCapsuleShapeData*)shapeData;
319 
320 
321 			switch (capData->m_upAxis)
322 			{
323 			case 0:
324 				{
325 					shape = createCapsuleShapeX(1,1);
326 					break;
327 				}
328 			case 1:
329 				{
330 					shape = createCapsuleShapeY(1,1);
331 					break;
332 				}
333 			case 2:
334 				{
335 					shape = createCapsuleShapeZ(1,1);
336 					break;
337 				}
338 			default:
339 				{
340 					printf("error: wrong up axis for btCapsuleShape\n");
341 				}
342 
343 
344 			};
345 			if (shape)
346 			{
347 				btCapsuleShape* cap = (btCapsuleShape*) shape;
348 				cap->deSerializeFloat(capData);
349 			}
350 			break;
351 		}
352 		case CYLINDER_SHAPE_PROXYTYPE:
353 		case CONE_SHAPE_PROXYTYPE:
354 		case BOX_SHAPE_PROXYTYPE:
355 		case SPHERE_SHAPE_PROXYTYPE:
356 		case MULTI_SPHERE_SHAPE_PROXYTYPE:
357 		case CONVEX_HULL_SHAPE_PROXYTYPE:
358 			{
359 				btConvexInternalShapeData* bsd = (btConvexInternalShapeData*)shapeData;
360 				btVector3 implicitShapeDimensions;
361 				implicitShapeDimensions.deSerializeFloat(bsd->m_implicitShapeDimensions);
362 				btVector3 localScaling;
363 				localScaling.deSerializeFloat(bsd->m_localScaling);
364 				btVector3 margin(bsd->m_collisionMargin,bsd->m_collisionMargin,bsd->m_collisionMargin);
365 				switch (shapeData->m_shapeType)
366 				{
367 					case BOX_SHAPE_PROXYTYPE:
368 						{
369 							btBoxShape* box= (btBoxShape*)createBoxShape(implicitShapeDimensions/localScaling+margin);
370 							//box->initializePolyhedralFeatures();
371 							shape = box;
372 
373 							break;
374 						}
375 					case SPHERE_SHAPE_PROXYTYPE:
376 						{
377 							shape = createSphereShape(implicitShapeDimensions.getX());
378 							break;
379 						}
380 
381 					case CYLINDER_SHAPE_PROXYTYPE:
382 						{
383 							btCylinderShapeData* cylData = (btCylinderShapeData*) shapeData;
384 							btVector3 halfExtents = implicitShapeDimensions+margin;
385 							switch (cylData->m_upAxis)
386 							{
387 							case 0:
388 								{
389 									shape = createCylinderShapeX(halfExtents.getY(),halfExtents.getX());
390 									break;
391 								}
392 							case 1:
393 								{
394 									shape = createCylinderShapeY(halfExtents.getX(),halfExtents.getY());
395 									break;
396 								}
397 							case 2:
398 								{
399 									shape = createCylinderShapeZ(halfExtents.getX(),halfExtents.getZ());
400 									break;
401 								}
402 							default:
403 								{
404 									printf("unknown Cylinder up axis\n");
405 								}
406 
407 							};
408 
409 
410 
411 							break;
412 						}
413 					case CONE_SHAPE_PROXYTYPE:
414 						{
415 							btConeShapeData* conData = (btConeShapeData*) shapeData;
416 							btVector3 halfExtents = implicitShapeDimensions;//+margin;
417 							switch (conData->m_upIndex)
418 							{
419 							case 0:
420 								{
421 									shape = createConeShapeX(halfExtents.getY(),halfExtents.getX());
422 									break;
423 								}
424 							case 1:
425 								{
426 									shape = createConeShapeY(halfExtents.getX(),halfExtents.getY());
427 									break;
428 								}
429 							case 2:
430 								{
431 									shape = createConeShapeZ(halfExtents.getX(),halfExtents.getZ());
432 									break;
433 								}
434 							default:
435 								{
436 									printf("unknown Cone up axis\n");
437 								}
438 
439 							};
440 
441 
442 
443 							break;
444 						}
445 					case MULTI_SPHERE_SHAPE_PROXYTYPE:
446 						{
447 							btMultiSphereShapeData* mss = (btMultiSphereShapeData*)bsd;
448 							int numSpheres = mss->m_localPositionArraySize;
449 
450 							btAlignedObjectArray<btVector3> tmpPos;
451 							btAlignedObjectArray<btScalar> radii;
452 							radii.resize(numSpheres);
453 							tmpPos.resize(numSpheres);
454 							int i;
455 							for ( i=0;i<numSpheres;i++)
456 							{
457 								tmpPos[i].deSerializeFloat(mss->m_localPositionArrayPtr[i].m_pos);
458 								radii[i] = mss->m_localPositionArrayPtr[i].m_radius;
459 							}
460 							shape = createMultiSphereShape(&tmpPos[0],&radii[0],numSpheres);
461 							break;
462 						}
463 					case CONVEX_HULL_SHAPE_PROXYTYPE:
464 						{
465 						//	int sz = sizeof(btConvexHullShapeData);
466 						//	int sz2 = sizeof(btConvexInternalShapeData);
467 						//	int sz3 = sizeof(btCollisionShapeData);
468 							btConvexHullShapeData* convexData = (btConvexHullShapeData*)bsd;
469 							int numPoints = convexData->m_numUnscaledPoints;
470 
471 							btAlignedObjectArray<btVector3> tmpPoints;
472 							tmpPoints.resize(numPoints);
473 							int i;
474 							for ( i=0;i<numPoints;i++)
475 							{
476 #ifdef BT_USE_DOUBLE_PRECISION
477 							if (convexData->m_unscaledPointsDoublePtr)
478 								tmpPoints[i].deSerialize(convexData->m_unscaledPointsDoublePtr[i]);
479 							if (convexData->m_unscaledPointsFloatPtr)
480 								tmpPoints[i].deSerializeFloat(convexData->m_unscaledPointsFloatPtr[i]);
481 #else
482 							if (convexData->m_unscaledPointsFloatPtr)
483 								tmpPoints[i].deSerialize(convexData->m_unscaledPointsFloatPtr[i]);
484 							if (convexData->m_unscaledPointsDoublePtr)
485 								tmpPoints[i].deSerializeDouble(convexData->m_unscaledPointsDoublePtr[i]);
486 #endif //BT_USE_DOUBLE_PRECISION
487 							}
488 							btConvexHullShape* hullShape = createConvexHullShape();
489 							for (i=0;i<numPoints;i++)
490 							{
491 								hullShape->addPoint(tmpPoints[i]);
492 							}
493 							hullShape->setMargin(bsd->m_collisionMargin);
494 							//hullShape->initializePolyhedralFeatures();
495 							shape = hullShape;
496 							break;
497 						}
498 					default:
499 						{
500 							printf("error: cannot create shape type (%d)\n",shapeData->m_shapeType);
501 						}
502 				}
503 
504 				if (shape)
505 				{
506 					shape->setMargin(bsd->m_collisionMargin);
507 
508 					btVector3 localScaling;
509 					localScaling.deSerializeFloat(bsd->m_localScaling);
510 					shape->setLocalScaling(localScaling);
511 
512 				}
513 				break;
514 			}
515 		case TRIANGLE_MESH_SHAPE_PROXYTYPE:
516 		{
517 			btTriangleMeshShapeData* trimesh = (btTriangleMeshShapeData*)shapeData;
518 			btStridingMeshInterfaceData* interfaceData = createStridingMeshInterfaceData(&trimesh->m_meshInterface);
519 			btTriangleIndexVertexArray* meshInterface = createMeshInterface(*interfaceData);
520 			if (!meshInterface->getNumSubParts())
521 			{
522 				return 0;
523 			}
524 
525 			btVector3 scaling; scaling.deSerializeFloat(trimesh->m_meshInterface.m_scaling);
526 			meshInterface->setScaling(scaling);
527 
528 
529 			btOptimizedBvh* bvh = 0;
530 #if 1
531 			if (trimesh->m_quantizedFloatBvh)
532 			{
533 				btOptimizedBvh** bvhPtr = m_bvhMap.find(trimesh->m_quantizedFloatBvh);
534 				if (bvhPtr && *bvhPtr)
535 				{
536 					bvh = *bvhPtr;
537 				} else
538 				{
539 					bvh = createOptimizedBvh();
540 					bvh->deSerializeFloat(*trimesh->m_quantizedFloatBvh);
541 				}
542 			}
543 			if (trimesh->m_quantizedDoubleBvh)
544 			{
545 				btOptimizedBvh** bvhPtr = m_bvhMap.find(trimesh->m_quantizedDoubleBvh);
546 				if (bvhPtr && *bvhPtr)
547 				{
548 					bvh = *bvhPtr;
549 				} else
550 				{
551 					bvh = createOptimizedBvh();
552 					bvh->deSerializeDouble(*trimesh->m_quantizedDoubleBvh);
553 				}
554 			}
555 #endif
556 
557 
558 			btBvhTriangleMeshShape* trimeshShape = createBvhTriangleMeshShape(meshInterface,bvh);
559 			trimeshShape->setMargin(trimesh->m_collisionMargin);
560 			shape = trimeshShape;
561 
562 			if (trimesh->m_triangleInfoMap)
563 			{
564 				btTriangleInfoMap* map = createTriangleInfoMap();
565 				map->deSerialize(*trimesh->m_triangleInfoMap);
566 				trimeshShape->setTriangleInfoMap(map);
567 
568 #ifdef USE_INTERNAL_EDGE_UTILITY
569 				gContactAddedCallback = btAdjustInternalEdgeContactsCallback;
570 #endif //USE_INTERNAL_EDGE_UTILITY
571 
572 			}
573 
574 			//printf("trimesh->m_collisionMargin=%f\n",trimesh->m_collisionMargin);
575 			break;
576 		}
577 		case COMPOUND_SHAPE_PROXYTYPE:
578 			{
579 				btCompoundShapeData* compoundData = (btCompoundShapeData*)shapeData;
580 				btCompoundShape* compoundShape = createCompoundShape();
581 
582 				//btCompoundShapeChildData* childShapeDataArray = &compoundData->m_childShapePtr[0];
583 
584 
585 				btAlignedObjectArray<btCollisionShape*> childShapes;
586 				for (int i=0;i<compoundData->m_numChildShapes;i++)
587 				{
588 					//btCompoundShapeChildData* ptr = &compoundData->m_childShapePtr[i];
589 
590 					btCollisionShapeData* cd = compoundData->m_childShapePtr[i].m_childShape;
591 
592 					btCollisionShape* childShape = convertCollisionShape(cd);
593 					if (childShape)
594 					{
595 						btTransform localTransform;
596 						localTransform.deSerializeFloat(compoundData->m_childShapePtr[i].m_transform);
597 						compoundShape->addChildShape(localTransform,childShape);
598 					} else
599 					{
600 #ifdef _DEBUG
601 						printf("error: couldn't create childShape for compoundShape\n");
602 #endif
603 					}
604 
605 				}
606 				shape = compoundShape;
607 
608 				break;
609 			}
610 		case SOFTBODY_SHAPE_PROXYTYPE:
611 			{
612 				return 0;
613 			}
614 		default:
615 			{
616 #ifdef _DEBUG
617 				printf("unsupported shape type (%d)\n",shapeData->m_shapeType);
618 #endif
619 			}
620 		}
621 
622 		return shape;
623 
624 }
625 
626 
627 
duplicateName(const char * name)628 char* btCollisionWorldImporter::duplicateName(const char* name)
629 {
630 	if (name)
631 	{
632 		int l = (int)strlen(name);
633 		char* newName = new char[l+1];
634 		memcpy(newName,name,l);
635 		newName[l] = 0;
636 		m_allocatedNames.push_back(newName);
637 		return newName;
638 	}
639 	return 0;
640 }
641 
642 
643 
644 
645 
646 
647 
648 
649 
650 
651 
createMeshInterface(btStridingMeshInterfaceData & meshData)652 btTriangleIndexVertexArray* btCollisionWorldImporter::createMeshInterface(btStridingMeshInterfaceData&  meshData)
653 {
654 	btTriangleIndexVertexArray* meshInterface = createTriangleMeshContainer();
655 
656 	for (int i=0;i<meshData.m_numMeshParts;i++)
657 	{
658 		btIndexedMesh meshPart;
659 		meshPart.m_numTriangles = meshData.m_meshPartsPtr[i].m_numTriangles;
660 		meshPart.m_numVertices = meshData.m_meshPartsPtr[i].m_numVertices;
661 
662 
663 		if (meshData.m_meshPartsPtr[i].m_indices32)
664 		{
665 			meshPart.m_indexType = PHY_INTEGER;
666 			meshPart.m_triangleIndexStride = 3*sizeof(int);
667 			int* indexArray = (int*)btAlignedAlloc(sizeof(int)*3*meshPart.m_numTriangles,16);
668 			m_indexArrays.push_back(indexArray);
669 			for (int j=0;j<3*meshPart.m_numTriangles;j++)
670 			{
671 				indexArray[j] = meshData.m_meshPartsPtr[i].m_indices32[j].m_value;
672 			}
673 			meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
674 		} else
675 		{
676 			if (meshData.m_meshPartsPtr[i].m_3indices16)
677 			{
678 				meshPart.m_indexType = PHY_SHORT;
679 				meshPart.m_triangleIndexStride = sizeof(short int)*3;//sizeof(btShortIntIndexTripletData);
680 
681 				short int* indexArray = (short int*)btAlignedAlloc(sizeof(short int)*3*meshPart.m_numTriangles,16);
682 				m_shortIndexArrays.push_back(indexArray);
683 
684 				for (int j=0;j<meshPart.m_numTriangles;j++)
685 				{
686 					indexArray[3*j] = meshData.m_meshPartsPtr[i].m_3indices16[j].m_values[0];
687 					indexArray[3*j+1] = meshData.m_meshPartsPtr[i].m_3indices16[j].m_values[1];
688 					indexArray[3*j+2] = meshData.m_meshPartsPtr[i].m_3indices16[j].m_values[2];
689 				}
690 
691 				meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
692 			}
693 			if (meshData.m_meshPartsPtr[i].m_indices16)
694 			{
695 				meshPart.m_indexType = PHY_SHORT;
696 				meshPart.m_triangleIndexStride = 3*sizeof(short int);
697 				short int* indexArray = (short int*)btAlignedAlloc(sizeof(short int)*3*meshPart.m_numTriangles,16);
698 				m_shortIndexArrays.push_back(indexArray);
699 				for (int j=0;j<3*meshPart.m_numTriangles;j++)
700 				{
701 					indexArray[j] = meshData.m_meshPartsPtr[i].m_indices16[j].m_value;
702 				}
703 
704 				meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
705 			}
706 
707 			if (meshData.m_meshPartsPtr[i].m_3indices8)
708 			{
709 				meshPart.m_indexType = PHY_UCHAR;
710 				meshPart.m_triangleIndexStride = sizeof(unsigned char)*3;
711 
712 				unsigned char* indexArray = (unsigned char*)btAlignedAlloc(sizeof(unsigned char)*3*meshPart.m_numTriangles,16);
713 				m_charIndexArrays.push_back(indexArray);
714 
715 				for (int j=0;j<meshPart.m_numTriangles;j++)
716 				{
717 					indexArray[3*j] = meshData.m_meshPartsPtr[i].m_3indices8[j].m_values[0];
718 					indexArray[3*j+1] = meshData.m_meshPartsPtr[i].m_3indices8[j].m_values[1];
719 					indexArray[3*j+2] = meshData.m_meshPartsPtr[i].m_3indices8[j].m_values[2];
720 				}
721 
722 				meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
723 			}
724 		}
725 
726 		if (meshData.m_meshPartsPtr[i].m_vertices3f)
727 		{
728 			meshPart.m_vertexType = PHY_FLOAT;
729 			meshPart.m_vertexStride = sizeof(btVector3FloatData);
730 			btVector3FloatData* vertices = (btVector3FloatData*) btAlignedAlloc(sizeof(btVector3FloatData)*meshPart.m_numVertices,16);
731 			m_floatVertexArrays.push_back(vertices);
732 
733 			for (int j=0;j<meshPart.m_numVertices;j++)
734 			{
735 				vertices[j].m_floats[0] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[0];
736 				vertices[j].m_floats[1] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[1];
737 				vertices[j].m_floats[2] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[2];
738 				vertices[j].m_floats[3] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[3];
739 			}
740 			meshPart.m_vertexBase = (const unsigned char*)vertices;
741 		} else
742 		{
743 			meshPart.m_vertexType = PHY_DOUBLE;
744 			meshPart.m_vertexStride = sizeof(btVector3DoubleData);
745 
746 
747 			btVector3DoubleData* vertices = (btVector3DoubleData*) btAlignedAlloc(sizeof(btVector3DoubleData)*meshPart.m_numVertices,16);
748 			m_doubleVertexArrays.push_back(vertices);
749 
750 			for (int j=0;j<meshPart.m_numVertices;j++)
751 			{
752 				vertices[j].m_floats[0] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[0];
753 				vertices[j].m_floats[1] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[1];
754 				vertices[j].m_floats[2] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[2];
755 				vertices[j].m_floats[3] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[3];
756 			}
757 			meshPart.m_vertexBase = (const unsigned char*)vertices;
758 		}
759 
760 		if (meshPart.m_triangleIndexBase && meshPart.m_vertexBase)
761 		{
762 			meshInterface->addIndexedMesh(meshPart,meshPart.m_indexType);
763 		}
764 	}
765 
766 	return meshInterface;
767 }
768 
769 
createStridingMeshInterfaceData(btStridingMeshInterfaceData * interfaceData)770 btStridingMeshInterfaceData* btCollisionWorldImporter::createStridingMeshInterfaceData(btStridingMeshInterfaceData* interfaceData)
771 {
772 	//create a new btStridingMeshInterfaceData that is an exact copy of shapedata and store it in the WorldImporter
773 	btStridingMeshInterfaceData* newData = new btStridingMeshInterfaceData;
774 
775 	newData->m_scaling = interfaceData->m_scaling;
776 	newData->m_numMeshParts = interfaceData->m_numMeshParts;
777 	newData->m_meshPartsPtr = new btMeshPartData[newData->m_numMeshParts];
778 
779 	for(int i = 0;i < newData->m_numMeshParts;i++)
780 	{
781 		btMeshPartData* curPart = &interfaceData->m_meshPartsPtr[i];
782 		btMeshPartData* curNewPart = &newData->m_meshPartsPtr[i];
783 
784 		curNewPart->m_numTriangles = curPart->m_numTriangles;
785 		curNewPart->m_numVertices = curPart->m_numVertices;
786 
787 		if(curPart->m_vertices3f)
788 		{
789 			curNewPart->m_vertices3f = new btVector3FloatData[curNewPart->m_numVertices];
790 			memcpy(curNewPart->m_vertices3f,curPart->m_vertices3f,sizeof(btVector3FloatData) * curNewPart->m_numVertices);
791 		}
792 		else
793 			curNewPart->m_vertices3f = NULL;
794 
795 		if(curPart->m_vertices3d)
796 		{
797 			curNewPart->m_vertices3d = new btVector3DoubleData[curNewPart->m_numVertices];
798 			memcpy(curNewPart->m_vertices3d,curPart->m_vertices3d,sizeof(btVector3DoubleData) * curNewPart->m_numVertices);
799 		}
800 		else
801 			curNewPart->m_vertices3d = NULL;
802 
803 		int numIndices = curNewPart->m_numTriangles * 3;
804 		///the m_3indices8 was not initialized in some Bullet versions, this can cause crashes at loading time
805 		///we catch it by only dealing with m_3indices8 if none of the other indices are initialized
806 		bool uninitialized3indices8Workaround =false;
807 
808 		if(curPart->m_indices32)
809 		{
810 			uninitialized3indices8Workaround=true;
811 			curNewPart->m_indices32 = new btIntIndexData[numIndices];
812 			memcpy(curNewPart->m_indices32,curPart->m_indices32,sizeof(btIntIndexData) * numIndices);
813 		}
814 		else
815 			curNewPart->m_indices32 = NULL;
816 
817 		if(curPart->m_3indices16)
818 		{
819 			uninitialized3indices8Workaround=true;
820 			curNewPart->m_3indices16 = new btShortIntIndexTripletData[curNewPart->m_numTriangles];
821 			memcpy(curNewPart->m_3indices16,curPart->m_3indices16,sizeof(btShortIntIndexTripletData) * curNewPart->m_numTriangles);
822 		}
823 		else
824 			curNewPart->m_3indices16 = NULL;
825 
826 		if(curPart->m_indices16)
827 		{
828 			uninitialized3indices8Workaround=true;
829 			curNewPart->m_indices16 = new btShortIntIndexData[numIndices];
830 			memcpy(curNewPart->m_indices16,curPart->m_indices16,sizeof(btShortIntIndexData) * numIndices);
831 		}
832 		else
833 			curNewPart->m_indices16 = NULL;
834 
835 		if(!uninitialized3indices8Workaround && curPart->m_3indices8)
836 		{
837 			curNewPart->m_3indices8 = new btCharIndexTripletData[curNewPart->m_numTriangles];
838 			memcpy(curNewPart->m_3indices8,curPart->m_3indices8,sizeof(btCharIndexTripletData) * curNewPart->m_numTriangles);
839 		}
840 		else
841 			curNewPart->m_3indices8 = NULL;
842 
843 	}
844 
845 	m_allocatedbtStridingMeshInterfaceDatas.push_back(newData);
846 
847 	return(newData);
848 }
849 
850 #ifdef USE_INTERNAL_EDGE_UTILITY
851 extern ContactAddedCallback		gContactAddedCallback;
852 
btAdjustInternalEdgeContactsCallback(btManifoldPoint & cp,const btCollisionObject * colObj0,int partId0,int index0,const btCollisionObject * colObj1,int partId1,int index1)853 static bool btAdjustInternalEdgeContactsCallback(btManifoldPoint& cp,	const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1)
854 {
855 
856 	btAdjustInternalEdgeContacts(cp,colObj1,colObj0, partId1,index1);
857 		//btAdjustInternalEdgeContacts(cp,colObj1,colObj0, partId1,index1, BT_TRIANGLE_CONVEX_BACKFACE_MODE);
858 		//btAdjustInternalEdgeContacts(cp,colObj1,colObj0, partId1,index1, BT_TRIANGLE_CONVEX_DOUBLE_SIDED+BT_TRIANGLE_CONCAVE_DOUBLE_SIDED);
859 	return true;
860 }
861 #endif //USE_INTERNAL_EDGE_UTILITY
862 
863 
864 /*
865 btRigidBody*  btWorldImporter::createRigidBody(bool isDynamic, btScalar mass, const btTransform& startTransform,btCollisionShape* shape,const char* bodyName)
866 {
867 	btVector3 localInertia;
868 	localInertia.setZero();
869 
870 	if (mass)
871 		shape->calculateLocalInertia(mass,localInertia);
872 
873 	btRigidBody* body = new btRigidBody(mass,0,shape,localInertia);
874 	body->setWorldTransform(startTransform);
875 
876 	if (m_dynamicsWorld)
877 		m_dynamicsWorld->addRigidBody(body);
878 
879 	if (bodyName)
880 	{
881 		char* newname = duplicateName(bodyName);
882 		m_objectNameMap.insert(body,newname);
883 		m_nameBodyMap.insert(newname,body);
884 	}
885 	m_allocatedRigidBodies.push_back(body);
886 	return body;
887 
888 }
889 */
890 
getCollisionObjectByName(const char * name)891 btCollisionObject* btCollisionWorldImporter::getCollisionObjectByName(const char* name)
892 {
893 	btCollisionObject** bodyPtr = m_nameColObjMap.find(name);
894 	if (bodyPtr && *bodyPtr)
895 	{
896 		return *bodyPtr;
897 	}
898 	return 0;
899 }
900 
createCollisionObject(const btTransform & startTransform,btCollisionShape * shape,const char * bodyName)901 btCollisionObject* btCollisionWorldImporter::createCollisionObject(const btTransform& startTransform,btCollisionShape* shape, const char* bodyName)
902 {
903 	btCollisionObject* colObj = new btCollisionObject();
904 	colObj->setWorldTransform(startTransform);
905 	colObj->setCollisionShape(shape);
906 	m_collisionWorld->addCollisionObject(colObj);//todo: flags etc
907 
908 	if (bodyName)
909 	{
910 		char* newname = duplicateName(bodyName);
911 		m_objectNameMap.insert(colObj,newname);
912 		m_nameColObjMap.insert(newname,colObj);
913 	}
914 	m_allocatedCollisionObjects.push_back(colObj);
915 
916 	return colObj;
917 }
918 
919 
920 
createPlaneShape(const btVector3 & planeNormal,btScalar planeConstant)921 btCollisionShape* btCollisionWorldImporter::createPlaneShape(const btVector3& planeNormal,btScalar planeConstant)
922 {
923 	btStaticPlaneShape* shape = new btStaticPlaneShape(planeNormal,planeConstant);
924 	m_allocatedCollisionShapes.push_back(shape);
925 	return shape;
926 }
createBoxShape(const btVector3 & halfExtents)927 btCollisionShape* btCollisionWorldImporter::createBoxShape(const btVector3& halfExtents)
928 {
929 	btBoxShape* shape = new btBoxShape(halfExtents);
930 	m_allocatedCollisionShapes.push_back(shape);
931 	return shape;
932 }
createSphereShape(btScalar radius)933 btCollisionShape* btCollisionWorldImporter::createSphereShape(btScalar radius)
934 {
935 	btSphereShape* shape = new btSphereShape(radius);
936 	m_allocatedCollisionShapes.push_back(shape);
937 	return shape;
938 }
939 
940 
createCapsuleShapeX(btScalar radius,btScalar height)941 btCollisionShape* btCollisionWorldImporter::createCapsuleShapeX(btScalar radius, btScalar height)
942 {
943 	btCapsuleShapeX* shape = new btCapsuleShapeX(radius,height);
944 	m_allocatedCollisionShapes.push_back(shape);
945 	return shape;
946 }
947 
createCapsuleShapeY(btScalar radius,btScalar height)948 btCollisionShape* btCollisionWorldImporter::createCapsuleShapeY(btScalar radius, btScalar height)
949 {
950 	btCapsuleShape* shape = new btCapsuleShape(radius,height);
951 	m_allocatedCollisionShapes.push_back(shape);
952 	return shape;
953 }
954 
createCapsuleShapeZ(btScalar radius,btScalar height)955 btCollisionShape* btCollisionWorldImporter::createCapsuleShapeZ(btScalar radius, btScalar height)
956 {
957 	btCapsuleShapeZ* shape = new btCapsuleShapeZ(radius,height);
958 	m_allocatedCollisionShapes.push_back(shape);
959 	return shape;
960 }
961 
createCylinderShapeX(btScalar radius,btScalar height)962 btCollisionShape* btCollisionWorldImporter::createCylinderShapeX(btScalar radius,btScalar height)
963 {
964 	btCylinderShapeX* shape = new btCylinderShapeX(btVector3(height,radius,radius));
965 	m_allocatedCollisionShapes.push_back(shape);
966 	return shape;
967 }
968 
createCylinderShapeY(btScalar radius,btScalar height)969 btCollisionShape* btCollisionWorldImporter::createCylinderShapeY(btScalar radius,btScalar height)
970 {
971 	btCylinderShape* shape = new btCylinderShape(btVector3(radius,height,radius));
972 	m_allocatedCollisionShapes.push_back(shape);
973 	return shape;
974 }
975 
createCylinderShapeZ(btScalar radius,btScalar height)976 btCollisionShape* btCollisionWorldImporter::createCylinderShapeZ(btScalar radius,btScalar height)
977 {
978 	btCylinderShapeZ* shape = new btCylinderShapeZ(btVector3(radius,radius,height));
979 	m_allocatedCollisionShapes.push_back(shape);
980 	return shape;
981 }
982 
createConeShapeX(btScalar radius,btScalar height)983 btCollisionShape* btCollisionWorldImporter::createConeShapeX(btScalar radius,btScalar height)
984 {
985 	btConeShapeX* shape = new btConeShapeX(radius,height);
986 	m_allocatedCollisionShapes.push_back(shape);
987 	return shape;
988 }
989 
createConeShapeY(btScalar radius,btScalar height)990 btCollisionShape* btCollisionWorldImporter::createConeShapeY(btScalar radius,btScalar height)
991 {
992 	btConeShape* shape = new btConeShape(radius,height);
993 	m_allocatedCollisionShapes.push_back(shape);
994 	return shape;
995 }
996 
createConeShapeZ(btScalar radius,btScalar height)997 btCollisionShape* btCollisionWorldImporter::createConeShapeZ(btScalar radius,btScalar height)
998 {
999 	btConeShapeZ* shape = new btConeShapeZ(radius,height);
1000 	m_allocatedCollisionShapes.push_back(shape);
1001 	return shape;
1002 }
1003 
createTriangleMeshContainer()1004 btTriangleIndexVertexArray*	btCollisionWorldImporter::createTriangleMeshContainer()
1005 {
1006 	btTriangleIndexVertexArray* in = new btTriangleIndexVertexArray();
1007 	m_allocatedTriangleIndexArrays.push_back(in);
1008 	return in;
1009 }
1010 
createOptimizedBvh()1011 btOptimizedBvh*	btCollisionWorldImporter::createOptimizedBvh()
1012 {
1013 	btOptimizedBvh* bvh = new btOptimizedBvh();
1014 	m_allocatedBvhs.push_back(bvh);
1015 	return bvh;
1016 }
1017 
1018 
createTriangleInfoMap()1019 btTriangleInfoMap* btCollisionWorldImporter::createTriangleInfoMap()
1020 {
1021 	btTriangleInfoMap* tim = new btTriangleInfoMap();
1022 	m_allocatedTriangleInfoMaps.push_back(tim);
1023 	return tim;
1024 }
1025 
createBvhTriangleMeshShape(btStridingMeshInterface * trimesh,btOptimizedBvh * bvh)1026 btBvhTriangleMeshShape* btCollisionWorldImporter::createBvhTriangleMeshShape(btStridingMeshInterface* trimesh, btOptimizedBvh* bvh)
1027 {
1028 	if (bvh)
1029 	{
1030 		btBvhTriangleMeshShape* bvhTriMesh = new btBvhTriangleMeshShape(trimesh,bvh->isQuantized(), false);
1031 		bvhTriMesh->setOptimizedBvh(bvh);
1032 		m_allocatedCollisionShapes.push_back(bvhTriMesh);
1033 		return bvhTriMesh;
1034 	}
1035 
1036 	btBvhTriangleMeshShape* ts = new btBvhTriangleMeshShape(trimesh,true);
1037 	m_allocatedCollisionShapes.push_back(ts);
1038 	return ts;
1039 
1040 }
createConvexTriangleMeshShape(btStridingMeshInterface * trimesh)1041 btCollisionShape* btCollisionWorldImporter::createConvexTriangleMeshShape(btStridingMeshInterface* trimesh)
1042 {
1043 	return 0;
1044 }
1045 #ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
createGimpactShape(btStridingMeshInterface * trimesh)1046 btGImpactMeshShape* btCollisionWorldImporter::createGimpactShape(btStridingMeshInterface* trimesh)
1047 {
1048 	btGImpactMeshShape* shape = new btGImpactMeshShape(trimesh);
1049 	m_allocatedCollisionShapes.push_back(shape);
1050 	return shape;
1051 
1052 }
1053 #endif //SUPPORT_GIMPACT_SHAPE_IMPORT
1054 
createConvexHullShape()1055 btConvexHullShape* btCollisionWorldImporter::createConvexHullShape()
1056 {
1057 	btConvexHullShape* shape = new btConvexHullShape();
1058 	m_allocatedCollisionShapes.push_back(shape);
1059 	return shape;
1060 }
1061 
createCompoundShape()1062 btCompoundShape* btCollisionWorldImporter::createCompoundShape()
1063 {
1064 	btCompoundShape* shape = new btCompoundShape();
1065 	m_allocatedCollisionShapes.push_back(shape);
1066 	return shape;
1067 }
1068 
1069 
createScaledTrangleMeshShape(btBvhTriangleMeshShape * meshShape,const btVector3 & localScaling)1070 btScaledBvhTriangleMeshShape* btCollisionWorldImporter::createScaledTrangleMeshShape(btBvhTriangleMeshShape* meshShape,const btVector3& localScaling)
1071 {
1072 	btScaledBvhTriangleMeshShape* shape = new btScaledBvhTriangleMeshShape(meshShape,localScaling);
1073 	m_allocatedCollisionShapes.push_back(shape);
1074 	return shape;
1075 }
1076 
createMultiSphereShape(const btVector3 * positions,const btScalar * radi,int numSpheres)1077 btMultiSphereShape* btCollisionWorldImporter::createMultiSphereShape(const btVector3* positions,const btScalar* radi,int numSpheres)
1078 {
1079 	btMultiSphereShape* shape = new btMultiSphereShape(positions, radi, numSpheres);
1080 	m_allocatedCollisionShapes.push_back(shape);
1081 	return shape;
1082 }
1083 
1084 
1085 
1086 	// query for data
getNumCollisionShapes() const1087 int	btCollisionWorldImporter::getNumCollisionShapes() const
1088 {
1089 	return m_allocatedCollisionShapes.size();
1090 }
1091 
getCollisionShapeByIndex(int index)1092 btCollisionShape* btCollisionWorldImporter::getCollisionShapeByIndex(int index)
1093 {
1094 	return m_allocatedCollisionShapes[index];
1095 }
1096 
getCollisionShapeByName(const char * name)1097 btCollisionShape* btCollisionWorldImporter::getCollisionShapeByName(const char* name)
1098 {
1099 	btCollisionShape** shapePtr = m_nameShapeMap.find(name);
1100 	if (shapePtr&& *shapePtr)
1101 	{
1102 		return *shapePtr;
1103 	}
1104 	return 0;
1105 }
1106 
1107 
getNameForPointer(const void * ptr) const1108 const char*	btCollisionWorldImporter::getNameForPointer(const void* ptr) const
1109 {
1110 	const char*const * namePtr = m_objectNameMap.find(ptr);
1111 	if (namePtr && *namePtr)
1112 		return *namePtr;
1113 	return 0;
1114 }
1115 
1116 
getNumRigidBodies() const1117 int btCollisionWorldImporter::getNumRigidBodies() const
1118 {
1119 	return m_allocatedRigidBodies.size();
1120 }
1121 
getRigidBodyByIndex(int index) const1122 btCollisionObject* btCollisionWorldImporter::getRigidBodyByIndex(int index) const
1123 {
1124 	return m_allocatedRigidBodies[index];
1125 }
1126 
1127 
getNumBvhs() const1128 int btCollisionWorldImporter::getNumBvhs() const
1129 {
1130 	return m_allocatedBvhs.size();
1131 }
getBvhByIndex(int index) const1132  btOptimizedBvh* btCollisionWorldImporter::getBvhByIndex(int index) const
1133 {
1134 	return m_allocatedBvhs[index];
1135 }
1136 
getNumTriangleInfoMaps() const1137 int btCollisionWorldImporter::getNumTriangleInfoMaps() const
1138 {
1139 	return m_allocatedTriangleInfoMaps.size();
1140 }
1141 
getTriangleInfoMapByIndex(int index) const1142 btTriangleInfoMap* btCollisionWorldImporter::getTriangleInfoMapByIndex(int index) const
1143 {
1144 	return m_allocatedTriangleInfoMaps[index];
1145 }
1146 
1147 
1148