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}");
        }