/// <summary> /// Initialise the physics model to be built /// </summary> public PhysicsModelBuilder() { _phmo = new PhysicsModel(); _phmo.RigidBodies = new List<PhysicsModel.RigidBody>(); _phmo.Nodes = new List<PhysicsModel.Node>(); var node = new PhysicsModel.Node(); node.Child = -1; node.Sibling = -1; node.Parent = -1; //the 'default' stringid node.Name = new StringID(1); _phmo.Nodes.Add(node); _phmo.Materials = new List<PhysicsModel.Material>(); var material = new PhysicsModel.Material(); //the 'default' stringid material.Name = new StringID(1); material.Flags = -256; material.PhantomType = -1; _phmo.Materials.Add(material); }
/// <summary> /// Gets the number of shapes in the list for the particular shape /// </summary> /// <param name="phmo">the serialized phmo from which to get the counts</param> /// <param name="type">the shape for which to get the count</param> /// <returns></returns> private int getNumberOfShapes(PhysicsModel phmo, ShapeTypes type) { switch (type) { case ShapeTypes.Box: return phmo.Boxes != null ? phmo.Boxes.Count : 0; case ShapeTypes.List: return phmo.Lists != null ? phmo.Lists.Count : 0; case ShapeTypes.Mopp: return phmo.Mopps != null ? phmo.Mopps.Count : 0; case ShapeTypes.Pill: return phmo.Pills != null ? phmo.Pills.Count : 0; case ShapeTypes.Polyhedron: return phmo.Polyhedra != null ? phmo.Polyhedra.Count : 0; case ShapeTypes.Sphere: return phmo.Spheres != null ? phmo.Spheres.Count : 0; default: return 0; } }
/// <summary> /// Finds the type of the shape and adds it. Currently, only 'Polyhedron' is supported. /// </summary> /// <param name="phmo">the tag to add the shape to</param> /// <param name="n">the json node from which to parse the shape description.</param> /// <returns>shape type added, 'Unused0' is used to represent failure.</returns> private ShapeTypes AddShape(PhysicsModel phmo, JSONNode n) { if (n == null) { return ShapeTypes.Unused0; } //an element of the top-level JSON array is a map // containing values for keys: 'Type', 'Data' switch (n["Type"]) { case "Polyhedron": return AddPolyhedron(phmo, n["Data"]) ? ShapeTypes.Polyhedron : ShapeTypes.Unused0; default: return ShapeTypes.Unused0; } }
private bool AddPolyhedron(PhysicsModel phmo, JSONNode n) { if (n == null) { return false; } //In the control flow, it could have been possible to have // no polyhedra up to this point. if (phmo.Polyhedra == null) { phmo.Polyhedra = new List<PhysicsModel.Polyhedron>(); } int index = phmo.Polyhedra.Count; PhysicsModel.Polyhedron poly = new PhysicsModel.Polyhedron(); float friction, mass, restitution; int polyListOffset = phmo.Polyhedra.Count; //the index this polyhedron will be put into. bool fault = false; foreach (string attr in new string[]{ "Friction", "Mass", "Center", "Extents", "Restitution" }) { if (n[attr] == null) { fault = true; Console.WriteLine("Polyhedra {0} had no \"{1}\" attribute.", polyListOffset, attr); } } if (fault) { return false; } friction = n["Friction"].AsFloat; mass = n["Mass"].AsFloat; restitution = n["Restitution"].AsFloat; var center = n["Center"].AsArray; var extents = n["Extents"].AsArray; int nPlanes = AddManyPlanes(phmo, n["Planes"]); int nFVS = AddManyFVS(phmo, n["Vertices"]); if (nPlanes <= 0 || nFVS <= 0) { return false; } //This portion of the 'Polyhedron' tagblock becomes severly // mutated at runtime. The AABB center and half-extents // are still there however. This field may not be // correctly named however this number is always used for it. poly.Size = 0; poly.Count = 128; // uncertain as to what this does. poly.Offset = 32 + index * 128; //The axis-aligned fields are used to optimise collisions // with other physics objects. If they are set incorrectly, // other objects will pass through this object. poly.AabbCenterI = center[0].AsFloat; poly.AabbCenterJ = center[1].AsFloat; poly.AabbCenterK = center[2].AsFloat; poly.AabbHalfExtentsI = extents[0].AsFloat; poly.AabbHalfExtentsJ = extents[1].AsFloat; poly.AabbHalfExtentsK = extents[2].AsFloat; //The field 'Radius' is strange. When the byte at 0x18 of // the main-struct is assigned a value x > 0, the 'radius' // of the Polyhedron is used to repel other physics objects // which enter the radius. This might be used to correctly // repel penetrating objects. //poly.Radius = __ poly.Restitution = restitution; poly.Friction = friction; poly.Mass = mass; poly.RelativeMassScale = 1.0f; poly.PhantomIndex = 0; poly.PhantomIndex--; poly.InteractionUnknown = 0; poly.InteractionUnknown--; poly.FourVectorsSize = nFVS; poly.FourVectorsCapacity = (uint)(0x80000000 + nFVS); // poly.PlaneEquationsSize = nPlanes; poly.PlaneEquationsCapacity = (uint)(0x80000000 + nPlanes); // poly.GlobalMaterialIndex = 0; //A possible improvement could be to calculate this poly.Volume = 0.1f; phmo.Polyhedra.Add(poly); return true; }
/// <summary> /// Adds planes to the physics model as described by the JSON node /// </summary> /// <param name="phmo"></param> /// <param name="n">a node that is a list of plane equations</param> /// <returns>The number of plane-equation tag-blocks added</returns> private int AddManyPlanes(PhysicsModel phmo, JSONNode n) { if (n == null) { Console.WriteLine("could not find \"Planes\" attribute."); return 0; } if (phmo.PolyhedronPlaneEquations == null) { phmo.PolyhedronPlaneEquations = new List<PhysicsModel.PolyhedronPlaneEquation>(); } foreach (JSONNode p in n.AsArray) { var p_vals = p.AsArray; var plane = new PhysicsModel.PolyhedronPlaneEquation(); plane.Unknown = p_vals[0].AsFloat; //i plane.Unknown2 = p_vals[1].AsFloat; //j plane.Unknown3 = p_vals[2].AsFloat; //k plane.Unknown4 = p_vals[3].AsFloat; // dist phmo.PolyhedronPlaneEquations.Add(plane); } return n.AsArray.Count; }
/// <summary> /// Adds Four-vertex tag-blocks to the physics model. For lists /// of vertices that are not multiples of four, the last vertex /// is copied. /// </summary> /// <param name="phmo"></param> /// <param name="n">a node that is a list of vertex equations</param> /// <returns>the number of four-vertex tag-blocks added.</returns> private int AddManyFVS(PhysicsModel phmo, JSONNode n) { if (n == null) { Console.WriteLine("could not find \"Vertices\" attribute."); return 0; } if (phmo.PolyhedronFourVectors == null) { phmo.PolyhedronFourVectors = new List<PhysicsModel.PolyhedronFourVector>(); } int vertCount = n.AsArray.Count; int numfvs = vertCount / 4 + ((vertCount % 4) > 0 ? 1 : 0); for (int i = 0; i < numfvs; ++i) { JSONNode v0 = (i * 4) < vertCount ? n.AsArray[i * 4] : n.AsArray[vertCount - 1]; JSONNode v1 = (i * 4 + 1) < vertCount ? n.AsArray[i * 4 + 1] : n.AsArray[vertCount - 1]; JSONNode v2 = (i * 4 + 2) < vertCount ? n.AsArray[i * 4 + 2] : n.AsArray[vertCount - 1]; JSONNode v3 = (i * 4 + 3) < vertCount ? n.AsArray[i * 4 + 3] : n.AsArray[vertCount - 1]; var fourvert = new PhysicsModel.PolyhedronFourVector(); //The plugin had these named incorrectly, the four vectors are really //four vertices, with the coordinates grouped (four X's, four Y's, four Z's) //This is likely done for SIMD. If the number of vertices aren't a multiple //of four, usually the last vertex is copied several times. fourvert.FourVectorsXI = v0.AsArray[0].AsFloat; fourvert.FourVectorsXJ = v1.AsArray[0].AsFloat; fourvert.FourVectorsXK = v2.AsArray[0].AsFloat; fourvert.FourVectorsXRadius = v3.AsArray[0].AsFloat; fourvert.FourVectorsYI = v0.AsArray[1].AsFloat; fourvert.FourVectorsYJ = v1.AsArray[1].AsFloat; fourvert.FourVectorsYK = v2.AsArray[1].AsFloat; fourvert.FourVectorsYRadius = v3.AsArray[1].AsFloat; fourvert.FourVectorsZI = v0.AsArray[2].AsFloat; fourvert.FourVectorsZJ = v1.AsArray[2].AsFloat; fourvert.FourVectorsZK = v2.AsArray[2].AsFloat; fourvert.FourVectorsZRadius = v3.AsArray[2].AsFloat; phmo.PolyhedronFourVectors.Add(fourvert); } return numfvs; }