Beispiel #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MeshReader"/> class.
 /// </summary>
 /// <param name="version">The engine version to target.</param>
 /// <param name="mesh">The mesh.</param>
 public MeshReader(CacheVersion version, Mesh mesh)
 {
     _version      = version;
     Mesh          = mesh;
     VertexStreams = new VertexBufferDefinition[StreamCount];
     IndexBuffers  = new IndexBufferDefinition[IndexBufferCount];
     BindVertexStreams();
     BindIndexBuffers();
 }
Beispiel #2
0
 /// <summary>
 /// Opens a vertex stream on one of the mesh's vertex buffers.
 /// </summary>
 /// <param name="definition">The vertex buffer definition.</param>
 /// <param name="baseStream">The stream open on the mesh's resource data to use as a base stream.</param>
 /// <returns>The vertex stream if successful, or <c>null</c> otherwise.</returns>
 public IVertexStream OpenVertexStream(VertexBufferDefinition definition, Stream baseStream)
 {
     if (definition.Data.Address.Type != ResourceAddressType.Resource)
     {
         return(null); // Don't bother supporting non-resource addresses
     }
     baseStream.Position = definition.Data.Address.Offset;
     return(VertexStreamFactory.Create(_version, baseStream));
 }
Beispiel #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MeshReader"/> class.
 /// </summary>
 /// <param name="version">The engine version to target.</param>
 /// <param name="mesh">The mesh.</param>
 /// <param name="definition">The mesh's definition data.</param>
 public MeshReader(DefinitionSet version, Mesh mesh, RenderGeometryResourceDefinition definition)
 {
     _version      = version;
     Mesh          = mesh;
     Definition    = definition;
     VertexStreams = new VertexBufferDefinition[StreamCount];
     IndexBuffers  = new IndexBufferDefinition[IndexBufferCount];
     BindVertexStreams();
     BindIndexBuffers();
 }
Beispiel #4
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());
        }
Beispiel #5
0
        /// <summary>
        /// Opens a vertex stream on one of the mesh's vertex buffers.
        /// </summary>
        /// <param name="definition">The vertex buffer definition.</param>
        /// <returns>The vertex stream if successful, or <c>null</c> otherwise.</returns>
        public IVertexStream OpenVertexStream(VertexBufferDefinition definition)
        {
            var stream = new MemoryStream(definition.Data.Data);

            return(VertexStreamFactory.Create(_version, stream));
        }
Beispiel #6
0
        public static void ConvertVertexBuffer(CacheVersion inVersion, CacheVersion outVersion, VertexBufferDefinition vertexBuffer)
        {
            using (var outputStream = new MemoryStream())
                using (var inputStream = new MemoryStream(vertexBuffer.Data.Data))
                {
                    var inVertexStream  = VertexStreamFactory.Create(inVersion, inputStream);
                    var outVertexStream = VertexStreamFactory.Create(outVersion, outputStream);
                    var count           = vertexBuffer.Count;

                    switch (vertexBuffer.Format)
                    {
                    case VertexBufferFormat.World:
                        ConvertVertices(count, inVertexStream.ReadWorldVertex, (v, i) =>
                        {
                            v.Normal   = ConvertVectorSpace(v.Normal);
                            v.Tangent  = ConvertVectorSpace(v.Tangent);
                            v.Binormal = ConvertVectorSpace(v.Binormal);
                            outVertexStream.WriteWorldVertex(v);
                        });
                        break;

                    case VertexBufferFormat.Rigid:
                        ConvertVertices(count, inVertexStream.ReadRigidVertex, (v, i) =>
                        {
                            v.Normal   = ConvertVectorSpace(v.Normal);
                            v.Tangent  = ConvertVectorSpace(v.Tangent);
                            v.Binormal = ConvertVectorSpace(v.Binormal);
                            outVertexStream.WriteRigidVertex(v);
                        });
                        break;

                    case VertexBufferFormat.Skinned:
                        ConvertVertices(count, inVertexStream.ReadSkinnedVertex, (v, i) =>
                        {
                            v.Normal   = ConvertVectorSpace(v.Normal);
                            v.Tangent  = ConvertVectorSpace(v.Tangent);
                            v.Binormal = ConvertVectorSpace(v.Binormal);
                            outVertexStream.WriteSkinnedVertex(v);
                        });
                        break;

                    case VertexBufferFormat.StaticPerPixel:
                        ConvertVertices(count, inVertexStream.ReadStaticPerPixelData, (v, i) => outVertexStream.WriteStaticPerPixelData(v));
                        break;

                    case VertexBufferFormat.StaticPerVertex:
                        ConvertVertices(count, inVertexStream.ReadStaticPerVertexData, (v, i) =>
                        {
                            v.Color1 = ConvertColorSpace(v.Color1);
                            v.Color2 = ConvertColorSpace(v.Color2);
                            v.Color3 = ConvertColorSpace(v.Color3);
                            v.Color4 = ConvertColorSpace(v.Color4);
                            v.Color5 = ConvertColorSpace(v.Color5);
                            outVertexStream.WriteStaticPerVertexData(v);
                        });
                        break;

                    // assume count has been fixed up before this
                    case VertexBufferFormat.AmbientPrt:
                        ConvertVertices(count, inVertexStream.ReadAmbientPrtData, (v, i) => outVertexStream.WriteAmbientPrtData(v));
                        break;

                    case VertexBufferFormat.LinearPrt:
                        ConvertVertices(count, inVertexStream.ReadLinearPrtData, (v, i) =>
                        {
                            v.SHCoefficients = ConvertNormal(v.SHCoefficients);
                            outVertexStream.WriteLinearPrtData(v);
                        });
                        break;

                    case VertexBufferFormat.QuadraticPrt:
                        ConvertVertices(count, inVertexStream.ReadQuadraticPrtData, (v, i) => outVertexStream.WriteQuadraticPrtData(v));
                        break;

                    case VertexBufferFormat.StaticPerVertexColor:
                        ConvertVertices(count, inVertexStream.ReadStaticPerVertexColorData, (v, i) => outVertexStream.WriteStaticPerVertexColorData(v));
                        break;

                    case VertexBufferFormat.Decorator:
                        ConvertVertices(count, inVertexStream.ReadDecoratorVertex, (v, i) =>
                        {
                            v.Normal = ConvertVectorSpace(v.Normal);
                            outVertexStream.WriteDecoratorVertex(v);
                        });
                        break;

                    case VertexBufferFormat.World2:
                        vertexBuffer.Format = VertexBufferFormat.World;
                        goto case VertexBufferFormat.World;

                    /*
                     * case VertexBufferFormat.Unknown1A:
                     *
                     * var waterData = WaterData[CurrentWaterBuffer];
                     *
                     * // Reformat Vertex Buffer
                     * vertexBuffer.Format = VertexBufferFormat.World;
                     * vertexBuffer.VertexSize = 0x34;
                     * vertexBuffer.Count = waterData.IndexBufferLength;
                     *
                     * // Create list of indices for later use.
                     * Unknown1BIndices = new List<ushort>();
                     *
                     * for (int k = 0; k < waterData.PartData.Count(); k++)
                     * {
                     *  Tuple<int, int, bool> currentPartData = waterData.PartData[k];
                     *
                     *  // Not water, add garbage data
                     *  if (currentPartData.Item3 == false)
                     *  {
                     *      for (int j = 0; j < currentPartData.Item2; j++)
                     *          WriteUnusedWorldWaterData(outputStream);
                     *  }
                     *  else
                     *  {
                     *      ConvertVertices(currentPartData.Item2 / 3, inVertexStream.ReadUnknown1A, (v, i) =>
                     *      {
                     *          // Store current stream position
                     *          var tempStreamPosition = inputStream.Position;
                     *
                     *          // Open previous world buffer (H3)
                     *          var worldVertexBufferBasePosition = OriginalBufferOffsets[OriginalBufferOffsets.Count() - 3];
                     *          inputStream.Position = worldVertexBufferBasePosition;
                     *
                     *          for (int j = 0; j < 3; j++)
                     *          {
                     *              inputStream.Position = 0x20 * v.Vertices[j] + worldVertexBufferBasePosition;
                     *
                     *              WorldVertex w = inVertexStream.ReadWorldVertex();
                     *
                     *              Unknown1BIndices.Add(v.Indices[j]);
                     *
                     *              // The last 2 floats in WorldWater are unknown.
                     *
                     *              outVertexStream.WriteWorldWaterVertex(w);
                     *          }
                     *
                     *          // Restore position for reading the next vertex correctly
                     *          inputStream.Position = tempStreamPosition;
                     *      });
                     *  }
                     * }
                     * break;
                     *
                     * case VertexBufferFormat.Unknown1B:
                     *
                     * var waterDataB = WaterData[CurrentWaterBuffer];
                     *
                     * // Adjust vertex size to match HO. Set count of vertices
                     *
                     * vertexBuffer.VertexSize = 0x18;
                     *
                     * var originalCount = vertexBuffer.Count;
                     * vertexBuffer.Count = waterDataB.IndexBufferLength;
                     *
                     * var basePosition = inputStream.Position;
                     * var unknown1BPosition = 0;
                     *
                     * for (int k = 0; k < waterDataB.PartData.Count(); k++)
                     * {
                     *  Tuple<int, int, bool> currentPartData = waterDataB.PartData[k];
                     *
                     *  // Not water, add garbage data
                     *  if (currentPartData.Item3 == false)
                     *  {
                     *      for (int j = 0; j < currentPartData.Item2; j++)
                     *          WriteUnusedUnknown1BData(outputStream);
                     *  }
                     *  else
                     *  {
                     *      for (int j = unknown1BPosition; j < Unknown1BIndices.Count() && j - unknown1BPosition < currentPartData.Item2; j++)
                     *      {
                     *          inputStream.Position = basePosition + 0x24 * Unknown1BIndices[j];
                     *          ConvertVertices(1, inVertexStream.ReadUnknown1B, (v, i) => outVertexStream.WriteUnknown1B(v));
                     *          unknown1BPosition++;
                     *      }
                     *  }
                     * }
                     *
                     * // Get to the end of Unknown1B in H3 data
                     * inputStream.Position = basePosition + originalCount * 0x24;
                     *
                     * CurrentWaterBuffer++;
                     *
                     * break;
                     */
                    case VertexBufferFormat.ParticleModel:
                        ConvertVertices(count, inVertexStream.ReadParticleModelVertex, (v, i) =>
                        {
                            v.Normal = ConvertVectorSpace(v.Normal);
                            outVertexStream.WriteParticleModelVertex(v);
                        });
                        break;

                    case VertexBufferFormat.TinyPosition:
                        ConvertVertices(count, inVertexStream.ReadTinyPositionVertex, (v, i) =>
                        {
                            v.Position = ConvertPositionShort(v.Position);
                            v.Variant  = (ushort)((v.Variant >> 8) & 0xFF);
                            v.Normal   = ConvertNormal(v.Normal);
                            outVertexStream.WriteTinyPositionVertex(v);
                        });
                        break;

                    default:
                        throw new NotSupportedException(vertexBuffer.Format.ToString());
                    }

                    // set proper size of vertices
                    vertexBuffer.VertexSize = (short)outVertexStream.GetVertexSize(vertexBuffer.Format);
                    // set data
                    vertexBuffer.Data.Data = outputStream.ToArray();
                }
        }