private void Read(BinaryDataReader reader) { ModelOctreeRoot = new ModelOctreeNode(); ModelOctreeRoot.Children = new ModelOctreeNode[ModelOctreeNode.ChildCount]; Models = new List <KCLModel>(); reader.ByteOrder = ByteOrder.BigEndian; uint value = reader.ReadUInt32(); Version = (FileVersion)value; ByteOrder = CheckByteOrder(reader); reader.ByteOrder = this.ByteOrder; if ((FileVersion)value != FileVersion.Version2) //Assume the KCL is V1 instead { if (value == 56) //Smaller header (GCN) { Version = FileVersion.VersionGC; } else { using (reader.TemporarySeek(56, SeekOrigin.Begin)) { if (reader.ReadInt32() == 102400) { Version = FileVersion.VersionDS; } else { Version = FileVersion.VersionWII; } } } reader.Seek(-4); //Seek back and read V1 properly //V1 KCL is just a KCL model. KCLModel model = new KCLModel(); model.Read(reader, Version); Models.Add(model); //Create default model octrees that index the first model for (int i = 0; i < ModelOctreeNode.ChildCount; i++) { ModelOctreeRoot.Children[i] = new ModelOctreeNode() { ModelIndex = 0 }; } PrismCount = model.Prisms.Length; MinCoordinate = model.MinCoordinate; //Todo, auto generate the rest of V2 header data for V1 for cross conversion. } else { int octreeOffset = reader.ReadInt32(); int modelOffsetArrayOffset = reader.ReadInt32(); int modelCount = reader.ReadInt32(); MinCoordinate = reader.ReadVector3F(); MaxCoordinate = reader.ReadVector3F(); CoordinateShift = reader.ReadVector3U(); PrismCount = reader.ReadInt32(); reader.Position = octreeOffset; // Mostly unrequired, data is successive. for (int i = 0; i < ModelOctreeNode.ChildCount; i++) { ModelOctreeRoot.Children[i] = new ModelOctreeNode(reader, (uint)octreeOffset); } // Read the model offsets. reader.Position = modelOffsetArrayOffset; // Mostly unrequired, data is successive. int[] modelOffsets = reader.ReadInt32s(modelCount); Models = new List <KCLModel>(modelCount); foreach (int modelOffset in modelOffsets) { reader.Position = modelOffset; // Required as loading a model does not position reader at its end. var model = new KCLModel(); model.Read(reader, Version); Models.Add(model); } } }
/// <summary> /// Replaces the current collision model from the given /// <paramref name="objModel"/>. /// </summary> /// <param name="objModel">The <see cref="ObjModel"/> to create the collision data from.</param> public void Replace(List <Triangle> triangles, CollisionImportSettings settings) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); // Find the smallest and biggest coordinate (and add padding). Vector3 minCoordinate = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue); Vector3 maxCoordinate = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue); DebugLogger.WriteLine($"Replacing Collision..."); DebugLogger.WriteLine($"Settings:"); DebugLogger.WriteLine($"-MaxRootSize {settings.MaxRootSize}"); DebugLogger.WriteLine($"-MaxTrianglesInCube {settings.MaxTrianglesInCube}"); DebugLogger.WriteLine($"-MinCubeSize {settings.MinCubeSize}"); DebugLogger.WriteLine($"-PaddingMax {settings.PaddingMax}"); DebugLogger.WriteLine($"-PaddingMin {settings.PaddingMin}"); DebugLogger.WriteLine($"-PrismThickness {settings.PrismThickness}"); DebugLogger.WriteLine($"-SphereRadius {settings.SphereRadius}"); DebugLogger.WriteLine($"Calculating bounding sizes..."); for (int i = 0; i < triangles.Count; i++) { for (int v = 0; v < triangles[i].Vertices.Length; v++) { Vector3 position = triangles[i].Vertices[v]; minCoordinate.X = Math.Min(position.X, minCoordinate.X); minCoordinate.Y = Math.Min(position.Y, minCoordinate.Y); minCoordinate.Z = Math.Min(position.Z, minCoordinate.Z); maxCoordinate.X = Math.Max(position.X, maxCoordinate.X); maxCoordinate.Y = Math.Max(position.Y, maxCoordinate.Y); maxCoordinate.Z = Math.Max(position.Z, maxCoordinate.Z); } } MinCoordinate = minCoordinate + settings.PaddingMin; MaxCoordinate = maxCoordinate + settings.PaddingMax; DebugLogger.WriteLine($"MinCoordinate: {MinCoordinate}"); DebugLogger.WriteLine($"MaxCoordinate: {MaxCoordinate}"); // Compute square cube size of the world, and with it the coordinate shift for use with the model octree. Vector3 size = MaxCoordinate - MinCoordinate; int worldLengthExp = Maths.GetNext2Exponent(Math.Min(Math.Min(size.X, size.Y), size.Z)); int cubeSize = 1 << worldLengthExp; Vector3 exponents = new Vector3( Maths.GetNext2Exponent(size.X), Maths.GetNext2Exponent(size.Y), Maths.GetNext2Exponent(size.Z)); CoordinateShift = new Vector3U( (uint)(exponents.X), (uint)(exponents.Y), (uint)(exponents.Z)); Models = new List <KCLModel>(); Vector3 boxSize = new Vector3( 1 << (int)CoordinateShift.X, 1 << (int)CoordinateShift.Y, 1 << (int)CoordinateShift.Z); DebugLogger.WriteLine($"Model Octree Bounds: {boxSize}"); //Create subdivied triangle models var modelRoots = CreateModelDivision(MinCoordinate, triangles, boxSize / 2f); //For a model octree, we need 8 octrees per division ModelOctreeRoot = new ModelOctreeNode(); ModelOctreeRoot.Children = new ModelOctreeNode[ModelOctreeNode.ChildCount]; for (int i = 0; i < ModelOctreeNode.ChildCount; i++) { ModelOctreeRoot.Children[i] = new ModelOctreeNode(); } Models.Clear(); //Load all the model data CreateModelOctree(modelRoots, ModelOctreeRoot.Children, settings, 0); PrismCount = Models.Sum(x => x.Prisms.Length); stopWatch.Stop(); DebugLogger.WriteLine($"Model Octree:"); PrintModelOctree(ModelOctreeRoot.Children); DebugLogger.WriteLine($"Finished Collsion Generation {stopWatch.Elapsed}"); }