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
 private PhysicsModel ConvertPhysicsModel(CachedTag instance, PhysicsModel phmo)
 {
     phmo.MoppData = HavokConverter.ConvertHkpMoppData(BlamCache.Version, CacheContext.Version, phmo.MoppData);
     if (BlamCache.Version == CacheVersion.HaloReach)
     {
         foreach (var rigidbody in phmo.RigidBodies)
         {
             rigidbody.MotionType = rigidbody.MotionType_Reach;
             rigidbody.ShapeType  = rigidbody.ShapeType_Reach;
             rigidbody.ShapeIndex = rigidbody.ShapeIndex_Reach;
             rigidbody.Mass       = rigidbody.Mass_Reach;
         }
     }
     return(phmo);
 }
예제 #3
0
        /// <summary>
        /// Converts RenderGeometry class in place and returns a new RenderGeometryApiResourceDefinition
        /// </summary>
        public RenderGeometryApiResourceDefinition Convert(RenderGeometry geometry, RenderGeometryApiResourceDefinition resourceDefinition)
        {
            //
            // Convert byte[] of UnknownBlock
            //

            foreach (var block in geometry.Unknown2)
            {
                var data = block.Unknown3;
                if (data != null || data.Length != 0)
                {
                    var result = new byte[data.Length];

                    using (var inputReader = new EndianReader(new MemoryStream(data), SourceCache.Endianness))
                        using (var outputWriter = new EndianWriter(new MemoryStream(result), HOCache.Endianness))
                        {
                            while (!inputReader.EOF)
                            {
                                outputWriter.Write(inputReader.ReadUInt32());
                            }

                            block.Unknown3 = result;
                        }
                }
            }

            //
            // Convert mopps in cluster visibility
            //

            foreach (var clusterVisibility in geometry.MeshClusterVisibility)
            {
                clusterVisibility.MoppData = HavokConverter.ConvertHkpMoppData(SourceCache.Version, HOCache.Version, clusterVisibility.MoppData);
            }

            //
            // Port resource definition
            //

            var wasNull = false;

            if (resourceDefinition == null)
            {
                wasNull = true;
                Console.Error.WriteLine("Render geometry does not have a valid resource definition, continuing anyway.");
                resourceDefinition = new RenderGeometryApiResourceDefinition
                {
                    VertexBuffers = new TagBlock <D3DStructure <VertexBufferDefinition> >(CacheAddressType.Definition),
                    IndexBuffers  = new TagBlock <D3DStructure <IndexBufferDefinition> >(CacheAddressType.Definition)
                };
            }

            geometry.SetResourceBuffers(resourceDefinition);

            // do conversion (PARTICLE INDEX BUFFERS, WATER CONVERSION TO DO) AMBIENT PRT TOO

            var generateParticles = false; // temp fix when pmdf geo is null

            if (wasNull)
            {
                if (geometry.Meshes.Count == 1 && geometry.Meshes[0].Type == VertexType.ParticleModel)
                {
                    generateParticles = true;
                }
                else
                {
                    geometry.Resource = HOCache.ResourceCache.CreateRenderGeometryApiResource(resourceDefinition);
                    geometry.Resource.HaloOnlinePageableResource.Resource.ResourceType = TagResourceTypeGen3.None;
                    return(resourceDefinition);
                }
            }

            //
            // Convert Blam data to ElDorado data
            //

            if (generateParticles)
            {
                var mesh = geometry.Meshes[0];
                mesh.Flags  |= MeshFlags.MeshIsUnindexed;
                mesh.PrtType = PrtSHType.None;

                var newVertexBuffer = new VertexBufferDefinition
                {
                    Format     = VertexBufferFormat.ParticleModel,
                    VertexSize = (short)VertexStreamFactory.Create(HOCache.Version, null).GetVertexSize(VertexBufferFormat.ParticleModel),
                    Data       = new TagData
                    {
                        Data        = new byte[32],
                        AddressType = CacheAddressType.Data
                    }
                };
                mesh.ResourceVertexBuffers[0] = newVertexBuffer;
            }
            else
            {
                foreach (var mesh in geometry.Meshes)
                {
                    foreach (var vertexBuffer in mesh.ResourceVertexBuffers)
                    {
                        if (vertexBuffer == null)
                        {
                            continue;
                        }

                        // Gen3 order 0 coefficients are stored in ints but should be read as bytes, 1 per vertex in the original buffer
                        if (vertexBuffer.Format == VertexBufferFormat.AmbientPrt)
                        {
                            vertexBuffer.Count = mesh.ResourceVertexBuffers[0].Count;
                        }

                        // skip conversion of water vertices, done right after the loop
                        if (vertexBuffer.Format == VertexBufferFormat.Unknown1A || vertexBuffer.Format == VertexBufferFormat.Unknown1B)
                        {
                            continue;
                        }

                        VertexBufferConverter.ConvertVertexBuffer(SourceCache.Version, HOCache.Version, vertexBuffer);
                    }

                    // convert water vertex buffers
                    if (mesh.ResourceVertexBuffers[6] != null && mesh.ResourceVertexBuffers[7] != null)
                    {
                        // Get total amount of indices and prepare for water conversion

                        int indexCount = 0;
                        foreach (var subpart in mesh.SubParts)
                        {
                            indexCount += subpart.IndexCount;
                        }

                        WaterConversionData waterData = new WaterConversionData();

                        for (int j = 0; j < mesh.Parts.Count(); j++)
                        {
                            var part = mesh.Parts[j];
                            if (part.FlagsNew.HasFlag(Mesh.Part.PartFlagsNew.IsWaterPart))
                            {
                                waterData.PartData.Add(new Tuple <int, int>(part.FirstIndexOld, part.IndexCountOld));
                            }
                        }

                        if (waterData.PartData.Count > 1)
                        {
                            waterData.Sort();
                        }

                        // read all world vertices, unknown1A and unknown1B into lists.
                        List <WorldVertex> worldVertices     = new List <WorldVertex>();
                        List <Unknown1B>   h3WaterParameters = new List <Unknown1B>();
                        List <Unknown1A>   h3WaterIndices    = new List <Unknown1A>();

                        using (var stream = new MemoryStream(mesh.ResourceVertexBuffers[0].Data.Data))
                        {
                            var vertexStream = VertexStreamFactory.Create(HOCache.Version, stream);
                            for (int v = 0; v < mesh.ResourceVertexBuffers[0].Count; v++)
                            {
                                worldVertices.Add(vertexStream.ReadWorldVertex());
                            }
                        }
                        using (var stream = new MemoryStream(mesh.ResourceVertexBuffers[6].Data.Data))
                        {
                            var vertexStream = VertexStreamFactory.Create(SourceCache.Version, stream);
                            for (int v = 0; v < mesh.ResourceVertexBuffers[6].Count; v++)
                            {
                                h3WaterIndices.Add(vertexStream.ReadUnknown1A());
                            }
                        }
                        using (var stream = new MemoryStream(mesh.ResourceVertexBuffers[7].Data.Data))
                        {
                            var vertexStream = VertexStreamFactory.Create(SourceCache.Version, stream);
                            for (int v = 0; v < mesh.ResourceVertexBuffers[7].Count; v++)
                            {
                                h3WaterParameters.Add(vertexStream.ReadUnknown1B());
                            }
                        }

                        // create vertex buffer for Unknown1A -> World
                        VertexBufferDefinition waterVertices = new VertexBufferDefinition
                        {
                            Count      = indexCount,
                            Format     = VertexBufferFormat.World,
                            Data       = new TagData(),
                            VertexSize = 0x38   // this size is actually wrong but I replicate the errors in HO data, size should be 0x34
                        };

                        // create vertex buffer for Unknown1B
                        VertexBufferDefinition waterParameters = new VertexBufferDefinition
                        {
                            Count      = indexCount,
                            Format     = VertexBufferFormat.Unknown1B,
                            Data       = new TagData(),
                            VertexSize = 0x24   // wrong size, this is 0x18 on file, padded with zeroes.
                        };

                        using (var outputWorldWaterStream = new MemoryStream())
                            using (var outputWaterParametersStream = new MemoryStream())
                            {
                                var outWorldVertexStream          = VertexStreamFactory.Create(HOCache.Version, outputWorldWaterStream);
                                var outWaterParameterVertexStream = VertexStreamFactory.Create(HOCache.Version, outputWaterParametersStream);

                                // fill vertex buffer to the right size HO expects, then write the vertex data at the actual proper position
                                VertexBufferConverter.DebugFill(outputWorldWaterStream, waterVertices.VertexSize * waterVertices.Count);
                                VertexBufferConverter.Fill(outputWaterParametersStream, waterParameters.VertexSize * waterParameters.Count);

                                var unknown1ABaseIndex = 0; // unknown1A are not separated into parts, if a mesh has multiple parts we need to get the right unknown1As

                                for (int k = 0; k < waterData.PartData.Count(); k++)
                                {
                                    Tuple <int, int> currentPartData = waterData.PartData[k];

                                    //seek to the right location in the buffer
                                    outputWorldWaterStream.Position      = 0x34 * currentPartData.Item1;
                                    outputWaterParametersStream.Position = 0x18 * currentPartData.Item1;

                                    for (int v = 0; v < currentPartData.Item2; v += 3)
                                    {
                                        var unknown1A = h3WaterIndices[(v / 3) + unknown1ABaseIndex];
                                        for (int j = 0; j < 3; j++)
                                        {
                                            var worldVertex = worldVertices[unknown1A.Vertices[j]];
                                            var unknown1B   = h3WaterParameters[unknown1A.Indices[j]];

                                            // conversion should happen here

                                            outWorldVertexStream.WriteWorldWaterVertex(worldVertex);
                                            outWaterParameterVertexStream.WriteUnknown1B(unknown1B);
                                        }
                                    }
                                    unknown1ABaseIndex += currentPartData.Item2 / 3; // tells next part we read those indices already
                                }
                                waterVertices.Data.Data   = outputWorldWaterStream.ToArray();
                                waterParameters.Data.Data = outputWaterParametersStream.ToArray();
                            }

                        mesh.ResourceVertexBuffers[6] = waterVertices;
                        mesh.ResourceVertexBuffers[7] = waterParameters;
                    }

                    foreach (var indexBuffer in mesh.ResourceIndexBuffers)
                    {
                        if (indexBuffer == null)
                        {
                            continue;
                        }

                        IndexBufferConverter.ConvertIndexBuffer(SourceCache.Version, HOCache.Version, indexBuffer);
                    }

                    // create index buffers for decorators, gen3 didn't have them
                    if (mesh.Flags.HasFlag(MeshFlags.MeshIsUnindexed) && mesh.Type == VertexType.Decorator)
                    {
                        mesh.Flags &= ~MeshFlags.MeshIsUnindexed;

                        var indexCount = 0;

                        foreach (var part in mesh.Parts)
                        {
                            indexCount += part.IndexCountOld;
                        }

                        mesh.ResourceIndexBuffers[0] = IndexBufferConverter.CreateIndexBuffer(indexCount);
                    }
                }
            }

            foreach (var perPixel in geometry.InstancedGeometryPerPixelLighting)
            {
                if (perPixel.VertexBuffer != null)
                {
                    VertexBufferConverter.ConvertVertexBuffer(SourceCache.Version, HOCache.Version, perPixel.VertexBuffer);
                }
            }

            return(geometry.GetResourceDefinition());
        }