/// <summary>
        /// Parses all H1CE Collision Node tagblocks stored sequentially.
        /// The purpose of 'Node' is similar to 'Region' in Halo Online.
        /// </summary>
        /// <param name="coll"></param>
        /// <param name="reader"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public long ParseNodes(CollisionModel coll, BinaryReader reader, int count)
        {
            var originalPos = reader.BaseStream.Position;

            coll.Nodes = new List <CollisionModel.Node>();
            //destroy the old list of regions, it may not be fine-grained enough
            coll.Regions = new List <CollisionModel.Region>();

            var new_region_count   = 0;
            var current_bsp_offset = originalPos + (count * NODE_SIZE);

            for (var i = 0; i < count; ++i)
            {
                var node = new CollisionModel.Node();
                node.Name = new StringId(0x140 + (uint)i);

                //offset of the parent node in the h1 ce node tagblock
                reader.BaseStream.Position = originalPos + (i * NODE_SIZE) + 32;
                short region_idx       = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0);
                short parent_node_idx  = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0);
                short next_sibling_idx = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0);
                short first_child_idx  = BitConverter.ToInt16(reader.ReadBytes(2).Reverse().ToArray(), 0);

                node.ParentNode      = parent_node_idx;
                node.NextSiblingNode = next_sibling_idx;
                node.FirstChildNode  = first_child_idx;

                coll.Nodes.Add(node);

                //there exists a region when the region index of the h1 ce collision node tagblock is not null
                if (region_idx >= 0)
                {
                    var region = new CollisionModel.Region();
                    coll.Regions.Add(region);
                    region.Name = new StringId(0x140 + (uint)new_region_count);
                    reader.BaseStream.Position = originalPos + (i * NODE_SIZE) + 52; //bsp tagblock count

                    //each bsp is placed into a separate permutation. In h1 ce
                    // a node referencing a region with n permutations has n bsps
                    region.Permutations = new List <CollisionModel.Region.Permutation>();
                    CollisionModel.Region.Permutation permutation = new CollisionModel.Region.Permutation();
                    region.Permutations.Add(permutation);
                    permutation.Bsps = new List <BSP>();
                    uint n_bsps = (uint)BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);
                    for (uint j = 0; j < n_bsps; ++j)
                    {
                        reader.BaseStream.Position = current_bsp_offset;
                        current_bsp_offset         = ParseBSP(permutation, reader);
                    }
                    new_region_count++;
                }
            }

            return(current_bsp_offset);
        }
        public long ParseBSP(CollisionModel.Region.Permutation permutation, BinaryReader reader)
        {
            long originalPos = reader.BaseStream.Position;
            var  bsp         = new BSP();

            permutation.Bsps.Add(bsp);

            reader.BaseStream.Position = originalPos + BSP_BSP3DNODES_OFFSET;
            int n_3dnodes = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_PLANES_OFFSET;
            int n_planes = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_LEAVES_OFFSET;
            int n_leaves = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_BSP2DREFERENCES_OFFSET;
            int n_2dreferences = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_BSP2DNODES_OFFSET;
            int n_2dnodes = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_SURFACES_OFFSET;
            int n_surfaces = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_EDGES_OFFSET;
            int n_edges = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_VERTICES_OFFSET;
            int n_vertices = BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);

            reader.BaseStream.Position = originalPos + BSP_SIZE;
            reader.BaseStream.Position = ParseBSP3DNodes(bsp, reader, n_3dnodes);
            reader.BaseStream.Position = ParsePlanes(bsp, reader, n_planes);
            reader.BaseStream.Position = ParseLeaves(bsp, reader, n_leaves);
            reader.BaseStream.Position = ParseBSP2DReferences(bsp, reader, n_2dreferences);
            reader.BaseStream.Position = ParseBSP2DNodes(bsp, reader, n_2dnodes);
            reader.BaseStream.Position = ParseSurfaces(bsp, reader, n_surfaces);
            reader.BaseStream.Position = ParseEdges(bsp, reader, n_edges);
            return(ParseVertices(bsp, reader, n_vertices));
        }
        /// <summary>
        /// Parses regions into Halo Online collision 'Region' tagblocks.
        /// Names are not preserved.
        /// </summary>
        /// <param name="coll"></param>
        /// <param name="reader"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public long ParseRegions(CollisionModel coll, BinaryReader reader, int count)
        {
            var originalPos = reader.BaseStream.Position;

            //The number of permutations that have been parsed in total for all regions
            var n_parsed_permutations = 0;
            //Permutations for all regions follow sequentially after all regions
            var permutations_base_addr = reader.BaseStream.Position
                                         + count * REGION_TAGBLOCK_SIZE;

            coll.Regions = new List <CollisionModel.Region>();

            for (uint i = 0; i < count; ++i)
            {
                //configure the current region
                CollisionModel.Region region = new CollisionModel.Region();
                region.Name = new StringId(0x140 + i);

                //set up stream for reading number of permutations in current region
                reader.BaseStream.Position = originalPos
                                             + (long)(i * REGION_TAGBLOCK_SIZE)
                                             + REGION_PERMUTATION_OFFSET;

                uint n_permutations = (uint)BitConverter.ToInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);
                region.Permutations = new List <CollisionModel.Region.Permutation>();

                for (uint j = 0; j < n_permutations; ++j)
                {
                    var permutation = new CollisionModel.Region.Permutation();
                    permutation.Name = new StringId(0x140 + j);
                    permutation.Bsps = new List <BSP>();
                    region.Permutations.Add(permutation);
                }

                coll.Regions.Add(region);
                n_parsed_permutations += (int)n_permutations;
            }

            return(permutations_base_addr + (n_parsed_permutations * PERMUTATION_SIZE));
        }
Exemple #4
0
        private CollisionModel GenerateCollisionModel(CachedTag modelTag, int geometryIndex, bool iscluster)
        {
            var collisionModel = new CollisionModel();

            collisionModel.Regions = new List <CollisionModel.Region>();

            var permutation = new CollisionModel.Region.Permutation()
            {
                Name         = DestCache.StringTable.GetStringId("default"),
                BspPhysics   = new List <CollisionBspPhysicsDefinition>(),
                BspMoppCodes = new List <TagTool.Havok.TagHkpMoppCode>(),
                Bsps         = new List <CollisionModel.Region.Permutation.Bsp>()
            };

            collisionModel.Regions = new List <CollisionModel.Region>()
            {
                new CollisionModel.Region()
                {
                    Name         = DestCache.StringTable.GetStringId("default"),
                    Permutations = new List <CollisionModel.Region.Permutation>()
                    {
                        permutation
                    }
                }
            };

            // copy over and fixup bsp physics blocks
            var newCollisionGeometry = new BspCollisionGeometry.CollisionGeometry();

            //instanced geometry
            if (!iscluster)
            {
                //bsp physics
                var instancedGeometryInstance = StructureBsp.InstancedGeometryInstances[geometryIndex];
                var instancedGeometryDef      = StructureBspResources.InstancedGeometry[instancedGeometryInstance.MeshIndex];

                foreach (var bspPhysics  in instancedGeometryInstance.BspPhysics)
                {
                    permutation.BspPhysics.Add(ConvertData(bspPhysics));
                }

                //mopps
                foreach (var mopp in instancedGeometryDef.CollisionMoppCodes)
                {
                    permutation.BspMoppCodes.Add(ConvertData(mopp));
                }

                //collision geometry
                newCollisionGeometry = instancedGeometryDef.CollisionInfo.DeepClone();
            }
            else
            {
                var cluster = StructureBsp.Clusters[geometryIndex];

                // bsp physics & mopps
                foreach (var mopp in cluster.CollisionMoppCodes)
                {
                    permutation.BspMoppCodes.Add(ConvertData(mopp));

                    var bspPhysics = new CollisionBspPhysicsDefinition
                    {
                        GeometryShape = new CollisionGeometryShape()
                        {
                            // need to double check this
                            AABB_Min = new RealQuaternion(cluster.BoundsX.Lower, cluster.BoundsY.Lower, cluster.BoundsZ.Lower, 0),
                            AABB_Max = new RealQuaternion(cluster.BoundsX.Upper, cluster.BoundsY.Upper, cluster.BoundsZ.Upper, 0),
                        },
                        MoppBvTreeShape = new Havok.HkpBvMoppTreeShape()
                    };
                    permutation.BspPhysics.Add(bspPhysics);
                }

                // collision geometry
                if (StructureBspResources.CollisionBsps.Count > 0)
                {
                    newCollisionGeometry = StructureBspResources.CollisionBsps[0].DeepClone();
                }

                //TODO: cull unnecessary parts of bsp collision
            }

            // fixup bsp fixups for collision model
            foreach (var bspPhysics in permutation.BspPhysics)
            {
                bspPhysics.GeometryShape.Model    = modelTag;
                bspPhysics.GeometryShape.BspIndex = -1;
                bspPhysics.GeometryShape.CollisionGeometryShapeKey  = 0xffff;
                bspPhysics.GeometryShape.CollisionGeometryShapeType = 0;
            }

            // fixup surfaces materials block
            // build a mapping of surface material indices to collision materials

            foreach (var surface in newCollisionGeometry.Surfaces)
            {
                if (surface.MaterialIndex == -1)
                {
                    continue;
                }

                short modelMaterialIndex;
                if (!CollisionMaterialMapping.TryGetValue(surface.MaterialIndex, out modelMaterialIndex))
                {
                    CollisionMaterialMapping.Add(surface.MaterialIndex, modelMaterialIndex);
                }

                surface.MaterialIndex = modelMaterialIndex;
            }

            // add the collision geometry
            permutation.Bsps.Add(new CollisionModel.Region.Permutation.Bsp()
            {
                NodeIndex = 0,
                Geometry  = newCollisionGeometry
            });

            return(collisionModel);
        }