private TagResourceReference ConvertStructureBspTagResources(ScenarioStructureBsp bsp)
        {
            StructureBspTagResources resourceDefinition = BlamCache.ResourceCache.GetStructureBspTagResources(bsp.CollisionBspResource);

            // probably can remove all the code here

            if (resourceDefinition == null)
            {
                return(null);
            }

            if (BlamCache.Version < CacheVersion.Halo3ODST)
            {
                // convert surface planes
                foreach (var instance in resourceDefinition.InstancedGeometry)
                {
                    foreach (var surfacePlane in instance.SurfacePlanes)
                    {
                        surfacePlane.PlaneCountNew = surfacePlane.PlaneCountOld;
                        surfacePlane.PlaneIndexNew = surfacePlane.PlaneIndexOld;
                    }

                    foreach (var mopps in instance.CollisionMoppCodes)
                    {
                        mopps.Data.Elements = HavokConverter.ConvertMoppCodes(BlamCache.Version, CacheContext.Version, mopps.Data.Elements);
                    }
                }
            }

            bsp.CollisionBspResource = CacheContext.ResourceCache.CreateStructureBspResource(resourceDefinition);

            return(bsp.CollisionBspResource);
        }
예제 #2
0
        public GeometryToObjectConverter(
            GameCacheHaloOnlineBase destCache, Stream destStream, GameCache sourceCache,
            Stream sourceStream, Scenario scenario, int structureBspIndex)
        {
            DestCache         = destCache;
            DestStream        = destStream;
            SourceCache       = sourceCache;
            SourceStream      = sourceStream;
            StructureBspIndex = structureBspIndex;
            PortTag           = new PortTagCommand(destCache, sourceCache);
            PortTag.SetFlags(PortTagCommand.PortingFlags.Default);

            Scenario          = scenario;
            StructureBspIndex = structureBspIndex;
            StructureBsp      = SourceCache.Deserialize <ScenarioStructureBsp>(SourceStream, Scenario.StructureBsps[structureBspIndex].StructureBsp);
            sLdT = SourceCache.Deserialize <ScenarioLightmap>(SourceStream, Scenario.Lightmap);

            if (SourceCache.Version >= CacheVersion.Halo3ODST)
            {
                Lbsp = SourceCache.Deserialize <ScenarioLightmapBspData>(SourceStream, sLdT.LightmapDataReferences[StructureBspIndex]);
            }
            else
            {
                Lbsp = sLdT.Lightmaps[StructureBspIndex];
            }

            var resourceDefinition = SourceCache.ResourceCache.GetRenderGeometryApiResourceDefinition(Lbsp.Geometry.Resource);

            Lbsp.Geometry.SetResourceBuffers(resourceDefinition);

            StructureBspResources = SourceCache.ResourceCache.GetStructureBspTagResources(StructureBsp.CollisionBspResource);
        }
예제 #3
0
 public abstract TagResourceReference CreateStructureBspResource(StructureBspTagResources sbspResource);
예제 #4
0
 public override TagResourceReference CreateStructureBspResource(StructureBspTagResources sbspResource)
 {
     throw new NotImplementedException();
 }
예제 #5
0
        private PageableResource ConvertStructureBspTagResources(ScenarioStructureBsp bsp, Dictionary <ResourceLocation, Stream> resourceStreams)
        {
            //
            // Set up ElDorado resource reference
            //

            bsp.CollisionBspResource = new PageableResource
            {
                Page = new RawPage
                {
                    Index = -1
                },
                Resource = new TagResourceGen3
                {
                    ResourceType             = TagResourceTypeGen3.Collision,
                    DefinitionData           = new byte[0x30],
                    DefinitionAddress        = new CacheResourceAddress(CacheResourceAddressType.Definition, 0),
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    Unknown2 = 1
                }
            };

            //
            // Port Blam resource definition
            //

            var resourceEntry = BlamCache.ResourceGestalt.TagResources[bsp.ZoneAssetIndex3.Index];

            bsp.CollisionBspResource.Resource.DefinitionAddress = resourceEntry.DefinitionAddress;
            bsp.CollisionBspResource.Resource.DefinitionData    = BlamCache.ResourceGestalt.FixupInformation.Skip(resourceEntry.FixupInformationOffset).Take(resourceEntry.FixupInformationLength).ToArray();

            StructureBspTagResources resourceDefinition = null;

            using (var definitionStream = new MemoryStream(bsp.CollisionBspResource.Resource.DefinitionData, true))
                using (var definitionReader = new EndianReader(definitionStream, EndianFormat.BigEndian))
                    using (var definitionWriter = new EndianWriter(definitionStream, EndianFormat.BigEndian))
                    {
                        foreach (var fixup in resourceEntry.ResourceFixups)
                        {
                            var newFixup = new TagResourceGen3.ResourceFixup
                            {
                                BlockOffset = (uint)fixup.BlockOffset,
                                Address     = new CacheResourceAddress(
                                    fixup.Type == 4 ?
                                    CacheResourceAddressType.Resource :
                                    CacheResourceAddressType.Definition,
                                    fixup.Offset)
                            };

                            definitionStream.Position = newFixup.BlockOffset;
                            definitionWriter.Write(newFixup.Address.Value);

                            bsp.CollisionBspResource.Resource.ResourceFixups.Add(newFixup);
                        }

                        var dataContext = new DataSerializationContext(definitionReader, definitionWriter, CacheResourceAddressType.Definition);

                        definitionStream.Position = bsp.CollisionBspResource.Resource.DefinitionAddress.Offset;
                        resourceDefinition        = BlamCache.Deserializer.Deserialize <StructureBspTagResources>(dataContext);

                        //
                        // Apply game-specific fixes to the resource definition
                        //

                        if (BlamCache.Version < CacheVersion.Halo3ODST)
                        {
                            resourceDefinition.LargeCollisionBsps = new List <StructureBspTagResources.LargeCollisionBspBlock>();
                            resourceDefinition.HavokData          = new List <StructureBspTagResources.HavokDatum>();
                        }

                        foreach (var instance in resourceDefinition.InstancedGeometry)
                        {
                            instance.Unknown5 = new TagBlock <StructureBspTagResources.InstancedGeometryBlock.Unknown4Block>();
                            instance.Unknown2 = new TagBlock <StructureBspTagResources.InstancedGeometryBlock.Unknown2Block>();
                        }
                    }

            //
            // Load Blam resource data
            //

            var resourceData = BlamCache.GetRawFromID(bsp.ZoneAssetIndex3);

            if (resourceData == null)
            {
                CacheContext.Serializer.Serialize(new ResourceSerializationContext(CacheContext, bsp.CollisionBspResource), resourceDefinition);
                return(bsp.CollisionBspResource);
            }

            //
            // Port Blam resource to ElDorado resource cache
            //

            using (var blamResourceStream = resourceData != null ? new MemoryStream(resourceData) : new MemoryStream())
                using (var resourceReader = new EndianReader(blamResourceStream, EndianFormat.BigEndian))
                    using (var dataStream = new MemoryStream())
                        using (var resourceWriter = new EndianWriter(dataStream, EndianFormat.LittleEndian))
                        {
                            var dataContext = new DataSerializationContext(resourceReader, resourceWriter);

                            foreach (var collisionBsp in resourceDefinition.CollisionBsps)
                            {
                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position     = collisionBsp.Bsp3dNodes.Address.Offset;
                                collisionBsp.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Bsp3dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp3dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = collisionBsp.Planes.Address.Offset;
                                collisionBsp.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Planes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = collisionBsp.Leaves.Address.Offset;
                                collisionBsp.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Leaves.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position          = collisionBsp.Bsp2dReferences.Address.Offset;
                                collisionBsp.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Bsp2dReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position     = collisionBsp.Bsp2dNodes.Address.Offset;
                                collisionBsp.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position   = collisionBsp.Surfaces.Address.Offset;
                                collisionBsp.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Surfaces.Count; i++)
                                {
                                    var surface = BlamCache.Deserializer.Deserialize <CollisionGeometry.Surface>(dataContext);
                                    CacheContext.Serializer.Serialize(dataContext, surface);
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = collisionBsp.Edges.Address.Offset;
                                collisionBsp.Edges.Address  = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Edges.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Edge>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position   = collisionBsp.Vertices.Address.Offset;
                                collisionBsp.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < collisionBsp.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Vertex>(dataContext));
                                }
                            }

                            foreach (var largeCollisionBsp in resourceDefinition.LargeCollisionBsps)
                            {
                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position          = largeCollisionBsp.Bsp3dNodes.Address.Offset;
                                largeCollisionBsp.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Bsp3dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position      = largeCollisionBsp.Planes.Address.Offset;
                                largeCollisionBsp.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Planes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position      = largeCollisionBsp.Leaves.Address.Offset;
                                largeCollisionBsp.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Leaves.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = largeCollisionBsp.Bsp2dReferences.Address.Offset;
                                largeCollisionBsp.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Bsp2dReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position          = largeCollisionBsp.Bsp2dNodes.Address.Offset;
                                largeCollisionBsp.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position        = largeCollisionBsp.Surfaces.Address.Offset;
                                largeCollisionBsp.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Surfaces.Count; i++)
                                {
                                    var surface = BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Surface>(dataContext);
                                    // surface.Material = PortGlobalMaterialIndex(CacheContext, BlamCache, surface.Material);
                                    CacheContext.Serializer.Serialize(dataContext, surface);
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position     = largeCollisionBsp.Edges.Address.Offset;
                                largeCollisionBsp.Edges.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Edges.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Edge>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position        = largeCollisionBsp.Vertices.Address.Offset;
                                largeCollisionBsp.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < largeCollisionBsp.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.LargeCollisionBspBlock.Vertex>(dataContext));
                                }
                            }

                            foreach (var instance in resourceDefinition.InstancedGeometry)
                            {
                                StreamUtil.Align(dataStream, 0x10); // 0x8 > 0x10
                                blamResourceStream.Position = instance.CollisionInfo.Bsp3dNodes.Address.Offset;
                                instance.CollisionInfo.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Bsp3dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp3dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position           = instance.CollisionInfo.Planes.Address.Offset;
                                instance.CollisionInfo.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Planes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position           = instance.CollisionInfo.Leaves.Address.Offset;
                                instance.CollisionInfo.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Leaves.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = instance.CollisionInfo.Bsp2dReferences.Address.Offset;
                                instance.CollisionInfo.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Bsp2dReferences.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dReference>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position = instance.CollisionInfo.Bsp2dNodes.Address.Offset;
                                instance.CollisionInfo.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Bsp2dNodes.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dNode>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position             = instance.CollisionInfo.Surfaces.Address.Offset;
                                instance.CollisionInfo.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++)
                                {
                                    var surface = BlamCache.Deserializer.Deserialize <CollisionGeometry.Surface>(dataContext);
                                    // surface.Material = PortGlobalMaterialIndex(CacheContext, BlamCache, surface.Material);
                                    CacheContext.Serializer.Serialize(dataContext, surface);
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position          = instance.CollisionInfo.Edges.Address.Offset;
                                instance.CollisionInfo.Edges.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Edges.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Edge>(dataContext));
                                }

                                StreamUtil.Align(dataStream, 0x10);
                                blamResourceStream.Position             = instance.CollisionInfo.Vertices.Address.Offset;
                                instance.CollisionInfo.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Vertex>(dataContext));
                                }

                                foreach (var collisionGeometry in instance.CollisionGeometries)
                                {
                                    StreamUtil.Align(dataStream, 0x10); // 0x8 > 0x10
                                    blamResourceStream.Position          = collisionGeometry.Bsp3dNodes.Address.Offset;
                                    collisionGeometry.Bsp3dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Bsp3dNodes.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp3dNode>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position      = collisionGeometry.Planes.Address.Offset;
                                    collisionGeometry.Planes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Planes.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Plane>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position      = collisionGeometry.Leaves.Address.Offset;
                                    collisionGeometry.Leaves.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Leaves.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Leaf>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position = collisionGeometry.Bsp2dReferences.Address.Offset;
                                    collisionGeometry.Bsp2dReferences.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Bsp2dReferences.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dReference>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position          = collisionGeometry.Bsp2dNodes.Address.Offset;
                                    collisionGeometry.Bsp2dNodes.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Bsp2dNodes.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Bsp2dNode>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position        = collisionGeometry.Surfaces.Address.Offset;
                                    collisionGeometry.Surfaces.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Surfaces.Count; i++)
                                    {
                                        var surface = BlamCache.Deserializer.Deserialize <CollisionGeometry.Surface>(dataContext);
                                        // surface.Material = PortGlobalMaterialIndex(CacheContext, BlamCache, surface.Material);
                                        CacheContext.Serializer.Serialize(dataContext, surface);
                                    }

                                    StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                    blamResourceStream.Position     = collisionGeometry.Edges.Address.Offset;
                                    collisionGeometry.Edges.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Edges.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Edge>(dataContext));
                                    }

                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position        = collisionGeometry.Vertices.Address.Offset;
                                    collisionGeometry.Vertices.Address = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    for (var i = 0; i < collisionGeometry.Vertices.Count; i++)
                                    {
                                        CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <CollisionGeometry.Vertex>(dataContext));
                                    }
                                }

                                foreach (var moppCode in instance.BspPhysics)
                                {
                                    StreamUtil.Align(dataStream, 0x10);
                                    blamResourceStream.Position = moppCode.Data.Address.Offset;
                                    moppCode.Data.Address       = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                    var moppData = resourceReader.ReadBytes(moppCode.Data.Count).Select(i => new CollisionMoppCode.Datum {
                                        Value = i
                                    }).ToList();
                                    if (BlamCache.Version < CacheVersion.Halo3ODST)
                                    {
                                        moppData = ConvertCollisionMoppData(moppData);
                                    }
                                    resourceWriter.Write(moppData.Select(i => i.Value).ToArray());
                                }

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = instance.Unknown1.Address.Offset;
                                instance.Unknown1.Address   = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.Unknown1.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.InstancedGeometryBlock.Unknown1Block>(dataContext));
                                }

                                /*
                                 * StreamUtil.Align(dataStream, 0x4); // 0x4 > 0x10
                                 * blamResourceStream.Position = instance.Unknown2.Address.Offset;
                                 * instance.Unknown2.Address = new CacheAddress(CacheAddressType.Resource, (int)dataStream.Position);
                                 * for (var i = 0; i < instance.Unknown2.Count; i++)
                                 * {
                                 *  var element = BlamCache.Deserializer.Deserialize<StructureBspTagResources.InstancedGeometryBlock.Unknown2Block>(dataContext);
                                 *  if (BlamCache.Version <= CacheVersion.Halo3ODST)
                                 *  {
                                 *      element.Unknown1 = element.Unknown1_H3;
                                 *      element.Unknown2 = element.Unknown2_H3;
                                 *  }
                                 *  CacheContext.Serializer.Serialize(dataContext, element);
                                 */

                                StreamUtil.Align(dataStream, 0x10); // 0x4 > 0x10
                                blamResourceStream.Position = instance.Unknown3.Address.Offset;
                                instance.Unknown3.Address   = new CacheResourceAddress(CacheResourceAddressType.Resource, (int)dataStream.Position);
                                for (var i = 0; i < instance.Unknown3.Count; i++)
                                {
                                    CacheContext.Serializer.Serialize(dataContext, BlamCache.Deserializer.Deserialize <StructureBspTagResources.InstancedGeometryBlock.Unknown3Block>(dataContext));
                                }
                            }

                            dataStream.Position = 0;

                            CacheContext.Serializer.Serialize(new ResourceSerializationContext(CacheContext, bsp.CollisionBspResource), resourceDefinition);

                            bsp.CollisionBspResource.ChangeLocation(ResourceLocation.ResourcesB);
                            var resource = bsp.CollisionBspResource;

                            if (resource == null)
                            {
                                throw new ArgumentNullException("resource");
                            }

                            if (!dataStream.CanRead)
                            {
                                throw new ArgumentException("The input stream is not open for reading", "dataStream");
                            }

                            var cache = CacheContext.GetResourceCache(ResourceLocation.ResourcesB);

                            if (!resourceStreams.ContainsKey(ResourceLocation.ResourcesB))
                            {
                                resourceStreams[ResourceLocation.ResourcesB] = FlagIsSet(PortingFlags.Memory) ?
                                                                               new MemoryStream() :
                                                                               (Stream)CacheContext.OpenResourceCacheReadWrite(ResourceLocation.ResourcesB);

                                if (FlagIsSet(PortingFlags.Memory))
                                {
                                    using (var resourceStream = CacheContext.OpenResourceCacheRead(ResourceLocation.ResourcesB))
                                        resourceStream.CopyTo(resourceStreams[ResourceLocation.ResourcesB]);
                                }
                            }

                            var dataSize = (int)(dataStream.Length - dataStream.Position);
                            var data     = new byte[dataSize];
                            dataStream.Read(data, 0, dataSize);

                            resource.Page.Index = cache.Add(resourceStreams[ResourceLocation.ResourcesB], data, out uint compressedSize);
                            resource.Page.CompressedBlockSize   = compressedSize;
                            resource.Page.UncompressedBlockSize = (uint)dataSize;
                            resource.DisableChecksum();
                        }

            return(bsp.CollisionBspResource);
        }
 public override TagResourceReference CreateStructureBspResource(StructureBspTagResources sbspResource)
 {
     return(CreateResource(sbspResource, ResourceLocation.Resources, TagResourceTypeGen3.Collision));
 }