protected void Load(string name, InstancingType instancing) { if (name == null || name == string.Empty) { return; } // load description ModelDescription desc = game.Content.Load <ModelDescription>(".\\Content\\Models\\" + name + "Desc"); LocalRotation = Quaternion.CreateFromAxisAngle(desc.BaseRotationAxis, MathHelper.ToRadians(desc.BaseRotationAngle)); // load fbx Microsoft.Xna.Framework.Graphics.Model model = game.Content.Load <Microsoft.Xna.Framework.Graphics.Model>(".\\Content\\Models\\" + desc.BaseFBX); // process meshes foreach (ModelMesh modelmesh in model.Meshes) { // wrap ModelMesh in adapter IMesh mesh; switch (instancing) { case InstancingType.None: mesh = new ModelMeshAdapterMesh(game, modelmesh); break; case InstancingType.Constants: mesh = new ConstantsInstancingModelMeshAdapterMesh(game, modelmesh); break; case InstancingType.Hardware: mesh = new HardwareInstancingModelMeshAdapterMesh(game, modelmesh); break; default: throw new Exception(); } mesh.Parent = this; meshes.Add(mesh); // get material name. prefer the one with the mesh's name before * string materialName = ""; foreach (MeshMaterial matdesc in desc.Materials) { if (matdesc.MeshName == modelmesh.Name) { materialName = matdesc.MaterialName; break; } if (matdesc.MeshName == "*") { if (materialName == "") { materialName = matdesc.MaterialName; } } } // load material Material material = Material.Create(game, materialName, instancing); materials.Add(material); // tell the mesh which effect to use mesh.Effect = material.Effect; } // get weapon slots foreach (WeaponDescription weapon in desc.Weapons) { WeaponSlot slot = new WeaponSlot( (WeaponType)Enum.Parse(typeof(WeaponType), weapon.WeaponType, false), weapon.Position, weapon.RotationAxis, weapon.RotationAngle, weapon.Scaling); weaponSlots.Add(slot); } // get collision shapes foreach (Box box in desc.CollisionShapes.Boxes) { BoxShapeData shape = new BoxShapeData(); shape.Dimensions = box.Size; Matrix m = Matrix.CreateFromQuaternion(Quaternion.CreateFromAxisAngle(box.OffsetRotationAxis, box.OffsetRotationAngle)); m.Translation = box.OffsetPosition; shape.Offset = m; shape.Material.Friction = desc.Friction; shape.Material.Bounciness = desc.Bounciness; shape.Material.Hardness = desc.Hardness; collisionShapes.Add(shape); } foreach (Capsule capsule in desc.CollisionShapes.Capsules) { CapsuleShapeData shape = new CapsuleShapeData(); shape.Radius = capsule.Radius; shape.Length = capsule.Length; Matrix m = Matrix.CreateFromQuaternion(Quaternion.CreateFromAxisAngle(capsule.OffsetRotationAxis, capsule.OffsetRotationAngle)); m.Translation = capsule.OffsetPosition; shape.Offset = m; shape.Material.Friction = desc.Friction; shape.Material.Bounciness = desc.Bounciness; shape.Material.Hardness = desc.Hardness; collisionShapes.Add(shape); } foreach (Sphere sphere in desc.CollisionShapes.Spheres) { SphereShapeData shape = new SphereShapeData(); shape.Radius = sphere.Radius; Matrix m = Matrix.CreateTranslation(sphere.OffsetPosition); shape.Offset = m; shape.Material.Friction = desc.Friction; shape.Material.Bounciness = desc.Bounciness; shape.Material.Hardness = desc.Hardness; collisionShapes.Add(shape); } wreckageModels = desc.Wreckages; // get particle effects if (game.World != null) { foreach (ParticleEffectDescription effect in desc.ParticleEffects) { IEffect fx = game.Effects.CreateEffect(effect.EffectName); fx.Parent = this; fx.LocalPosition = effect.Position; fx.LocalRotation = Quaternion.CreateFromAxisAngle(effect.RotationAxis, effect.RotationAngle); fx.LocalScale = effect.Scaling; game.World.AddEffect(fx); particleEffects.Add(fx); // for calling Destroy() later fx.Play(); } } // afterburner foreach (AfterBurnerEffectDescription ab in desc.AfterBurnerEffects) { AfterBurner a = new AfterBurner(game); a.Parent = this; a.LocalPosition = ab.Position; a.LocalScale = ab.Scaling; a.LocalRotation = Quaternion.CreateFromAxisAngle(ab.RotationAxis, ab.RotationAngle); a.LoadTheContent(); afterBurnerEffects.Add(a); } // get animations foreach (MeshAnimation anim in desc.Animations) { foreach (IMesh mesh in meshes) { if (mesh.Name == anim.MeshName) { mesh.Animation = anim; break; // inner foreach } } } // mass mass = desc.Mass; // base rotation LocalRotation = Quaternion.CreateFromAxisAngle(desc.BaseRotationAxis, desc.BaseRotationAngle); // save name this.name = name; }
public override void AddShape(ShapeData data) { if (data.Material.Density < 0) { return; } dGeomID newGeomID = null; dGeomID newTransformID = null; dTriMeshDataID newTrimeshDataID = null; dSpaceID tempSpaceID = null; Tao.Ode.Ode.dMass newMass = new Tao.Ode.Ode.dMass(); if (new Matrix() == data.Offset) { // No offset transform. tempSpaceID = spaceID; newTransformID = null; } else { // Use ODE's geom transform object. tempSpaceID = IntPtr.Zero; newTransformID = spaceID.CreateGeomTransform(); } // Allocate a new GeomData object. GeomData newGeomData = new GeomData(); switch (data.Type) { case ShapeType.Box: { BoxShapeData boxData = data as BoxShapeData; newGeomID = tempSpaceID.CreateBoxGeom(boxData.Dimensions.X, boxData.Dimensions.Y, boxData.Dimensions.Z); Tao.Ode.Ode.dMassSetBox(ref newMass, data.Material.Density, boxData.Dimensions.X, boxData.Dimensions.Y, boxData.Dimensions.Z); break; } case ShapeType.Sphere: { SphereShapeData sphereData = data as SphereShapeData; newGeomID = tempSpaceID.CreateSphereGeom(sphereData.Radius); Tao.Ode.Ode.dMassSetSphere(ref newMass, data.Material.Density, sphereData.Radius); break; } case ShapeType.Capsule: { CapsuleShapeData capsuleData = data as CapsuleShapeData; newGeomID = tempSpaceID.CreateCylinderGeom(capsuleData.Radius, capsuleData.Length); // The "direction" parameter orients the mass along one of the // body's local axes; x=1, y=2, z=3. This axis MUST // correspond with the axis along which the capsule is // initially aligned, which is the capsule's local Z axis. /*Tao.Ode.Ode.dMassSetCylinder(ref newMass, data.Material.Density, * 3, capsuleData.Radius, capsuleData.Length);*/ Tao.Ode.Ode.dMassSetCapsule(ref newMass, data.Material.Density, 3, capsuleData.Radius, capsuleData.Length); break; } case ShapeType.Plane: { PlaneShapeData planeData = data as PlaneShapeData; if (!this.data.IsStatic) { //OPAL_LOGGER( "warning" ) << "opal::ODESolid::addPlane: " << //"Plane Shape added to a non-static Solid. " << //"The Solid will be made static." << std::endl; // ODE planes can't have bodies, so make it static. this.Static = true; } // TODO: make this fail gracefully and print warning: plane // offset transform ignored. if (newTransformID != null) { break; } // ODE planes must have their normal vector (abc) normalized. Vector3 normal = new Vector3(planeData.Abcd[0], planeData.Abcd[1], planeData.Abcd[2]); normal.Normalize(); newGeomID = tempSpaceID.CreatePlaneGeom(normal.X, normal.Y, normal.Z, planeData.Abcd[3]); // Note: ODE planes cannot have mass, but this is already // handled since static Solids ignore mass. // Solids with planes are the only non-"placeable" Solids. isPlaceable = false; break; } //case RAY_SHAPE: //{ // RayShapeData& rayData = (RayShapeData&)data; // newGeomID = dCreateRay(spaceID, // (dReal)rayData.ray.getLength()); // Point3r origin = rayData.ray.getOrigin(); // Vec3r dir = rayData.ray.getDir(); // dGeomRaySet(newGeomID, (dReal)origin[0], (dReal)origin[1], // (dReal)origin[2], (dReal)dir[0], (dReal)dir[1], // (dReal)dir[2]); // // Note: rays don't have mass. // break; //} case ShapeType.Mesh: { MeshShapeData meshData = data as MeshShapeData; // Setup trimesh data pointer. It is critical that the // size of OPAL reals at this point match the size of ODE's // dReals. newTrimeshDataID = dTriMeshDataID.Create(); // Old way... This is problematic because ODE interprets // the vertex array as an array of dVector3s which each // have 4 elements. //dGeomTriMeshDataBuildSimple(newTrimeshDataID, // (dReal*)meshData.vertexArray, meshData.numVertices, // (int*)meshData.triangleArray, 3 * meshData.numTriangles); //#ifdef dSINGLE newTrimeshDataID.BuildSingle(meshData.VertexArray, 3 * sizeof(float), meshData.NumVertices, meshData.TriangleArray, 3 * meshData.NumTriangles, 3 * sizeof(int)); //#else // dGeomTriMeshDataBuildDouble( newTrimeshDataID, // ( void* ) meshData.vertexArray, 3 * sizeof( real ), // meshData.numVertices, ( void* ) meshData.triangleArray, // 3 * meshData.numTriangles, 3 * sizeof( unsigned int ) ); //#endif newGeomID = tempSpaceID.CreateTriMeshGeom(newTrimeshDataID); // This is a simple way to set the mass of an arbitrary // mesh. Ideally we would compute the exact volume and // intertia tensor. Instead we just use a box // inertia tensor from its axis-aligned bounding box. float[] aabb = newGeomID.AABB; // dGeomGetAABB( newGeomID, aabb ); Tao.Ode.Ode.dMassSetBox(ref newMass, data.Material.Density, aabb[1] - aabb[0], aabb[3] - aabb[2], aabb[5] - aabb[4]); break; } default: throw new InvalidOperationException("OdeSolid.AddShape"); } // This will do nothing if this is a static Solid. AddMass(newMass, data.Offset); // Store new Shape. this.data.AddShape(data); // Update the Solid's local AABB. The new shape's local AABB // must be transformed using the shape's offset from the Solid. BoundingBox shapeAABB = data.LocalAABB; //data.LocalAABBgetLocalAABB( shapeAABB ); Vector3 minExtents = Vector3.Transform(shapeAABB.Min, data.Offset); Vector3 maxExtents = Vector3.Transform(shapeAABB.Max, data.Offset); shapeAABB.Min = minExtents; shapeAABB.Max = maxExtents; AddToLocalAABB(shapeAABB); if (newGeomData == null) { return; } // Setup GeomData. newGeomData.Solid = this; newGeomData.Shape = this.data.GetShapeData(this.data.NumShapes - 1); newGeomData.GeomID = newGeomID; newGeomData.TransformID = newTransformID; newGeomData.SpaceID = spaceID; newGeomData.TrimeshDataID = newTrimeshDataID; // Setup the geom. SetupNewGeom(newGeomData); }