Exemplo n.º 1
0
        /// <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));
                }
            }
        }
Exemplo n.º 2
0
        /// <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));
            }
        }