diff options
Diffstat (limited to '')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 296 |
1 files changed, 181 insertions, 115 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 861ffe7..d3ba273 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -117,7 +117,7 @@ public class BSShapeCollection : IDisposable | |||
117 | 117 | ||
118 | // Track another user of a body | 118 | // Track another user of a body |
119 | // We presume the caller has allocated the body. | 119 | // We presume the caller has allocated the body. |
120 | // Bodies only have one user so the reference count is either 1 or 0. | 120 | // Bodies only have one user so the body is just put into the world if not already there. |
121 | public void ReferenceBody(BulletBody body, bool inTaintTime) | 121 | public void ReferenceBody(BulletBody body, bool inTaintTime) |
122 | { | 122 | { |
123 | lock (m_collectionActivityLock) | 123 | lock (m_collectionActivityLock) |
@@ -241,26 +241,32 @@ public class BSShapeCollection : IDisposable | |||
241 | 241 | ||
242 | BSScene.TaintCallback dereferenceOperation = delegate() | 242 | BSScene.TaintCallback dereferenceOperation = delegate() |
243 | { | 243 | { |
244 | switch (shape.type) | 244 | if (shape.ptr != IntPtr.Zero) |
245 | { | 245 | { |
246 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | 246 | if (shape.isNativeShape) |
247 | DereferenceHull(shape, shapeCallback); | 247 | { |
248 | break; | ||
249 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
250 | DereferenceMesh(shape, shapeCallback); | ||
251 | break; | ||
252 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
253 | break; | ||
254 | default: | ||
255 | // Native shapes are not tracked and are released immediately | 248 | // Native shapes are not tracked and are released immediately |
256 | if (shape.ptr != IntPtr.Zero & shape.isNativeShape) | 249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | ||
251 | if (shapeCallback != null) shapeCallback(shape); | ||
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | switch (shape.type) | ||
257 | { | 257 | { |
258 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 258 | case ShapeData.PhysicsShapeType.SHAPE_HULL: |
259 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 259 | DereferenceHull(shape, shapeCallback); |
260 | if (shapeCallback != null) shapeCallback(shape); | 260 | break; |
261 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: |
262 | DereferenceMesh(shape, shapeCallback); | ||
263 | break; | ||
264 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
265 | break; | ||
266 | default: | ||
267 | break; | ||
262 | } | 268 | } |
263 | break; | 269 | } |
264 | } | 270 | } |
265 | }; | 271 | }; |
266 | if (inTaintTime) | 272 | if (inTaintTime) |
@@ -405,7 +411,6 @@ public class BSShapeCollection : IDisposable | |||
405 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, | 411 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, |
406 | ShapeDestructionCallback shapeCallback) | 412 | ShapeDestructionCallback shapeCallback) |
407 | { | 413 | { |
408 | BulletShape newShape; | ||
409 | 414 | ||
410 | shapeData.Type = shapeType; | 415 | shapeData.Type = shapeType; |
411 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 416 | // Bullet native objects are scaled by the Bullet engine so pass the size in |
@@ -415,27 +420,35 @@ public class BSShapeCollection : IDisposable | |||
415 | // release any previous shape | 420 | // release any previous shape |
416 | DereferenceShape(prim.BSShape, true, shapeCallback); | 421 | DereferenceShape(prim.BSShape, true, shapeCallback); |
417 | 422 | ||
423 | BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); | ||
424 | |||
425 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | ||
426 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | ||
427 | shapeData.ID, newShape, shapeData.Scale); | ||
428 | |||
429 | prim.BSShape = newShape; | ||
430 | return true; | ||
431 | } | ||
432 | |||
433 | private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, | ||
434 | ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) | ||
435 | { | ||
436 | BulletShape newShape; | ||
437 | |||
418 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 438 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) |
419 | { | 439 | { |
420 | newShape = new BulletShape( | 440 | newShape = new BulletShape( |
421 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), | 441 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), |
422 | shapeType); | 442 | shapeType); |
423 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
424 | newShape.isNativeShape = true; | ||
425 | } | 443 | } |
426 | else | 444 | else |
427 | { | 445 | { |
428 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); | 446 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); |
429 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
430 | newShape.isNativeShape = true; | ||
431 | } | 447 | } |
448 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
449 | newShape.isNativeShape = true; | ||
432 | 450 | ||
433 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 451 | return newShape; |
434 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | ||
435 | shapeData.ID, newShape, shapeData.Scale); | ||
436 | |||
437 | prim.BSShape = newShape; | ||
438 | return true; | ||
439 | } | 452 | } |
440 | 453 | ||
441 | // Builds a mesh shape in the physical world and updates prim.BSShape. | 454 | // Builds a mesh shape in the physical world and updates prim.BSShape. |
@@ -461,6 +474,8 @@ public class BSShapeCollection : IDisposable | |||
461 | DereferenceShape(prim.BSShape, true, shapeCallback); | 474 | DereferenceShape(prim.BSShape, true, shapeCallback); |
462 | 475 | ||
463 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); | 476 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); |
477 | // Take evasive action if the mesh was not constructed. | ||
478 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | ||
464 | 479 | ||
465 | ReferenceShape(newShape); | 480 | ReferenceShape(newShape); |
466 | 481 | ||
@@ -474,7 +489,7 @@ public class BSShapeCollection : IDisposable | |||
474 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 489 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
475 | { | 490 | { |
476 | IMesh meshData = null; | 491 | IMesh meshData = null; |
477 | IntPtr meshPtr; | 492 | IntPtr meshPtr = IntPtr.Zero; |
478 | MeshDesc meshDesc; | 493 | MeshDesc meshDesc; |
479 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 494 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) |
480 | { | 495 | { |
@@ -486,23 +501,26 @@ public class BSShapeCollection : IDisposable | |||
486 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 501 | // Pass false for physicalness as this creates some sort of bounding box which we don't need |
487 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 502 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); |
488 | 503 | ||
489 | int[] indices = meshData.getIndexListAsInt(); | 504 | if (meshData != null) |
490 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
491 | |||
492 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
493 | int vi = 0; | ||
494 | foreach (OMV.Vector3 vv in vertices) | ||
495 | { | 505 | { |
496 | verticesAsFloats[vi++] = vv.X; | 506 | int[] indices = meshData.getIndexListAsInt(); |
497 | verticesAsFloats[vi++] = vv.Y; | 507 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
498 | verticesAsFloats[vi++] = vv.Z; | ||
499 | } | ||
500 | 508 | ||
501 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 509 | float[] verticesAsFloats = new float[vertices.Count * 3]; |
502 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 510 | int vi = 0; |
511 | foreach (OMV.Vector3 vv in vertices) | ||
512 | { | ||
513 | verticesAsFloats[vi++] = vv.X; | ||
514 | verticesAsFloats[vi++] = vv.Y; | ||
515 | verticesAsFloats[vi++] = vv.Z; | ||
516 | } | ||
517 | |||
518 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
519 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | ||
503 | 520 | ||
504 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 521 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
505 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 522 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); |
523 | } | ||
506 | } | 524 | } |
507 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | 525 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); |
508 | newShape.shapeKey = newMeshKey; | 526 | newShape.shapeKey = newMeshKey; |
@@ -531,6 +549,7 @@ public class BSShapeCollection : IDisposable | |||
531 | DereferenceShape(prim.BSShape, true, shapeCallback); | 549 | DereferenceShape(prim.BSShape, true, shapeCallback); |
532 | 550 | ||
533 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); | 551 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); |
552 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | ||
534 | 553 | ||
535 | ReferenceShape(newShape); | 554 | ReferenceShape(newShape); |
536 | 555 | ||
@@ -544,7 +563,7 @@ public class BSShapeCollection : IDisposable | |||
544 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 563 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
545 | { | 564 | { |
546 | 565 | ||
547 | IntPtr hullPtr; | 566 | IntPtr hullPtr = IntPtr.Zero; |
548 | HullDesc hullDesc; | 567 | HullDesc hullDesc; |
549 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 568 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
550 | { | 569 | { |
@@ -556,86 +575,89 @@ public class BSShapeCollection : IDisposable | |||
556 | // Build a new hull in the physical world | 575 | // Build a new hull in the physical world |
557 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 576 | // Pass false for physicalness as this creates some sort of bounding box which we don't need |
558 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 577 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); |
559 | 578 | if (meshData != null) | |
560 | int[] indices = meshData.getIndexListAsInt(); | ||
561 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
562 | |||
563 | //format conversion from IMesh format to DecompDesc format | ||
564 | List<int> convIndices = new List<int>(); | ||
565 | List<float3> convVertices = new List<float3>(); | ||
566 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
567 | { | ||
568 | convIndices.Add(indices[ii]); | ||
569 | } | ||
570 | foreach (OMV.Vector3 vv in vertices) | ||
571 | { | 579 | { |
572 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
573 | } | ||
574 | 580 | ||
575 | // setup and do convex hull conversion | 581 | int[] indices = meshData.getIndexListAsInt(); |
576 | m_hulls = new List<ConvexResult>(); | 582 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
577 | DecompDesc dcomp = new DecompDesc(); | ||
578 | dcomp.mIndices = convIndices; | ||
579 | dcomp.mVertices = convVertices; | ||
580 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
581 | // create the hull into the _hulls variable | ||
582 | convexBuilder.process(dcomp); | ||
583 | |||
584 | // Convert the vertices and indices for passing to unmanaged. | ||
585 | // The hull information is passed as a large floating point array. | ||
586 | // The format is: | ||
587 | // convHulls[0] = number of hulls | ||
588 | // convHulls[1] = number of vertices in first hull | ||
589 | // convHulls[2] = hull centroid X coordinate | ||
590 | // convHulls[3] = hull centroid Y coordinate | ||
591 | // convHulls[4] = hull centroid Z coordinate | ||
592 | // convHulls[5] = first hull vertex X | ||
593 | // convHulls[6] = first hull vertex Y | ||
594 | // convHulls[7] = first hull vertex Z | ||
595 | // convHulls[8] = second hull vertex X | ||
596 | // ... | ||
597 | // convHulls[n] = number of vertices in second hull | ||
598 | // convHulls[n+1] = second hull centroid X coordinate | ||
599 | // ... | ||
600 | // | ||
601 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
602 | // data structures that do not need to be converted in order to pass to Bullet. | ||
603 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
604 | int hullCount = m_hulls.Count; | ||
605 | int totalVertices = 1; // include one for the count of the hulls | ||
606 | foreach (ConvexResult cr in m_hulls) | ||
607 | { | ||
608 | totalVertices += 4; // add four for the vertex count and centroid | ||
609 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
610 | } | ||
611 | float[] convHulls = new float[totalVertices]; | ||
612 | 583 | ||
613 | convHulls[0] = (float)hullCount; | 584 | //format conversion from IMesh format to DecompDesc format |
614 | int jj = 1; | 585 | List<int> convIndices = new List<int>(); |
615 | foreach (ConvexResult cr in m_hulls) | 586 | List<float3> convVertices = new List<float3>(); |
616 | { | 587 | for (int ii = 0; ii < indices.GetLength(0); ii++) |
617 | // copy vertices for index access | ||
618 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
619 | int kk = 0; | ||
620 | foreach (float3 ff in cr.HullVertices) | ||
621 | { | 588 | { |
622 | verts[kk++] = ff; | 589 | convIndices.Add(indices[ii]); |
590 | } | ||
591 | foreach (OMV.Vector3 vv in vertices) | ||
592 | { | ||
593 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
623 | } | 594 | } |
624 | 595 | ||
625 | // add to the array one hull's worth of data | 596 | // setup and do convex hull conversion |
626 | convHulls[jj++] = cr.HullIndices.Count; | 597 | m_hulls = new List<ConvexResult>(); |
627 | convHulls[jj++] = 0f; // centroid x,y,z | 598 | DecompDesc dcomp = new DecompDesc(); |
628 | convHulls[jj++] = 0f; | 599 | dcomp.mIndices = convIndices; |
629 | convHulls[jj++] = 0f; | 600 | dcomp.mVertices = convVertices; |
630 | foreach (int ind in cr.HullIndices) | 601 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); |
602 | // create the hull into the _hulls variable | ||
603 | convexBuilder.process(dcomp); | ||
604 | |||
605 | // Convert the vertices and indices for passing to unmanaged. | ||
606 | // The hull information is passed as a large floating point array. | ||
607 | // The format is: | ||
608 | // convHulls[0] = number of hulls | ||
609 | // convHulls[1] = number of vertices in first hull | ||
610 | // convHulls[2] = hull centroid X coordinate | ||
611 | // convHulls[3] = hull centroid Y coordinate | ||
612 | // convHulls[4] = hull centroid Z coordinate | ||
613 | // convHulls[5] = first hull vertex X | ||
614 | // convHulls[6] = first hull vertex Y | ||
615 | // convHulls[7] = first hull vertex Z | ||
616 | // convHulls[8] = second hull vertex X | ||
617 | // ... | ||
618 | // convHulls[n] = number of vertices in second hull | ||
619 | // convHulls[n+1] = second hull centroid X coordinate | ||
620 | // ... | ||
621 | // | ||
622 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
623 | // data structures that do not need to be converted in order to pass to Bullet. | ||
624 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
625 | int hullCount = m_hulls.Count; | ||
626 | int totalVertices = 1; // include one for the count of the hulls | ||
627 | foreach (ConvexResult cr in m_hulls) | ||
631 | { | 628 | { |
632 | convHulls[jj++] = verts[ind].x; | 629 | totalVertices += 4; // add four for the vertex count and centroid |
633 | convHulls[jj++] = verts[ind].y; | 630 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles |
634 | convHulls[jj++] = verts[ind].z; | 631 | } |
632 | float[] convHulls = new float[totalVertices]; | ||
633 | |||
634 | convHulls[0] = (float)hullCount; | ||
635 | int jj = 1; | ||
636 | foreach (ConvexResult cr in m_hulls) | ||
637 | { | ||
638 | // copy vertices for index access | ||
639 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
640 | int kk = 0; | ||
641 | foreach (float3 ff in cr.HullVertices) | ||
642 | { | ||
643 | verts[kk++] = ff; | ||
644 | } | ||
645 | |||
646 | // add to the array one hull's worth of data | ||
647 | convHulls[jj++] = cr.HullIndices.Count; | ||
648 | convHulls[jj++] = 0f; // centroid x,y,z | ||
649 | convHulls[jj++] = 0f; | ||
650 | convHulls[jj++] = 0f; | ||
651 | foreach (int ind in cr.HullIndices) | ||
652 | { | ||
653 | convHulls[jj++] = verts[ind].x; | ||
654 | convHulls[jj++] = verts[ind].y; | ||
655 | convHulls[jj++] = verts[ind].z; | ||
656 | } | ||
635 | } | 657 | } |
658 | // create the hull data structure in Bullet | ||
659 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
636 | } | 660 | } |
637 | // create the hull data structure in Bullet | ||
638 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
639 | } | 661 | } |
640 | 662 | ||
641 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | 663 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); |
@@ -676,6 +698,50 @@ public class BSShapeCollection : IDisposable | |||
676 | return ComputeShapeKey(shapeData, pbs, out lod); | 698 | return ComputeShapeKey(shapeData, pbs, out lod); |
677 | } | 699 | } |
678 | 700 | ||
701 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
702 | { | ||
703 | // If the shape was successfully created, nothing more to do | ||
704 | if (newShape.ptr != IntPtr.Zero) | ||
705 | return newShape; | ||
706 | |||
707 | // The most common reason for failure is that an underlying asset is not available | ||
708 | |||
709 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
710 | if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) | ||
711 | { | ||
712 | prim.LastAssetBuildFailed = true; | ||
713 | BSPhysObject xprim = prim; | ||
714 | Util.FireAndForget(delegate | ||
715 | { | ||
716 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
717 | if (assetProvider != null) | ||
718 | { | ||
719 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
720 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
721 | { | ||
722 | if (!yprim.BaseShape.SculptEntry) | ||
723 | return; | ||
724 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
725 | return; | ||
726 | |||
727 | yprim.BaseShape.SculptData = new byte[asset.Data.Length]; | ||
728 | asset.Data.CopyTo(yprim.BaseShape.SculptData, 0); | ||
729 | // This will cause the prim to see that the filler shape is not the right | ||
730 | // one and try again to build the object. | ||
731 | yprim.ForceBodyShapeRebuild(false); | ||
732 | |||
733 | }); | ||
734 | } | ||
735 | }); | ||
736 | } | ||
737 | |||
738 | // While we figure out the real problem, stick a simple native shape on the object. | ||
739 | BulletShape fillinShape = | ||
740 | BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); | ||
741 | |||
742 | return fillinShape; | ||
743 | } | ||
744 | |||
679 | // Create a body object in Bullet. | 745 | // Create a body object in Bullet. |
680 | // Updates prim.BSBody with the information about the new body if one is created. | 746 | // Updates prim.BSBody with the information about the new body if one is created. |
681 | // Returns 'true' if an object was actually created. | 747 | // Returns 'true' if an object was actually created. |