public void ReadSphere(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData)
        {
            Vector3 scaleDelta = transform.Scale - Vector3.UnitScale;

            if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon)
            {
                log.Error("Scale is not currently supported for sphere shapes");
            }
            float radius = 0;

            foreach (XmlNode childNode in node.ChildNodes)
            {
                switch (childNode.Name)
                {
                case "radius":
                    radius = float.Parse(childNode.InnerText);
                    break;

                default:
                    DebugMessage(childNode);
                    break;
                }
            }
            Vector3 center = unitConversion * transform.Translation;

            radius *= unitConversion;

            CollisionShape collisionShape = new CollisionSphere(center, radius);

            physicsData.AddCollisionShape(objectId, collisionShape);
        }
        public void ReadCapsule(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData)
        {
            Quaternion rot          = MathHelpers.GetRotation(transform);
            Matrix4    tmpTransform = rot.Inverse().ToRotationMatrix() * transform;
            Vector3    scaleDelta   = tmpTransform.Scale - Vector3.UnitScale;

            if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon)
            {
                log.Error("Scale is not currently supported for capsule shapes");
            }
            float height = 0;

            float[] radius      = new float[2];
            Vector3 halfExtents = Vector3.Zero;

            foreach (XmlNode childNode in node.ChildNodes)
            {
                switch (childNode.Name)
                {
                case "height":
                    height = float.Parse(childNode.InnerText);
                    break;

                case "radius": {
                    string[] values = childNode.InnerText.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                    Debug.Assert(values.Length == 2);
                    for (int i = 0; i < 2; ++i)
                    {
                        radius[i] = float.Parse(values[i]);
                    }
                }
                break;

                default:
                    DebugMessage(childNode);
                    break;
                }
            }
            // We only support capsules where the two radii match
            if (radius[0] != radius[1])
            {
                log.Error("Different radii for capsules are not currently supported");
            }
            Vector3 center     = unitConversion * transform.Translation;
            Vector3 halfExtent = unitConversion * (.5f * height * (rot * Vector3.UnitY));

            radius[0] *= unitConversion;
            radius[1] *= unitConversion;

            CollisionShape collisionShape;

            collisionShape = new CollisionCapsule(center - halfExtent, center + halfExtent, radius[0]);
            physicsData.AddCollisionShape(objectId, collisionShape);
        }
        public void ReadBox(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData)
        {
            Quaternion rot          = MathHelpers.GetRotation(transform);
            Matrix4    tmpTransform = rot.Inverse().ToRotationMatrix() * transform;
            Vector3    scaleDelta   = tmpTransform.Scale - Vector3.UnitScale;

            if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon)
            {
                log.Error("Scale is not currently supported for box shapes");
            }
            Vector3 halfExtents = Vector3.Zero;

            foreach (XmlNode childNode in node.ChildNodes)
            {
                switch (childNode.Name)
                {
                case "half_extents":
                    ReadVector(ref halfExtents, childNode);
                    break;

                default:
                    DebugMessage(childNode);
                    break;
                }
            }
            Vector3 center = unitConversion * transform.Translation;

            halfExtents *= unitConversion;

            CollisionShape collisionShape;
            float          angle = 0;
            Vector3        axis  = Vector3.Zero;

            rot.ToAngleAxis(ref angle, ref axis);
            // I could build AABB shapes for boxes that are aligned, but then
            // I can't drop instances in the world with arbitrary rotations.
            // Instead, just always use an OBB.
            //if (angle < PhysicsSerializer.RotateEpsilon) {
            //    collisionShape = new CollisionAABB(center - halfExtents, center + halfExtents);
            //} else {
            // TODO: I'm not sure I understand the OBB constructor
            Vector3[] axes = new Vector3[3];
            axes[0]        = rot.XAxis;
            axes[1]        = rot.YAxis;
            axes[2]        = rot.ZAxis;
            collisionShape = new CollisionOBB(center, axes, halfExtents);
            physicsData.AddCollisionShape(objectId, collisionShape);
        }
        private static void TestPhysics( string srcDir, string dstDir, string name )
        {
            float OneMeter = 1000;
            PhysicsData pd = new PhysicsData();
            Vector3 center = new Vector3( 10 * OneMeter, 1 * OneMeter, 1 * OneMeter );
            Vector3[] obbAxes = new Vector3[ 3 ];
            obbAxes[ 0 ] = new Vector3( 1, 0, -1 );
            obbAxes[ 0 ].Normalize();
            obbAxes[ 1 ] = Vector3.UnitY;
            obbAxes[ 2 ] = new Vector3( 1, 0, 1 );
            obbAxes[ 2 ].Normalize();
            Vector3 obbExtents = new Vector3( 2.5f * OneMeter, 1 * OneMeter, 1 * OneMeter );
            CollisionOBB obb = new CollisionOBB( center, obbAxes, obbExtents );
            pd.AddCollisionShape( "submesh01", obb );
            CollisionAABB aabb = new CollisionAABB( center - obbExtents, center + obbExtents );
            pd.AddCollisionShape( "submesh01", aabb );
            CollisionSphere sphere = new CollisionSphere( center, 2 * OneMeter );
            pd.AddCollisionShape( "submesh01", sphere );
            Vector3 capExtents = new Vector3( -1 * OneMeter, 0, 0 );
            CollisionCapsule capsule = new CollisionCapsule( center + capExtents, center - capExtents, .5f * OneMeter );
            pd.AddCollisionShape( "submesh01", capsule );
            PhysicsSerializer ps = new PhysicsSerializer();
            ps.ExportPhysics( pd, name );

            pd = new PhysicsData();
            ps.ImportPhysics( pd, name );
            foreach( string objectId in pd.GetCollisionObjects() )
            {
                log.InfoFormat( "Collision shapes for: {0}", objectId );
                List<CollisionShape> collisionShapes = pd.GetCollisionShapes( objectId );
                foreach( CollisionShape shape in collisionShapes )
                    log.InfoFormat( "Shape: {0}", shape );
            }
        }
        public void ReadSphere(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData)
        {
            Vector3 scaleDelta = transform.Scale - Vector3.UnitScale;
            if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon)
                log.Error("Scale is not currently supported for sphere shapes");
            float radius = 0;
            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "radius":
                        radius = float.Parse(childNode.InnerText);
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }
            Vector3 center = unitConversion * transform.Translation;
            radius *= unitConversion;

            CollisionShape collisionShape = new CollisionSphere(center, radius);
            physicsData.AddCollisionShape(objectId, collisionShape);
        }
        public void ReadCapsule(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData)
        {
            Quaternion rot = MathHelpers.GetRotation(transform);
            Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform;
            Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale;
            if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon)
                log.Error("Scale is not currently supported for capsule shapes");
            float height = 0;
            float[] radius = new float[2];
            Vector3 halfExtents = Vector3.Zero;
            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "height":
                        height = float.Parse(childNode.InnerText);
                        break;
                    case "radius": {
                            string[] values = childNode.InnerText.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                            Debug.Assert(values.Length == 2);
                            for (int i = 0; i < 2; ++i)
                                radius[i] = float.Parse(values[i]);
                        }
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }
            // We only support capsules where the two radii match
            if (radius[0] != radius[1])
                log.Error("Different radii for capsules are not currently supported");
            Vector3 center = unitConversion * transform.Translation;
            Vector3 halfExtent = unitConversion * (.5f * height * (rot * Vector3.UnitY));
            radius[0] *= unitConversion;
            radius[1] *= unitConversion;

            CollisionShape collisionShape;
            collisionShape = new CollisionCapsule(center - halfExtent, center + halfExtent, radius[0]);
            physicsData.AddCollisionShape(objectId, collisionShape);
        }
        public void ReadBox(string objectId, Matrix4 transform, XmlNode node, PhysicsData physicsData)
        {
            Quaternion rot = MathHelpers.GetRotation(transform);
            Matrix4 tmpTransform = rot.Inverse().ToRotationMatrix() * transform;
            Vector3 scaleDelta = tmpTransform.Scale - Vector3.UnitScale;
            if (scaleDelta.Length > PhysicsSerializer.ScaleEpsilon)
                log.Error("Scale is not currently supported for box shapes");
            Vector3 halfExtents = Vector3.Zero;
            foreach (XmlNode childNode in node.ChildNodes) {
                switch (childNode.Name) {
                    case "half_extents":
                        ReadVector(ref halfExtents, childNode);
                        break;
                    default:
                        DebugMessage(childNode);
                        break;
                }
            }
            Vector3 center = unitConversion * transform.Translation;
            halfExtents *= unitConversion;

            CollisionShape collisionShape;
            float angle = 0;
            Vector3 axis = Vector3.Zero;
            rot.ToAngleAxis(ref angle, ref axis);
            // I could build AABB shapes for boxes that are aligned, but then
            // I can't drop instances in the world with arbitrary rotations.
            // Instead, just always use an OBB.
            //if (angle < PhysicsSerializer.RotateEpsilon) {
            //    collisionShape = new CollisionAABB(center - halfExtents, center + halfExtents);
            //} else {
            // TODO: I'm not sure I understand the OBB constructor
            Vector3[] axes = new Vector3[3];
            axes[0] = rot.XAxis;
            axes[1] = rot.YAxis;
            axes[2] = rot.ZAxis;
            collisionShape = new CollisionOBB(center, axes, halfExtents);
            physicsData.AddCollisionShape(objectId, collisionShape);
        }