/// <summary> /// Loads the data from the given <paramref name="stream"/>. /// </summary> /// <param name="stream">The <see cref="Stream"/> to load the data from.</param> /// <param name="loadOctree"><c>true</c> to also load the octree referencing models.</param> /// <param name="leaveOpen"><c>true</c> to leave <paramref name="stream"/> open after loading the instance. /// </param> public void Load(Stream stream, bool loadOctree, bool leaveOpen = false, ByteOrder Endianness = ByteOrder.LittleEndian) { using (BinaryDataReader reader = new BinaryDataReader(stream, leaveOpen)) { reader.ByteOrder = ByteOrder.BigEndian; // Read the header. if (reader.ReadInt32() != _signature) { throw new InvalidDataException("Invalid KCL file signature."); } reader.ByteOrder = Endianness; int octreeOffset = reader.ReadInt32(); int modelOffsetArrayOffset = reader.ReadInt32(); int modelCount = reader.ReadInt32(); MinCoordinate = reader.ReadVector3F(); MaxCoordinate = reader.ReadVector3F(); CoordinateShift = reader.ReadVector3(); Unknown = reader.ReadInt32(); // Read the model octree. if (loadOctree) { reader.Position = octreeOffset; // Mostly unrequired, data is successive. CourseOctreeRoot = new CourseOctreeNode(); CourseOctreeRoot.Children = new CourseOctreeNode[CourseOctreeNode.ChildCount]; for (int i = 0; i < CourseOctreeNode.ChildCount; i++) { CourseOctreeRoot.Children[i] = new CourseOctreeNode(reader); } } // Read the model offsets. reader.Position = modelOffsetArrayOffset; // Mostly unrequired, data is successive. int[] modelOffsets = reader.ReadInt32s(modelCount); // Read the models. 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. Models.Add(new KclModel(stream, loadOctree, true, Endianness)); } } }
/// <summary> /// Initializes a new instance of the <see cref="KclFile"/> class, created from the given /// <paramref name="objModel"/>. /// </summary> /// <param name="objModel">The <see cref="ObjModel"/> to create the collision data from.</param> public KclFile(ObjModel objModel) { // TODO: Divide models with more than 65535 triangles and generate a global octree accordingly. List <ObjModel> objSubModels = new List <ObjModel> { objModel }; CourseOctreeRoot = new CourseOctreeNode() { Children = new CourseOctreeNode[CourseOctreeNode.ChildCount] }; for (int i = 0; i < CourseOctreeNode.ChildCount; i++) { CourseOctreeNode child = new CourseOctreeNode() { ModelIndex = 0 }; CourseOctreeRoot.Children[i] = child; } // Find the smallest and biggest coordinate (and add padding). Vector3F minCoordinate = new Vector3F(Single.MaxValue, Single.MaxValue, Single.MaxValue); Vector3F maxCoordinate = new Vector3F(Single.MinValue, Single.MinValue, Single.MinValue); foreach (ObjModel objSubModel in objSubModels) { foreach (ObjFace objFace in objModel.Faces) { foreach (ObjVertex objVertex in objFace.Vertices) { Vector3F position = objSubModel.Positions[objVertex.PositionIndex]; 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 + _minCoordinatePadding; MaxCoordinate = maxCoordinate + _maxCoordinatePadding; // Compute square cube size of the world, and with it the coordinate shift for use with the model octree. Vector3F size = MaxCoordinate - MinCoordinate; int worldLengthExp = Maths.GetNext2Exponent(Math.Min(Math.Min(size.X, size.Y), size.Z)); Vector3 exponents = new Vector3( Maths.GetNext2Exponent(size.X), Maths.GetNext2Exponent(size.Y), Maths.GetNext2Exponent(size.Z)); CoordinateShift = new Vector3( worldLengthExp, exponents.X - worldLengthExp, exponents.X - worldLengthExp + exponents.Y - worldLengthExp); // Create model instances. Models = new List <KclModel>(objSubModels.Count); foreach (ObjModel subModel in objSubModels) { Models.Add(new KclModel(objModel)); } }