示例#1
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));
 }
示例#2
0
        private int SerializeVertexBuffer(MeshData mesh, Stream outStream)
        {
            var vertexStream = VertexStreamFactory.Create(_version, outStream);

            if (mesh.RigidVertices != null)
            {
                foreach (var v in mesh.RigidVertices)
                {
                    vertexStream.WriteRigidVertex(v);
                }
                return(mesh.RigidVertices.Length);
            }
            if (mesh.SkinnedVertices != null)
            {
                foreach (var v in mesh.SkinnedVertices)
                {
                    vertexStream.WriteSkinnedVertex(v);
                }
                return(mesh.SkinnedVertices.Length);
            }
            return(0);
        }
        public void ConvertVertexBuffer(RenderGeometryApiResourceDefinition resourceDefinition, Stream inputStream, Stream outputStream, int vertexBufferIndex, int previousVertexBufferCount)
        {
            var vertexBuffer = resourceDefinition.VertexBuffers[vertexBufferIndex].Definition;
            var count        = vertexBuffer.Count;

            var startPos = (int)outputStream.Position;

            vertexBuffer.Data.Address = new CacheAddress(CacheAddressType.Resource, startPos);

            var inVertexStream  = VertexStreamFactory.Create(BlamCache.Version, inputStream);
            var outVertexStream = VertexStreamFactory.Create(CacheContext.Version, outputStream);

            OriginalBufferOffsets.Add(inputStream.Position);

            switch (vertexBuffer.Format)
            {
            case VertexBufferFormat.World:
                ConvertVertices(count, inVertexStream.ReadWorldVertex, (v, i) =>
                {
                    //v.Tangent = new RealQuaternion(-Math.Abs(v.Tangent.I), -Math.Abs(v.Tangent.J), Math.Abs(v.Tangent.K), Math.Abs(v.Tangent.W)); // great results for H3 armors
                    outVertexStream.WriteWorldVertex(v);
                });
                break;

            case VertexBufferFormat.Rigid:
                ConvertVertices(count, inVertexStream.ReadRigidVertex, (v, i) =>
                {
                    //v.Tangent = new RealQuaternion(-Math.Abs(v.Tangent.I), -Math.Abs(v.Tangent.J), Math.Abs(v.Tangent.K), Math.Abs(v.Tangent.W)); // great results for H3 armors
                    outVertexStream.WriteRigidVertex(v);
                });
                break;

            case VertexBufferFormat.Skinned:
                ConvertVertices(count, inVertexStream.ReadSkinnedVertex, (v, i) =>
                {
                    //v.Tangent = new RealQuaternion(-Math.Abs(v.Tangent.I), -Math.Abs(v.Tangent.J), Math.Abs(v.Tangent.K), Math.Abs(v.Tangent.W)); // great results for H3 armors
                    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.Texcoord1 = ConvertNormal(v.Texcoord1);
                    v.Texcoord2 = ConvertNormal(v.Texcoord2);
                    v.Texcoord3 = ConvertNormal(v.Texcoord3);
                    v.Texcoord4 = ConvertNormal(v.Texcoord4);
                    v.Texcoord5 = ConvertNormal(v.Texcoord5);
                    outVertexStream.WriteStaticPerVertexData(v);
                });
                break;

            case VertexBufferFormat.AmbientPrt:
                ConvertVertices(vertexBuffer.Count = previousVertexBufferCount, inVertexStream.ReadAmbientPrtData, (v, i) => outVertexStream.WriteAmbientPrtData(v));
                break;

            case VertexBufferFormat.LinearPrt:
                ConvertVertices(count, inVertexStream.ReadLinearPrtData, (v, i) =>
                {
                    v.BlendWeight = ConvertNormal(v.BlendWeight);
                    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) => 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) => 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());
            }

            vertexBuffer.Data.Size  = (int)outputStream.Position - startPos;
            vertexBuffer.VertexSize = (short)(vertexBuffer.Data.Size / vertexBuffer.Count);

            resourceDefinition.VertexBuffers[vertexBufferIndex].DefinitionAddress = 0;
            resourceDefinition.VertexBuffers[vertexBufferIndex].RuntimeAddress    = 0;
        }
        public RenderGeometry Convert(Stream cacheStream, RenderGeometry geometry, Dictionary <ResourceLocation, Stream> resourceStreams, PortTagCommand.PortingFlags portingFlags)
        {
            if (BlamCache.ResourceGestalt == null || BlamCache.ResourceLayoutTable == null)
            {
                BlamCache.LoadResourceTags();
            }

            //
            // 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), EndianFormat.BigEndian))
                        using (var outputWriter = new EndianWriter(new MemoryStream(result), EndianFormat.LittleEndian))
                        {
                            while (!inputReader.EOF)
                            {
                                outputWriter.Write(inputReader.ReadUInt32());
                            }

                            block.Unknown3 = result;
                        }
                }
            }

            //
            // Convert UnknownSection.Unknown byte[] endian
            //

            for (int i = 0; i < geometry.UnknownSections.Count; i++)
            {
                byte[] dataref = geometry.UnknownSections[i].Unknown;

                if (dataref.Length == 0)
                {
                    continue;
                }

                using (var outStream = new MemoryStream())
                    using (var outReader = new BinaryReader(outStream))
                        using (var outWriter = new EndianWriter(outStream, EndianFormat.LittleEndian))
                            using (var stream = new MemoryStream(dataref))
                                using (var reader = new EndianReader(stream, EndianFormat.BigEndian))
                                {
                                    var dataContext = new DataSerializationContext(reader, outWriter);
                                    var header      = CacheContext.Deserializer.Deserialize <ScenarioLightmapBspDataSection.Header>(dataContext);

                                    var section = new ScenarioLightmapBspDataSection
                                    {
                                        Headers = new List <ScenarioLightmapBspDataSection.Header>
                                        {
                                            header
                                        },
                                        VertexLists = new ScenarioLightmapBspDataSection.VertexList
                                        {
                                            Vertex = new List <ScenarioLightmapBspDataSection.VertexList.Datum>()
                                        }
                                    };

                                    CacheContext.Serializer.Serialize(dataContext, header);

                                    while (reader.BaseStream.Position < dataref.Length) // read the rest of dataref
                                    {
                                        if (section.Headers.Count == 2)                 // remove "wrongfully" added ones
                                        {
                                            section.Headers.RemoveAt(1);
                                        }

                                        section.Headers.Add(CacheContext.Deserializer.Deserialize <ScenarioLightmapBspDataSection.Header>(dataContext));

                                        // if some values match header1, continue
                                        if (section.Headers[0].Position == section.Headers[1].Position)
                                        {
                                            header = section.Headers[1];
                                            CacheContext.Serializer.Serialize(dataContext, header);

                                            while (reader.BaseStream.Position < dataref.Length)
                                            {
                                                section.VertexLists.Vertex.Add(new ScenarioLightmapBspDataSection.VertexList.Datum {
                                                    Value = reader.ReadByte()
                                                });
                                                outWriter.Write(section.VertexLists.Vertex[section.VertexLists.Vertex.Count - 1].Value);
                                            }
                                        }
                                        else // if read data doesn't match, go back and just read 4 bytes
                                        {
                                            reader.BaseStream.Position = reader.BaseStream.Position - 0x2C; // if read data doesn't match, go back and serialize

                                            section.VertexLists.Vertex.Add(new ScenarioLightmapBspDataSection.VertexList.Datum {
                                                Value = reader.ReadByte()
                                            });
                                            outWriter.Write(section.VertexLists.Vertex[section.VertexLists.Vertex.Count - 1].Value);

                                            section.VertexLists.Vertex.Add(new ScenarioLightmapBspDataSection.VertexList.Datum {
                                                Value = reader.ReadByte()
                                            });
                                            outWriter.Write(section.VertexLists.Vertex[section.VertexLists.Vertex.Count - 1].Value);

                                            section.VertexLists.Vertex.Add(new ScenarioLightmapBspDataSection.VertexList.Datum {
                                                Value = reader.ReadByte()
                                            });
                                            outWriter.Write(section.VertexLists.Vertex[section.VertexLists.Vertex.Count - 1].Value);

                                            section.VertexLists.Vertex.Add(new ScenarioLightmapBspDataSection.VertexList.Datum {
                                                Value = reader.ReadByte()
                                            });
                                            outWriter.Write(section.VertexLists.Vertex[section.VertexLists.Vertex.Count - 1].Value);
                                        }
                                    }

                                    // Write back to tag
                                    outStream.Position = 0;
                                    geometry.UnknownSections[i].Unknown = outStream.ToArray();
                                }
            }

            //
            // Set up ElDorado resource reference
            //

            geometry.Resource = new PageableResource
            {
                Page = new RawPage
                {
                    Index = -1
                },
                Resource = new TagResourceGen3
                {
                    ResourceType             = TagResourceTypeGen3.RenderGeometry,
                    DefinitionData           = new byte[0x30],
                    DefinitionAddress        = new CacheAddress(CacheAddressType.Definition, 0),
                    ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                    ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                    Unknown2 = 1
                }
            };

            //
            // Port Blam resource definition
            //

            var resourceEntry = BlamCache.ResourceGestalt.TagResources[geometry.ZoneAssetHandle & ushort.MaxValue];

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

            RenderGeometryApiResourceDefinition resourceDefinition = null;

            if (geometry.Resource.Resource.DefinitionData.Length < 0x30)
            {
                resourceDefinition = new RenderGeometryApiResourceDefinition
                {
                    VertexBuffers = new List <TagStructureReference <VertexBufferDefinition> >(),
                    IndexBuffers  = new List <TagStructureReference <IndexBufferDefinition> >()
                };
            }
            else
            {
                using (var definitionStream = new MemoryStream(geometry.Resource.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)
                            {
                                definitionStream.Position = fixup.BlockOffset;
                                definitionWriter.Write(fixup.Address.Value);

                                geometry.Resource.Resource.ResourceFixups.Add(fixup);
                            }

                            foreach (var definitionFixup in resourceEntry.ResourceDefinitionFixups)
                            {
                                var newDefinitionFixup = new TagResourceGen3.ResourceDefinitionFixup
                                {
                                    Address = definitionFixup.Address,
                                    ResourceStructureTypeIndex = definitionFixup.ResourceStructureTypeIndex
                                };

                                geometry.Resource.Resource.ResourceDefinitionFixups.Add(newDefinitionFixup);
                            }

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

                            definitionStream.Position = geometry.Resource.Resource.DefinitionAddress.Offset;
                            resourceDefinition        = BlamCache.Deserializer.Deserialize <RenderGeometryApiResourceDefinition>(dataContext);
                        }
            }

            //
            // Load Blam resource data
            //

            var resourceData      = BlamCache.GetRawFromID(geometry.ZoneAssetHandle);
            var generateParticles = false;

            if (resourceData == null)
            {
                if (geometry.Meshes.Count == 1 && geometry.Meshes[0].Type == VertexType.ParticleModel)
                {
                    generateParticles = true;
                    resourceData      = new byte[0];
                }
                else
                {
                    geometry.Resource.Resource.ResourceType = TagResourceTypeGen3.None;
                    return(geometry);
                }
            }

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

            using (var dataStream = new MemoryStream())
                using (var blamResourceStream = new MemoryStream(resourceData))
                {
                    for (int i = 0; i < geometry.Meshes.Count(); i++)
                    {
                        var mesh = geometry.Meshes[i];

                        if (mesh.VertexBufferIndices[6] != 0xFFFF && mesh.VertexBufferIndices[7] != 0xFFFF)
                        {
                            ushort temp = mesh.VertexBufferIndices[6];
                            mesh.VertexBufferIndices[6] = mesh.VertexBufferIndices[7];
                            mesh.VertexBufferIndices[7] = temp;

                            // Get total amount of indices

                            int indexCount = 0;

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

                            WaterConversionData waterData = new WaterConversionData()
                            {
                                IndexBufferLength = indexCount,
                            };

                            for (int j = 0; j < mesh.Parts.Count(); j++)
                            {
                                var part = mesh.Parts[j];
                                waterData.PartData.Add(new Tuple <int, int, bool>(part.FirstIndex, part.IndexCount, part.FlagsNew.HasFlag(Mesh.Part.PartFlagsNew.CanBeRenderedInDrawBundles)));
                            }
                            waterData.Sort();
                            WaterData.Add(waterData);
                        }
                    }

                    if (generateParticles)
                    {
                        var outVertexStream = VertexStreamFactory.Create(CacheContext.Version, dataStream);

                        StreamUtil.Align(dataStream, 4);

                        resourceDefinition.VertexBuffers.Add(new TagStructureReference <VertexBufferDefinition>
                        {
                            Definition = new VertexBufferDefinition
                            {
                                Format = VertexBufferFormat.ParticleModel,
                                Data   = new TagData
                                {
                                    Size     = 32,
                                    Unused4  = 0,
                                    Unused8  = 0,
                                    Address  = new CacheAddress(CacheAddressType.Resource, (int)dataStream.Position),
                                    Unused10 = 0
                                }
                            }
                        });

                        var vertexBuffer = resourceDefinition.VertexBuffers.Last().Definition;

                        for (var j = 0; j < 3; j++)
                        {
                            outVertexStream.WriteParticleModelVertex(new ParticleModelVertex
                            {
                                Position = new RealVector3d(),
                                Texcoord = new RealVector2d(),
                                Normal   = new RealVector3d()
                            });
                        }

                        geometry.Meshes[0].VertexBufferIndices[0] = (ushort)resourceDefinition.VertexBuffers.IndexOf(resourceDefinition.VertexBuffers.Last());
                        geometry.Meshes[0].IndexBufferIndices[0]  = CreateIndexBuffer(resourceDefinition, dataStream, 3);
                    }
                    else
                    {
                        for (int i = 0, prevVertCount = -1; i < resourceDefinition.VertexBuffers.Count; i++, prevVertCount = resourceDefinition.VertexBuffers[i - 1].Definition.Count)
                        {
                            blamResourceStream.Position = resourceDefinition.VertexBuffers[i].Definition.Data.Address.Offset; // resourceEntry.ResourceFixups[i].Offset;
                            ConvertVertexBuffer(resourceDefinition, blamResourceStream, dataStream, i, prevVertCount);
                        }

                        for (var i = 0; i < resourceDefinition.IndexBuffers.Count; i++)
                        {
                            blamResourceStream.Position = resourceDefinition.IndexBuffers[i].Definition.Data.Address.Offset; // resourceEntry.ResourceFixups[resourceDefinition.VertexBuffers.Count * 2 + i].Offset;
                            ConvertIndexBuffer(resourceDefinition, blamResourceStream, dataStream, i);
                        }

                        foreach (var mesh in geometry.Meshes)
                        {
                            if (!mesh.Flags.HasFlag(MeshFlags.MeshIsUnindexed))
                            {
                                continue;
                            }

                            var indexCount = 0;

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

                            mesh.IndexBufferIndices[0] = CreateIndexBuffer(resourceDefinition, dataStream, indexCount);
                        }
                    }

                    //
                    // Swap order of water vertex buffers
                    //

                    for (var i = 0; i < resourceDefinition.VertexBuffers.Count; i++)
                    {
                        var vertexBuffer = resourceDefinition.VertexBuffers[i];

                        if (vertexBuffer.Definition.Format == VertexBufferFormat.Unknown1B)
                        {
                            TagStructureReference <VertexBufferDefinition> temp = vertexBuffer;
                            resourceDefinition.VertexBuffers[i]     = resourceDefinition.VertexBuffers[i - 1];
                            resourceDefinition.VertexBuffers[i - 1] = temp;
                        }
                    }

                    //
                    // Finalize the new ElDorado geometry resource
                    //

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

                    if (!resourceStreams.ContainsKey(ResourceLocation.Resources))
                    {
                        resourceStreams[ResourceLocation.Resources] = portingFlags.HasFlag(PortTagCommand.PortingFlags.Memory) ?
                                                                      new MemoryStream() :
                                                                      (Stream)CacheContext.OpenResourceCacheReadWrite(ResourceLocation.Resources);

                        if (portingFlags.HasFlag(PortTagCommand.PortingFlags.Memory))
                        {
                            using (var resourceStream = CacheContext.OpenResourceCacheRead(ResourceLocation.Resources))
                                resourceStream.CopyTo(resourceStreams[ResourceLocation.Resources]);
                        }
                    }

                    geometry.Resource.ChangeLocation(ResourceLocation.Resources);

                    geometry.Resource.Page.Index = cache.Add(resourceStreams[ResourceLocation.Resources], dataStream.ToArray(), out uint compressedSize);
                    geometry.Resource.Page.CompressedBlockSize   = compressedSize;
                    geometry.Resource.Page.UncompressedBlockSize = (uint)dataStream.Length;
                    geometry.Resource.DisableChecksum();

                    var resourceContext = new ResourceSerializationContext(CacheContext, geometry.Resource);
                    CacheContext.Serializer.Serialize(resourceContext, resourceDefinition);
                }

            return(geometry);
        }
示例#5
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());
        }
示例#6
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));
        }
示例#7
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();
                }
        }