public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_velocityMotor = null; m_walkingUpStairs = 0; m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); }
public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); LockAxisConstraint = null; HaveRegisteredForBeforeStepCallback = false; }
// Called to update/change the body and shape for an object. // The object has some shape and body on it. Here we decide if that is the correct shape // for the current state of the object (static/dynamic/...). // If bodyCallback is not null, it is called if either the body or the shape are changed // so dependencies (like constraints) can be removed before the physical object is dereferenced. // Return 'true' if either the body or the shape changed. // Called at taint-time. public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) { m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); bool ret = false; // This lock could probably be pushed down lower but building shouldn't take long lock (m_collectionActivityLock) { // Do we have the correct geometry for this type of object? // Updates prim.BSShape with information/pointers to shape. // Returns 'true' of BSShape is changed to a new shape. bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); // If we had to select a new shape geometry for the object, // rebuild the body around it. // Updates prim.BSBody with information/pointers to requested body // Returns 'true' if BSBody was changed. bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); ret = newGeom || newBody; } DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); return ret; }
// Called after a simulation step to post a collision with this object. // This returns 'true' if the collision has been queued and the SendCollisions call must // be made at the end of the simulation step. public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { bool ret = false; // Ask the linkset if it wants to handle the collision if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)) { // The linkset didn't handle it so pass the collision through normal processing ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); } return ret; }
public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) { // Calling this reference means we want another handle to an existing compound shape // (usually linksets) so return this copy. IncrementReference(); return this; }
public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { BSShape ret = null; // If the underlying shape is native, the actual shape has not been build (waiting for asset) // and we must create a copy of the native shape since they are never shared. if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) { // TODO: decide when the native shapes should be freed. Check in Dereference? ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); } else { // Another reference to this shape is just counted. IncrementReference(); ret = this; } return ret; }
// Code that uses the mesher to create the index/vertices info for a trimesh shape. // This is used by the passed 'makeShape' call to create the Bullet mesh shape. // The actual build call is passed so this logic can be used by several of the shapes that use a // simple mesh as their base shape. public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) { BulletShape newShape = new BulletShape(); IMesh meshData = null; lock (physicsScene.mesher) { meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, false, // say it is not physical so a bounding box is not built false, // do not cache the mesh and do not use previously built versions false, false ); } if (meshData != null) { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { // Release the fetched asset data once it has been used. pbs.SculptData = new byte[0]; prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; } int[] indices = meshData.getIndexListAsInt(); int realIndicesIndex = indices.Length; float[] verticesAsFloats = meshData.getVertexListAsFloat(); if (BSParam.ShouldRemoveZeroWidthTriangles) { // Remove degenerate triangles. These are triangles with two of the vertices // are the same. This is complicated by the problem that vertices are not // made unique in sculpties so we have to compare the values in the vertex. realIndicesIndex = 0; for (int tri = 0; tri < indices.Length; tri += 3) { // Compute displacements into vertex array for each vertex of the triangle int v1 = indices[tri + 0] * 3; int v2 = indices[tri + 1] * 3; int v3 = indices[tri + 2] * 3; // Check to see if any two of the vertices are the same if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) ) { // None of the vertices of the triangles are the same. This is a good triangle; indices[realIndicesIndex + 0] = indices[tri + 0]; indices[realIndicesIndex + 1] = indices[tri + 1]; indices[realIndicesIndex + 2] = indices[tri + 2]; realIndicesIndex += 3; } } } physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); if (realIndicesIndex != 0) { newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); } else { // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); } } newShape.shapeKey = newMeshKey; return newShape; }
public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { float lod; System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); BSShapeMesh retMesh = null; lock (Meshes) { if (Meshes.TryGetValue(newMeshKey, out retMesh)) { // The mesh has already been created. Return a new reference to same. retMesh.IncrementReference(); } else { retMesh = new BSShapeMesh(new BulletShape()); // An instance of this mesh has not been created. Build and remember same. BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); if (!newShape.isNativeShape || prim.AssetFailed() ) { // If a mesh was what was created, remember the built shape for later sharing. // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. Meshes.Add(newMeshKey, retMesh); } retMesh.physShapeInfo = newShape; } } physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); return retMesh; }
public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { // Native shapes are not shared so we return a new shape. BSShape ret = null; lock (physShapeInfo) { ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); } return ret; }
public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
// return 'true' if the prim's shape was changed. private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { bool ret = false; // Note that if it's a native shape, the check for physical/non-physical is not // made. Native shapes work in either case. if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) { // Use a simple, single mesh convex hull shape if the object is simple enough BSShape potentialHull = null; PrimitiveBaseShape pbs = prim.BaseShape; // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) if (BSParam.ShouldUseSingleConvexHullForPrims && pbs != null && !pbs.SculptEntry && PrimHasNoCuts(pbs) ) { potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); } // Use the GImpact shape if it is a prim that has some concaveness if (potentialHull == null && BSParam.ShouldUseGImpactShapeForPrims && pbs != null && !pbs.SculptEntry ) { potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); } // If not any of the simple cases, just make a hull if (potentialHull == null) { potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); } // If the current shape is not what is on the prim at the moment, time to change. if (!prim.PhysShape.HasPhysicalShape || potentialHull.ShapeType != prim.PhysShape.ShapeType || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = potentialHull; ret = true; } else { // The current shape on the prim is the correct one. We don't need the potential reference. potentialHull.Dereference(m_physicsScene); } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); } else { // Non-physical objects should be just meshes. BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); // If the current shape is not what is on the prim at the moment, time to change. if (!prim.PhysShape.HasPhysicalShape || potentialMesh.ShapeType != prim.PhysShape.ShapeType || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = potentialMesh; ret = true; } else { // We don't need this reference to the mesh that is already being using. potentialMesh.Dereference(m_physicsScene); } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); } return ret; }
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { bool ret = false; bool haveShape = false; bool nativeShapePossible = true; PrimitiveBaseShape pbs = prim.BaseShape; // Kludge to create the capsule for the avatar. // TDOD: Remove/redo this when BSShapeAvatar is working!! BSCharacter theChar = prim as BSCharacter; if (theChar != null) { DereferenceExistingShape(prim, shapeCallback); switch (BSParam.AvatarShape) { case AvatarShapeCapsule: prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); ret = true; haveShape = true; break; case AvatarShapeCube: prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE); ret = true; haveShape = true; break; case AvatarShapeOvoid: // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE); ret = true; haveShape = true; break; case AvatarShapeMesh: break; default: break; } } // If the prim attributes are simple, this could be a simple Bullet native shape // Native shapes work whether to object is static or physical. if (!haveShape && nativeShapePossible && pbs != null && PrimHasNoCuts(pbs) && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) ) { // Get the scale of any existing shape so we can see if the new shape is same native type and same size. OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; if (prim.PhysShape.HasPhysicalShape) scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); // It doesn't look like Bullet scales native spheres so make sure the scales are all equal if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) { haveShape = true; if (forceRebuild || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE ) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); ret = true; } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", prim.LocalID, forceRebuild, ret, prim.PhysShape); } // If we didn't make a sphere, maybe a box will work. if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) { haveShape = true; if (forceRebuild || prim.Scale != scaleOfExistingShape || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX ) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); ret = true; } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", prim.LocalID, forceRebuild, ret, prim.PhysShape); } } // If a simple shape is not happening, create a mesh and possibly a hull. if (!haveShape && pbs != null) { ret = CreateGeomMeshOrHull(prim, shapeCallback); } return ret; }
// If the existing prim's shape is to be replaced, remove the tie to the existing shape // before replacing it. private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { if (prim.PhysShape.HasPhysicalShape) { if (shapeCallback != null) shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); prim.PhysShape.Dereference(m_physicsScene); } prim.PhysShape = new BSShapeNull(); }
public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) { return GetBodyAndShape(forceRebuild, sim, prim, null); }
public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_hoverMotor = null; m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); }
// return 'true' if the prim's shape was changed. private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { bool ret = false; // Note that if it's a native shape, the check for physical/non-physical is not // made. Native shapes work in either case. if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) { // Use a simple, single mesh convex hull shape if the object is simple enough BSShape potentialHull = null; PrimitiveBaseShape pbs = prim.BaseShape; // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) if (BSParam.ShouldUseSingleConvexHullForPrims && pbs != null && !pbs.SculptEntry && PrimHasNoCuts(pbs) ) { potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); } // Use the GImpact shape if it is a prim that has some concaveness if (potentialHull == null && BSParam.ShouldUseGImpactShapeForPrims && pbs != null && !pbs.SculptEntry ) { potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); } // If not any of the simple cases, just make a hull if (potentialHull == null) { potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); } // If the current shape is not what is on the prim at the moment, time to change. if (!prim.PhysShape.HasPhysicalShape || potentialHull.ShapeType != prim.PhysShape.ShapeType || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = potentialHull; ret = true; } else { // The current shape on the prim is the correct one. We don't need the potential reference. potentialHull.Dereference(m_physicsScene); } if (DDetail) { DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); } } else { // Non-physical objects should be just meshes. BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); // If the current shape is not what is on the prim at the moment, time to change. if (!prim.PhysShape.HasPhysicalShape || potentialMesh.ShapeType != prim.PhysShape.ShapeType || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = potentialMesh; ret = true; } else { // We don't need this reference to the mesh that is already being using. potentialMesh.Dereference(m_physicsScene); } if (DDetail) { DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); } } return(ret); }
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { bool ret = false; bool haveShape = false; bool nativeShapePossible = true; PrimitiveBaseShape pbs = prim.BaseShape; // Kludge to create the capsule for the avatar. // TDOD: Remove/redo this when BSShapeAvatar is working!! BSCharacter theChar = prim as BSCharacter; if (theChar != null) { DereferenceExistingShape(prim, shapeCallback); switch (BSParam.AvatarShape) { case AvatarShapeCapsule: prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); ret = true; haveShape = true; break; case AvatarShapeCube: prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE); ret = true; haveShape = true; break; case AvatarShapeOvoid: // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE); ret = true; haveShape = true; break; case AvatarShapeMesh: break; default: break; } } // If the prim attributes are simple, this could be a simple Bullet native shape // Native shapes work whether to object is static or physical. if (!haveShape && nativeShapePossible && pbs != null && PrimHasNoCuts(pbs) && (!pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)) ) { // Get the scale of any existing shape so we can see if the new shape is same native type and same size. OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; if (prim.PhysShape.HasPhysicalShape) { scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); } if (DDetail) { DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); } // It doesn't look like Bullet scales native spheres so make sure the scales are all equal if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) { haveShape = true; if (forceRebuild || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE ) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); ret = true; } if (DDetail) { DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", prim.LocalID, forceRebuild, ret, prim.PhysShape); } } // If we didn't make a sphere, maybe a box will work. if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) { haveShape = true; if (forceRebuild || prim.Scale != scaleOfExistingShape || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX ) { DereferenceExistingShape(prim, shapeCallback); prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); ret = true; } if (DDetail) { DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", prim.LocalID, forceRebuild, ret, prim.PhysShape); } } } // If a simple shape is not happening, create a mesh and possibly a hull. if (!haveShape && pbs != null) { ret = CreateGeomMeshOrHull(prim, shapeCallback); } m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG return(ret); }
public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) { StringBuilder buff = new StringBuilder(prim.PhysObjectName); buff.Append("/pos="); buff.Append(prim.RawPosition.ToString()); if (pScene != null) { buff.Append("/rgn="); buff.Append(pScene.PhysicsSceneName); } return buff.ToString(); }
// Create a body object in Bullet. // Updates prim.BSBody with the information about the new body if one is created. // Returns 'true' if an object was actually created. // Called at taint-time. private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) { bool ret = false; // the mesh, hull or native shape must have already been created in Bullet bool mustRebuild = !prim.PhysBody.HasPhysicalBody; // If there is an existing body, verify it's of an acceptable type. // If not a solid object, body is a GhostObject. Otherwise a RigidBody. if (!mustRebuild) { CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) { // If the collisionObject is not the correct type for solidness, rebuild what's there mustRebuild = true; if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); } } if (mustRebuild || forceRebuild) { // Free any old body DereferenceBody(prim.PhysBody, bodyCallback); BulletBody aBody; if (prim.IsSolid) { aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); } else { aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); } ReferenceBody(aBody); prim.PhysBody = aBody; ret = true; } return ret; }
public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { // Native shapes are not shared and are always built anew. return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); }
public virtual bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { bool ret = false; // The following lines make IsColliding(), CollidingGround() and CollidingObj work CollidingStep = PhysScene.SimulationStep; if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) { CollidingGroundStep = PhysScene.SimulationStep; } else { CollidingObjectStep = PhysScene.SimulationStep; } CollisionAccumulation++; // For movement tests, remember if we are colliding with an object that is moving. ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; // Make a collection of the collisions that happened the last simulation tick. // This is different than the collection created for sending up to the simulator as it is cleared every tick. if (CollisionsLastTickStep != PhysScene.SimulationStep) { CollisionsLastTick = new CollisionEventUpdate(); CollisionsLastTickStep = PhysScene.SimulationStep; } CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); // If someone has subscribed for collision events log the collision so it will be reported up if (SubscribedEvents()) { lock (PhysScene.CollisionLock) { CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); } DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); ret = true; } return ret; }
private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { BulletShape newShape; ShapeData nativeShapeData = new ShapeData(); nativeShapeData.Type = shapeType; nativeShapeData.ID = prim.LocalID; nativeShapeData.Scale = prim.Scale; nativeShapeData.Size = prim.Scale; nativeShapeData.MeshKey = (ulong)shapeKey; nativeShapeData.HullKey = (ulong)shapeKey; if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) { newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); } else { newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); } if (!newShape.HasPhysicalShape) { physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", LogHeader, prim.LocalID, shapeType); } newShape.shapeType = shapeType; newShape.isNativeShape = true; newShape.shapeKey = (UInt64)shapeKey; return newShape; }
public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { float lod; System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); BSShapeConvexHull retConvexHull = null; lock (ConvexHulls) { if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) { // The mesh has already been created. Return a new reference to same. retConvexHull.IncrementReference(); } else { retConvexHull = new BSShapeConvexHull(new BulletShape()); BulletShape convexShape = null; // Get a handle to a mesh to build the hull from BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); if (baseMesh.physShapeInfo.isNativeShape) { // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. // In the short term, we return the native shape and a later ForceBodyShapeRebuild should // get back to this code with a buildable mesh. // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? convexShape = baseMesh.physShapeInfo; } else { convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); convexShape.shapeKey = newMeshKey; ConvexHulls.Add(convexShape.shapeKey, retConvexHull); physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}", BSScene.DetailLogZero, convexShape); } // Done with the base mesh baseMesh.Dereference(physicsScene); retConvexHull.physShapeInfo = convexShape; } } return retConvexHull; }
private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, (w, iC, i, vC, v) => { shapeInfo.Vertices = vC; return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); }); }
public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { float lod; System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); BSShapeGImpact retGImpact = null; lock (GImpacts) { if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) { // The mesh has already been created. Return a new reference to same. retGImpact.IncrementReference(); } else { retGImpact = new BSShapeGImpact(new BulletShape()); BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); newShape.shapeKey = newMeshKey; if (!newShape.isNativeShape || prim.AssetFailed()) { // If a mesh was what was created, remember the built shape for later sharing. // Also note that if meshing failed we put it in the mesh list as there is nothing // else to do about the mesh. GImpacts.Add(newMeshKey, retGImpact); } retGImpact.physShapeInfo = newShape; } } return retGImpact; }
public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { float lod; System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); BSShapeHull retHull = null; lock (Hulls) { if (Hulls.TryGetValue(newHullKey, out retHull)) { // The mesh has already been created. Return a new reference to same. retHull.IncrementReference(); } else { retHull = new BSShapeHull(new BulletShape()); // An instance of this mesh has not been created. Build and remember same. BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); // Check to see if hull was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); if (!newShape.isNativeShape || prim.AssetFailed()) { // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); } retHull.physShapeInfo = newShape; } } physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); return retHull; }
public static BSShape GetReference(BSPhysObject prim) { return new BSShapeNull(); }
private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = new BulletShape(); IMesh meshData = null; List<List<OMV.Vector3>> allHulls = null; lock (physicsScene.mesher) { // Pass true for physicalness as this prevents the creation of bounding box which is not needed meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false); // If we should use the asset's hull info, fetch it out of the locked mesher if (meshData != null && BSParam.ShouldUseAssetHulls) { Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; if (realMesher != null) { allHulls = realMesher.GetConvexHulls(size); } if (allHulls == null) { physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); } } } // If there is hull data in the mesh asset, build the hull from that if (allHulls != null && BSParam.ShouldUseAssetHulls) { int hullCount = allHulls.Count; shapeInfo.HullCount = hullCount; int totalVertices = 1; // include one for the count of the hulls // Using the structure described for HACD hulls, create the memory sturcture // to pass the hull data to the creater. foreach (List<OMV.Vector3> hullVerts in allHulls) { totalVertices += 4; // add four for the vertex count and centroid totalVertices += hullVerts.Count * 3; // one vertex is three dimensions } float[] convHulls = new float[totalVertices]; convHulls[0] = (float)hullCount; int jj = 1; int hullIndex = 0; foreach (List<OMV.Vector3> hullVerts in allHulls) { convHulls[jj + 0] = hullVerts.Count; convHulls[jj + 1] = 0f; // centroid x,y,z convHulls[jj + 2] = 0f; convHulls[jj + 3] = 0f; jj += 4; foreach (OMV.Vector3 oneVert in hullVerts) { convHulls[jj + 0] = oneVert.X; convHulls[jj + 1] = oneVert.Y; convHulls[jj + 2] = oneVert.Z; jj += 3; } shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); hullIndex++; } // create the hull data structure in Bullet newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", prim.LocalID, hullCount, totalVertices, newShape); } // If no hull specified in the asset and we should use Bullet's HACD approximation... if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) { // Build the hull shape from an existing mesh shape. // The mesh should have already been created in Bullet. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); if (meshShape.physShapeInfo.HasPhysicalShape) { HACDParams parms = new HACDParams(); parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; parms.minClusters = BSParam.BHullMinClusters; parms.compacityWeight = BSParam.BHullCompacityWeight; parms.volumeWeight = BSParam.BHullVolumeWeight; parms.concavity = BSParam.BHullConcavity; parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); parms.whichHACD = 0; // Use the HACD routine that comes with Bullet physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); // Now done with the mesh shape. shapeInfo.HullCount = 1; BSShapeMesh maybeMesh = meshShape as BSShapeMesh; if (maybeMesh != null) shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); meshShape.Dereference(physicsScene); } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } // If no other hull specifications, use our HACD hull approximation. if (!newShape.HasPhysicalShape && meshData != null) { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { // Release the fetched asset data once it has been used. pbs.SculptData = new byte[0]; prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; } int[] indices = meshData.getIndexListAsInt(); List<OMV.Vector3> vertices = meshData.getVertexList(); //format conversion from IMesh format to DecompDesc format List<int> convIndices = new List<int>(); List<float3> convVertices = new List<float3>(); for (int ii = 0; ii < indices.GetLength(0); ii++) { convIndices.Add(indices[ii]); } foreach (OMV.Vector3 vv in vertices) { convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); } uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) { // Simple primitive shapes we know are convex so they are better implemented with // fewer hulls. // Check for simple shape (prim without cuts) and reduce split parameter if so. if (BSShapeCollection.PrimHasNoCuts(pbs)) { maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; } } // setup and do convex hull conversion m_hulls = new List<ConvexResult>(); DecompDesc dcomp = new DecompDesc(); dcomp.mIndices = convIndices; dcomp.mVertices = convVertices; dcomp.mDepth = maxDepthSplit; dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); // create the hull into the _hulls variable convexBuilder.process(dcomp); physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); // Convert the vertices and indices for passing to unmanaged. // The hull information is passed as a large floating point array. // The format is: // convHulls[0] = number of hulls // convHulls[1] = number of vertices in first hull // convHulls[2] = hull centroid X coordinate // convHulls[3] = hull centroid Y coordinate // convHulls[4] = hull centroid Z coordinate // convHulls[5] = first hull vertex X // convHulls[6] = first hull vertex Y // convHulls[7] = first hull vertex Z // convHulls[8] = second hull vertex X // ... // convHulls[n] = number of vertices in second hull // convHulls[n+1] = second hull centroid X coordinate // ... // // TODO: is is very inefficient. Someday change the convex hull generator to return // data structures that do not need to be converted in order to pass to Bullet. // And maybe put the values directly into pinned memory rather than marshaling. int hullCount = m_hulls.Count; int totalVertices = 1; // include one for the count of the hulls foreach (ConvexResult cr in m_hulls) { totalVertices += 4; // add four for the vertex count and centroid totalVertices += cr.HullIndices.Count * 3; // we pass just triangles } float[] convHulls = new float[totalVertices]; convHulls[0] = (float)hullCount; int jj = 1; foreach (ConvexResult cr in m_hulls) { // copy vertices for index access float3[] verts = new float3[cr.HullVertices.Count]; int kk = 0; foreach (float3 ff in cr.HullVertices) { verts[kk++] = ff; } // add to the array one hull's worth of data convHulls[jj++] = cr.HullIndices.Count; convHulls[jj++] = 0f; // centroid x,y,z convHulls[jj++] = 0f; convHulls[jj++] = 0f; foreach (int ind in cr.HullIndices) { convHulls[jj++] = verts[ind].x; convHulls[jj++] = verts[ind].y; convHulls[jj++] = verts[ind].z; } } // create the hull data structure in Bullet newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); } newShape.shapeKey = newHullKey; return newShape; }
public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_targetMotor = null; m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); }
// The simulation step is telling this object about a collision. // I'm the 'collider', the thing I'm colliding with is the 'collidee'. // Return 'true' if a collision was processed and should be sent up. // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. // Called at taint time from within the Step() function public virtual bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { bool ret = false; // if 'collidee' is null, that means it is terrain uint collideeLocalID = (collidee == null) ? BSScene.TERRAIN_ID : collidee.LocalID; // All terrain goes by the TERRAIN_ID id when passed up as a collision if (collideeLocalID <= PhysScene.TerrainManager.HighestTerrainID) { collideeLocalID = BSScene.TERRAIN_ID; } // The following lines make IsColliding(), CollidingGround() and CollidingObj work CollidingStep = PhysScene.SimulationStep; if (collideeLocalID == BSScene.TERRAIN_ID) { CollidingGroundStep = PhysScene.SimulationStep; } else { CollidingObjectStep = PhysScene.SimulationStep; } CollisionAccumulation++; // For movement tests, if the collider is me, remember if we are colliding with an object that is moving. // Here the 'collider'/'collidee' thing gets messed up. In the larger context, when something is checking // if the thing it is colliding with is moving, for instance, it asks if the its collider is moving. ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero || collidee.RotationalVelocity != OMV.Vector3.Zero) : false; ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; // Make a collection of the collisions that happened the last simulation tick. // This is different than the collection created for sending up to the simulator as it is cleared every tick. if (CollisionsLastTickStep != PhysScene.SimulationStep) { CollisionsLastTick = new CollisionEventUpdate(); CollisionsLastTickStep = PhysScene.SimulationStep; } CollisionsLastTick.AddCollider(collideeLocalID, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); // If someone has subscribed for collision events log the collision so it will be reported up if (SubscribedEvents()) { ContactPoint newContact = new ContactPoint(contactPoint, contactNormal, pentrationDepth); // Collision sound requires a velocity to know it should happen. This is a lot of computation for a little used feature. OMV.Vector3 relvel = OMV.Vector3.Zero; if (IsPhysical) { relvel = RawVelocity; } if (collidee != null && collidee.IsPhysical) { relvel -= collidee.RawVelocity; } newContact.RelativeSpeed = -OMV.Vector3.Dot(relvel, contactNormal); // DetailLog("{0},{1}.Collision.AddCollider,vel={2},contee.vel={3},relvel={4},relspeed={5}", // LocalID, TypeName, RawVelocity, (collidee == null ? OMV.Vector3.Zero : collidee.RawVelocity), relvel, newContact.RelativeSpeed); lock (PhysScene.CollisionLock) { CollisionCollection.AddCollider(collideeLocalID, newContact); } DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},speed={6},colliderMoving={7}", LocalID, TypeName, collideeLocalID, contactPoint, contactNormal, pentrationDepth, newContact.RelativeSpeed, ColliderIsMoving); ret = true; } return(ret); }
// Get another reference to this shape. public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) { return(GetBodyAndShape(forceRebuild, sim, prim, null)); }
public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_forceMotor = null; m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); }
// The creation of a mesh or hull can fail if an underlying asset is not available. // There are two cases: 1) the asset is not in the cache and it needs to be fetched; // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). // The first case causes the asset to be fetched. The second case requires // us to not loop forever. // Called after creating a physical mesh or hull. If the physical shape was created, // just return. public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) { // If the shape was successfully created, nothing more to do if (newShape.HasPhysicalShape) return newShape; // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been // fetched but we end up here again, the meshing of the asset must have failed. // Prevent trying to keep fetching the mesh by declaring failure. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); } else { // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset if (prim.BaseShape.SculptEntry && !prim.AssetFailed() && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting && prim.BaseShape.SculptTexture != OMV.UUID.Zero ) { physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); // Multiple requestors will know we're waiting for this asset prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; BSPhysObject xprim = prim; RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; if (assetProvider != null) { BSPhysObject yprim = xprim; // probably not necessary, but, just in case. assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) { // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); bool assetFound = false; string mismatchIDs = String.Empty; // DEBUG DEBUG if (asset != null && yprim.BaseShape.SculptEntry) { if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) { yprim.BaseShape.SculptData = asset.Data; // This will cause the prim to see that the filler shape is not the right // one and try again to build the object. // No race condition with the normal shape setting since the rebuild is at taint time. yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; yprim.ForceBodyShapeRebuild(false /* inTaintTime */); assetFound = true; } else { mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; } } if (!assetFound) { yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; } physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); }); } else { xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", LogHeader, physicsScene.PhysicsSceneName); } } else { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); } if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) { physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); } } } // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); return fillShape.physShapeInfo; }