public override object Execute(List <string> args)
        {
            if (args.Count < 2)
            {
                return(false);
            }

            //
            // Verify Blam tag instance
            //

            var unitName = args[0].ToLower();

            if (unitName != "spartan" && unitName != "elite")
            {
                Console.WriteLine("ERROR: Only 'spartan' and 'elite' armor variants are allowed.");
                return(false);
            }

            args.RemoveAt(0);

            var blamTagName = unitName == "spartan" ?
                              @"objects\characters\masterchief\mp_masterchief\mp_masterchief" :
                              @"objects\characters\elite\mp_elite\mp_elite";

            Console.Write($"Verifying {blamTagName}.render_model...");

            CacheFile.IndexItem blamTag = null;

            foreach (var tag in BlamCache.IndexItems)
            {
                if ((tag.GroupTag == "mode") && (tag.Name == blamTagName))
                {
                    blamTag = tag;
                    break;
                }
            }

            if (blamTag == null)
            {
                Console.WriteLine($"ERROR: Blam tag does not exist: {blamTagName}.render_model");
                return(true);
            }

            Console.WriteLine("done.");

            //
            // Load the Blam tag definition
            //

            var variantName = args[0];

            args.RemoveAt(0);

            CachedTagInstance edModeTag = null;
            var isScenery   = false;
            var regionNames = new List <string>();

            while (args.Count != 0)
            {
                switch (args[0].ToLower())
                {
                case "scenery":
                    isScenery = true;
                    args.RemoveAt(0);
                    break;

                case "replace:":
                    edModeTag = CacheContext.GetTag(args[1]);
                    args.RemoveAt(1);
                    args.RemoveAt(0);
                    break;

                case "regions:":
                    regionNames.AddRange(args.Skip(1));
                    args.Clear();
                    break;

                default:
                    throw new InvalidDataException($"{args}");
                }
            }

            var blamContext      = new CacheSerializationContext(ref BlamCache, blamTag);
            var edModeDefinition = BlamCache.Deserializer.Deserialize <RenderModel>(blamContext);

            var materials = edModeDefinition.Materials.Select(i => new RenderMaterial
            {
                BreakableSurfaceIndex = i.BreakableSurfaceIndex,
                Properties            = i.Properties,
                RenderMethod          = i.RenderMethod,
                Skins    = i.Skins,
                Unknown  = i.Unknown,
                Unknown2 = i.Unknown2,
                Unknown3 = i.Unknown3,
                Unknown4 = i.Unknown4
            }).ToList();

            edModeDefinition = (RenderModel)ConvertData(null, edModeDefinition, false);

            var variantRegions = new List <RenderModel.Region>();

            foreach (var region in edModeDefinition.Regions)
            {
                if (regionNames.Count != 0 && !regionNames.Contains(CacheContext.GetString(region.Name)))
                {
                    continue;
                }

                var variantRegion = new RenderModel.Region
                {
                    Name         = region.Name,
                    Permutations = new List <RenderModel.Region.Permutation>()
                };

                foreach (var permutation in region.Permutations)
                {
                    if (variantName == CacheContext.GetString(permutation.Name))
                    {
                        variantRegion.Permutations.Add(permutation);
                    }
                }

                variantRegions.Add(variantRegion);
            }

            var variantMeshes        = new List <int>();
            var variantMaterials     = new List <int>();
            var variantVertexBuffers = new List <int>();
            var variantIndexBuffers  = new List <int>();

            foreach (var region in variantRegions)
            {
                foreach (var permutation in region.Permutations)
                {
                    for (var i = permutation.MeshIndex; i < (short)(permutation.MeshIndex + permutation.MeshCount); i++)
                    {
                        var mesh = edModeDefinition.Geometry.Meshes[i];

                        foreach (var part in mesh.Parts)
                        {
                            if (part.MaterialIndex != -1 && !variantMaterials.Contains(part.MaterialIndex))
                            {
                                variantMaterials.Add(part.MaterialIndex);
                            }
                        }

                        foreach (var vertexBuffer in mesh.VertexBufferIndices)
                        {
                            if (vertexBuffer != ushort.MaxValue && !variantVertexBuffers.Contains(vertexBuffer))
                            {
                                variantVertexBuffers.Add(vertexBuffer);
                            }
                        }

                        foreach (var indexBuffer in mesh.IndexBufferIndices)
                        {
                            if (indexBuffer != ushort.MaxValue && !variantIndexBuffers.Contains(indexBuffer))
                            {
                                variantIndexBuffers.Add(indexBuffer);
                            }
                        }

                        if (!variantMeshes.Contains(i))
                        {
                            variantMeshes.Add(i);
                        }
                    }
                }
            }

            variantMeshes.Sort();
            variantMaterials.Sort();
            variantVertexBuffers.Sort();
            variantIndexBuffers.Sort();

            foreach (var meshIndex in variantMeshes)
            {
                var mesh = edModeDefinition.Geometry.Meshes[meshIndex];

                foreach (var part in mesh.Parts)
                {
                    if (part.MaterialIndex != -1)
                    {
                        part.MaterialIndex = (short)variantMaterials.IndexOf(part.MaterialIndex);
                    }
                }
            }

            foreach (var region in variantRegions)
            {
                foreach (var permutation in region.Permutations)
                {
                    if (permutation.MeshIndex != -1)
                    {
                        permutation.MeshIndex = (short)variantMeshes.IndexOf(permutation.MeshIndex);
                    }
                }
            }

            foreach (var meshIndex in variantMeshes)
            {
                var mesh = edModeDefinition.Geometry.Meshes[meshIndex];

                for (var i = 0; i < mesh.VertexBufferIndices.Length; i++)
                {
                    if (!variantVertexBuffers.Contains(mesh.VertexBufferIndices[i]))
                    {
                        mesh.VertexBufferIndices[i] = ushort.MaxValue;
                    }
                    else
                    {
                        mesh.VertexBufferIndices[i] = (ushort)variantVertexBuffers.IndexOf(mesh.VertexBufferIndices[i]);
                    }
                }

                for (var i = 0; i < mesh.IndexBufferIndices.Length; i++)
                {
                    if (!variantIndexBuffers.Contains(mesh.IndexBufferIndices[i]))
                    {
                        mesh.IndexBufferIndices[i] = ushort.MaxValue;
                    }
                    else
                    {
                        mesh.IndexBufferIndices[i] = (ushort)variantIndexBuffers.IndexOf(mesh.IndexBufferIndices[i]);
                    }
                }
            }

            edModeDefinition.Regions         = variantRegions;
            edModeDefinition.Geometry.Meshes = edModeDefinition.Geometry.Meshes.Where(i => variantMeshes.Contains(edModeDefinition.Geometry.Meshes.IndexOf(i))).ToList();

            //
            // Port Blam render_model materials
            //

            materials = materials.Where(i => variantMaterials.Contains(materials.IndexOf(i))).ToList();

            using (var stream = CacheContext.OpenTagCacheReadWrite())
            {
                for (var i = 0; i < materials.Count; i++)
                {
                    var material = materials[i];

                    if (material.RenderMethod.Index == -1)
                    {
                        continue;
                    }

                    var blamRenderMethod    = materials[i].RenderMethod;
                    var blamRenderMethodTag = BlamCache.IndexItems.GetItemByID(blamRenderMethod.Index);

                    var renderMethodExists = false;

                    foreach (var instance in CacheContext.TagCache.Index.FindAllInGroup("rm  "))
                    {
                        if (instance?.Name == blamRenderMethodTag.Name)
                        {
                            renderMethodExists    = true;
                            material.RenderMethod = instance;
                            break;
                        }
                    }

                    if (!renderMethodExists)
                    {
                        material.RenderMethod = CacheContext.GetTag <Shader>(@"shaders\invalid");
                    }
                }
            }

            edModeDefinition.Materials = materials;

            //
            // Load Blam resource data
            //

            var resourceData = BlamCache.GetRawFromID(edModeDefinition.Geometry.ZoneAssetHandle);

            if (resourceData == null)
            {
                Console.WriteLine("Blam render_geometry resource contains no data.");
                return(true);
            }

            //
            // Load Blam resource definition
            //

            Console.Write("Loading Blam render_geometry resource definition...");

            var definitionEntry = BlamCache.ResourceGestalt.TagResources[edModeDefinition.Geometry.ZoneAssetHandle.Index];

            var resourceDefinition = new RenderGeometryApiResourceDefinition
            {
                VertexBuffers = new List <TagStructureReference <VertexBufferDefinition> >(),
                IndexBuffers  = new List <TagStructureReference <IndexBufferDefinition> >()
            };

            using (var definitionStream = new MemoryStream(BlamCache.ResourceGestalt.FixupInformation))
                using (var definitionReader = new EndianReader(definitionStream, EndianFormat.BigEndian))
                {
                    var dataContext = new DataSerializationContext(definitionReader, null, CacheResourceAddressType.Definition);

                    definitionReader.SeekTo(definitionEntry.FixupInformationOffset + (definitionEntry.FixupInformationLength - 24));

                    var vertexBufferCount = definitionReader.ReadInt32();
                    definitionReader.Skip(8);
                    var indexBufferCount = definitionReader.ReadInt32();

                    definitionReader.SeekTo(definitionEntry.FixupInformationOffset);

                    for (var i = 0; i < vertexBufferCount; i++)
                    {
                        resourceDefinition.VertexBuffers.Add(new TagStructureReference <VertexBufferDefinition>
                        {
                            Definition = new VertexBufferDefinition
                            {
                                Count      = definitionReader.ReadInt32(),
                                Format     = (VertexBufferFormat)definitionReader.ReadInt16(),
                                VertexSize = definitionReader.ReadInt16(),
                                Data       = new TagData
                                {
                                    Size     = definitionReader.ReadInt32(),
                                    Unused4  = definitionReader.ReadInt32(),
                                    Unused8  = definitionReader.ReadInt32(),
                                    Address  = new CacheResourceAddress(CacheResourceAddressType.Memory, definitionReader.ReadInt32()),
                                    Unused10 = definitionReader.ReadInt32()
                                }
                            }
                        });
                    }

                    definitionReader.Skip(vertexBufferCount * 12);

                    for (var i = 0; i < indexBufferCount; i++)
                    {
                        resourceDefinition.IndexBuffers.Add(new TagStructureReference <IndexBufferDefinition>
                        {
                            Definition = new IndexBufferDefinition
                            {
                                Format = (IndexBufferFormat)definitionReader.ReadInt32(),
                                Data   = new TagData
                                {
                                    Size     = definitionReader.ReadInt32(),
                                    Unused4  = definitionReader.ReadInt32(),
                                    Unused8  = definitionReader.ReadInt32(),
                                    Address  = new CacheResourceAddress(CacheResourceAddressType.Memory, definitionReader.ReadInt32()),
                                    Unused10 = definitionReader.ReadInt32()
                                }
                            }
                        });
                    }
                }

            Console.WriteLine("done.");

            //
            // Convert Blam resource data
            //

            using (var edResourceStream = new MemoryStream())
            {
                //
                // Convert Blam render_geometry_api_resource_definition
                //

                using (var blamResourceStream = new MemoryStream(resourceData))
                {
                    //
                    // Convert Blam vertex buffers
                    //

                    Console.Write("Converting vertex buffers...");

                    var previousVertexBufferCount = -1;

                    for (var i = 0; i < resourceDefinition.VertexBuffers.Count; i++)
                    {
                        if (!variantVertexBuffers.Contains(i))
                        {
                            continue;
                        }

                        blamResourceStream.Position = definitionEntry.ResourceFixups[i].Offset;
                        if (i > 0)
                        {
                            previousVertexBufferCount = resourceDefinition.VertexBuffers[i - 1].Definition.Count;
                        }
                        GeometryConverter.ConvertVertexBuffer(resourceDefinition, blamResourceStream, edResourceStream, i, previousVertexBufferCount);
                    }

                    Console.WriteLine("done.");

                    //
                    // Convert Blam index buffers
                    //

                    Console.Write("Converting index buffers...");

                    for (var i = 0; i < resourceDefinition.IndexBuffers.Count; i++)
                    {
                        if (!variantIndexBuffers.Contains(i))
                        {
                            continue;
                        }

                        blamResourceStream.Position = definitionEntry.ResourceFixups[resourceDefinition.VertexBuffers.Count * 2 + i].Offset;
                        GeometryConverter.ConvertIndexBuffer(resourceDefinition, blamResourceStream, edResourceStream, i);
                    }

                    Console.WriteLine("done.");
                }

                resourceDefinition.VertexBuffers = resourceDefinition.VertexBuffers.Where(i => variantVertexBuffers.Contains(resourceDefinition.VertexBuffers.IndexOf(i))).ToList();
                resourceDefinition.IndexBuffers  = resourceDefinition.IndexBuffers.Where(i => variantIndexBuffers.Contains(resourceDefinition.IndexBuffers.IndexOf(i))).ToList();

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

                Console.Write("Writing resource data...");

                edModeDefinition.Geometry.Resource = new PageableResource
                {
                    Page     = new RawPage(),
                    Resource = new TagResourceGen3
                    {
                        ResourceType             = TagResourceTypeGen3.RenderGeometry,
                        ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        Unknown2 = 1
                    }
                };

                edResourceStream.Position = 0;

                var resourceContext = new ResourceSerializationContext(CacheContext, edModeDefinition.Geometry.Resource);
                CacheContext.Serializer.Serialize(resourceContext, resourceDefinition);
                edModeDefinition.Geometry.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                CacheContext.AddResource(edModeDefinition.Geometry.Resource, edResourceStream);

                Console.WriteLine("done.");
            }

            edModeDefinition.Name = CacheContext.GetStringId(variantName);

            if (edModeTag == null)
            {
                for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                {
                    if (CacheContext.TagCache.Index[i] == null)
                    {
                        CacheContext.TagCache.Index[i] = edModeTag = new CachedTagInstance(i, TagGroup.Instances[new Tag("mode")]);
                        break;
                    }
                }

                if (edModeTag == null)
                {
                    edModeTag = CacheContext.TagCache.AllocateTag(TagGroup.Instances[new Tag("mode")]);
                }
            }

            //
            // Create a new armor model tag
            //

            Model             edHlmtDefinition = null;
            CachedTagInstance edHlmtTag        = null;

            if (isScenery)
            {
                Console.Write($"Verifying {blamTagName}.model...");

                CacheFile.IndexItem blamHlmtTag = null;

                foreach (var tag in BlamCache.IndexItems)
                {
                    if ((tag.GroupTag == "hlmt") && (tag.Name == blamTagName))
                    {
                        blamHlmtTag = tag;
                        break;
                    }
                }

                if (blamHlmtTag == null)
                {
                    Console.WriteLine($"ERROR: Blam tag does not exist: {blamTagName}.model");
                    return(true);
                }

                Console.WriteLine("done.");

                blamContext      = new CacheSerializationContext(ref BlamCache, blamHlmtTag);
                edHlmtDefinition = (Model)ConvertData(null, BlamCache.Deserializer.Deserialize <Model>(blamContext), false);

                edHlmtDefinition.RenderModel        = edModeTag;
                edHlmtDefinition.ReduceToL1SuperLow = 36.38004f;
                edHlmtDefinition.ReduceToL2Low      = 27.28503f;
                edHlmtDefinition.Variants           = new List <Model.Variant>();
                edHlmtDefinition.Materials          = new List <Model.Material>();
                edHlmtDefinition.NewDamageInfo      = new List <Model.GlobalDamageInfoBlock>();
                edHlmtDefinition.Targets            = new List <Model.Target>();

                var collisionRegions = new List <Model.CollisionRegion>();

                foreach (var collisionRegion in edHlmtDefinition.CollisionRegions)
                {
                    var found = false;

                    foreach (var variantRegion in variantRegions)
                    {
                        if (collisionRegion.Name == variantRegion.Name)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        continue;
                    }

                    found = false;

                    foreach (var permutation in collisionRegion.Permutations)
                    {
                        if (permutation.Name == CacheContext.GetStringId(variantName))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (found)
                    {
                        collisionRegions.Add(collisionRegion);
                    }
                }

                foreach (var collisionRegion in collisionRegions)
                {
                    Model.CollisionRegion.Permutation permutation = null;

                    foreach (var collisionPermutation in collisionRegion.Permutations)
                    {
                        if (collisionPermutation.Name == CacheContext.GetStringId(variantName))
                        {
                            permutation = collisionPermutation;
                            break;
                        }
                    }

                    if (permutation == null)
                    {
                        throw new KeyNotFoundException();
                    }

                    collisionRegion.Permutations = new List <Model.CollisionRegion.Permutation> {
                        permutation
                    };
                }

                edHlmtDefinition.CollisionRegions = collisionRegions;

                for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                {
                    if (CacheContext.TagCache.Index[i] == null)
                    {
                        CacheContext.TagCache.Index[i] = edHlmtTag = new CachedTagInstance(i, TagGroup.Instances[new Tag("hlmt")]);
                        break;
                    }
                }

                if (edHlmtTag == null)
                {
                    edHlmtTag = CacheContext.TagCache.AllocateTag(TagGroup.Instances[new Tag("hlmt")]);
                }
            }

            //
            // Create a new armor scenery tag
            //

            Scenery           edScenDefinition = null;
            CachedTagInstance edScenTag        = null;

            if (isScenery)
            {
                edScenDefinition = new Scenery
                {
                    ObjectType = new GameObjectType
                    {
                        Halo2       = GameObjectTypeHalo2.Scenery,
                        Halo3Retail = GameObjectTypeHalo3Retail.Scenery,
                        Halo3ODST   = GameObjectTypeHalo3ODST.Scenery,
                        HaloOnline  = GameObjectTypeHaloOnline.Scenery
                    },
                    BoundingRadius    = 0.44f,
                    BoundingOffset    = new RealPoint3d(-0.02f, 0.0f, 0.0f),
                    AccelerationScale = 1.2f,
                    SweetenerSize     = GameObject.SweetenerSizeValue.Medium,
                    Model             = edHlmtTag,
                    ChangeColors      = new List <GameObject.ChangeColor>
                    {
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor()
                    },
                    NodeMaps = new List <GameObject.NodeMap>()
                };

                for (sbyte i = 0; i < 51; i++)
                {
                    edScenDefinition.NodeMaps.Add(new GameObject.NodeMap {
                        TargetNode = i
                    });
                }

                for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                {
                    if (CacheContext.TagCache.Index[i] == null)
                    {
                        CacheContext.TagCache.Index[i] = edScenTag = new CachedTagInstance(i, TagGroup.Instances[new Tag("scen")]);
                        break;
                    }
                }

                if (edScenTag == null)
                {
                    edScenTag = CacheContext.TagCache.AllocateTag(TagGroup.Instances[new Tag("scen")]);
                }
            }

            //
            // Serialize new ElDorado tag definitions
            //

            using (var cacheStream = CacheContext.OpenTagCacheReadWrite())
            {
                CacheContext.Serialize(cacheStream, edModeTag, edModeDefinition);
                edModeTag.Name = isScenery ?
                                 (unitName == "spartan" ?
                                  $@"objects\characters\masterchief\mp_masterchief\armor\{variantName}" :
                                  $@"objects\characters\elite\mp_elite\armor\{variantName}") :
                                 (unitName == "spartan" ?
                                  @"objects\characters\masterchief\mp_masterchief\mp_masterchief" :
                                  @"objects\characters\elite\mp_elite\mp_elite");

                if (isScenery)
                {
                    CacheContext.Serialize(cacheStream, edHlmtTag, edHlmtDefinition);
                    CacheContext.Serialize(cacheStream, edScenTag, edScenDefinition);
                    edScenTag.Name = unitName == "spartan" ?
                                     $@"objects\characters\masterchief\mp_masterchief\armor\{variantName}" :
                                     $@"objects\characters\elite\mp_elite\armor\{variantName}";
                }
            }

            return(true);
        }
示例#2
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 0)
            {
                return(false);
            }

            var soundDataAggregate = new byte[0].AsEnumerable();

            int currentFileOffset         = 0;
            int totalSampleCount          = 0;
            int maxPermutationSampleCount = 0;


            int pitchRangeCount = GetPitchRangeCountUser();

            if (pitchRangeCount <= 0)
            {
                return(false);
            }

            //
            // Get basic information on the sounds
            //

            if (pitchRangeCount > 1)
            {
                Definition.ImportType = ImportType.MultiLayer;
            }
            else
            {
                Definition.ImportType = ImportType.SingleLayer;
            }

            Definition.SampleRate.value = GetSoundSampleRateUser();

            Definition.PlatformCodec.Compression = GetSoundCompressionUser();

            Definition.PlatformCodec.Encoding = GetSoundEncodingUser();

            Definition.PitchRanges = new List <PitchRange>();

            //
            // For each pitch range, get all the permutations and append sound data.
            //

            for (int u = 0; u < pitchRangeCount; u++)
            {
                int permutationCount = GetPermutationCountUser();

                if (permutationCount <= 0)
                {
                    return(false);
                }

                var pitchRange = new PitchRange
                {
                    ImportName           = new StringId(5221), //|default|
                    Unknown5             = -1,
                    Unknown6             = -1,
                    Unknown7             = -1,
                    Unknown8             = -1,
                    PermutationCount     = (short)permutationCount,
                    PitchRangeParameters = new PitchRangeParameter()
                };
                pitchRange.PitchRangeParameters.UnknownBounds = new Bounds <short>(-32768, 32767);

                pitchRange.Permutations = new List <Permutation>();

                //
                // Permutation section
                //

                for (int i = 0; i < permutationCount; i++)
                {
                    string soundFile = GetPermutationFileUser(i);
                    if (soundFile == null)
                    {
                        return(false);
                    }

                    int sampleCount = GetPermutationSampleCountUser(i);

                    var perm = new Permutation
                    {
                        ImportName = StringId.Invalid,
                        SampleSize = (uint)sampleCount
                    };

                    if (i != 0)
                    {
                        perm.IsNotFirstPermutation = 1;
                    }

                    perm.PermutationNumber = (uint)i;

                    var permutationData = File.ReadAllBytes(soundFile);

                    perm.PermutationChunks = new List <PermutationChunk>();

                    var chunk = new PermutationChunk(currentFileOffset, permutationData.Length);
                    perm.PermutationChunks.Add(chunk);
                    currentFileOffset += permutationData.Length;
                    totalSampleCount  += sampleCount;

                    if (maxPermutationSampleCount < sampleCount)
                    {
                        maxPermutationSampleCount = sampleCount;
                    }

                    soundDataAggregate = soundDataAggregate.Concat(permutationData);

                    pitchRange.Permutations.Add(perm);
                }

                Definition.PitchRanges.Add(pitchRange);
            }

            Definition.Promotion.LongestPermutationDuration = (uint)(1000 * (double)maxPermutationSampleCount / (Definition.SampleRate.GetSampleRateHz()));
            Definition.Promotion.TotalSampleSize            = (uint)totalSampleCount;


            // remove extra info for now

            Definition.ExtraInfo = new List <ExtraInfo>();

            //
            // Create new resource
            //

            Console.Write("Creating new sound resource...");

            var data = soundDataAggregate.ToArray();

            Definition.Unknown12 = 0;

            using (var dataStream = new MemoryStream(data))
            {
                var fileSize        = (int)dataStream.Length;
                var resourceContext = new ResourceSerializationContext(CacheContext, Definition.Resource);
                CacheContext.Serializer.Serialize(resourceContext,
                                                  new SoundResourceDefinition
                {
                    Data = new TagData(fileSize, new CacheResourceAddress(CacheResourceAddressType.Resource, 0))
                });

                Definition.Resource = new PageableResource
                {
                    Page = new RawPage
                    {
                        Index = -1
                    },
                    Resource = new TagResourceGen3
                    {
                        ResourceType      = TagResourceTypeGen3.Sound,
                        DefinitionData    = new byte[20],
                        DefinitionAddress = new CacheResourceAddress(CacheResourceAddressType.Definition, 536870912),
                        ResourceFixups    = new List <TagResourceGen3.ResourceFixup>
                        {
                            new TagResourceGen3.ResourceFixup
                            {
                                BlockOffset = 12,
                                Address     = new CacheResourceAddress(CacheResourceAddressType.Resource, 1073741824)
                            }
                        },
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        Unknown2 = 1
                    }
                };

                Definition.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                CacheContext.AddResource(Definition.Resource, dataStream);

                for (int i = 0; i < 4; i++)
                {
                    Definition.Resource.Resource.DefinitionData[i] = (byte)(Definition.Resource.Page.UncompressedBlockSize >> (i * 8));
                }

                Console.WriteLine("done.");
            }
            return(true);
        }
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            if (!CacheContext.TryGetTag <Shader>(@"shaders\invalid", out var defaultShaderTag))
            {
                Console.WriteLine("WARNING: 'shaders\\invalid.shader' not found!");
                Console.WriteLine("You will have to assign material shaders manually.");
            }

            var stringIdCount = CacheContext.StringIdCache.Strings.Count;

            var sceneFile = new FileInfo(args[0]);

            if (!sceneFile.Exists)
            {
                throw new FileNotFoundException(sceneFile.FullName);
            }

            if (sceneFile.Extension.ToLower() != ".dae")
            {
                throw new FormatException($"Input file is not COLLADA format: {sceneFile.FullName}");
            }

            Scene scene;

            using (var importer = new AssimpContext())
            {
                scene = importer.ImportFile(sceneFile.FullName,
                                            PostProcessSteps.CalculateTangentSpace |
                                            PostProcessSteps.GenerateNormals |
                                            PostProcessSteps.SortByPrimitiveType |
                                            PostProcessSteps.Triangulate);
            }

            var builder         = new RenderModelBuilder(CacheContext);
            var nodes           = new Dictionary <string, sbyte>();
            var materialIndices = new Dictionary <string, short>();

            foreach (var oldNode in Definition.Nodes)
            {
                var name = CacheContext.GetString(oldNode.Name);

                nodes[name] = builder.AddNode(oldNode);
            }

            foreach (var region in Definition.Regions)
            {
                builder.BeginRegion(region.Name);

                var regionName = CacheContext.GetString(region.Name);

                foreach (var permutation in region.Permutations)
                {
                    if (permutation.MeshCount > 1)
                    {
                        throw new NotSupportedException("multiple permutation meshes");
                    }

                    if (permutation.MeshIndex == -1)
                    {
                        continue;
                    }

                    var permName = CacheContext.GetString(permutation.Name);
                    var meshName = $"{regionName}FBXASC058{permName}Mesh";

                    var permMeshes = scene.Meshes.Where(i => i.Name == meshName).ToList();

                    if (permMeshes.Count == 0)
                    {
                        throw new Exception($"No mesh(es) found for region '{regionName}' permutation '{permName}'!");
                    }

                    permMeshes.Sort((a, b) => a.MaterialIndex.CompareTo(b.MaterialIndex));

                    // Build a multipart mesh from the model data,
                    // with each model mesh mapping to a part of one large mesh and having its own material
                    ushort partStartVertex = 0;
                    ushort partStartIndex  = 0;

                    var rigidVertices   = new List <RigidVertex>();
                    var skinnedVertices = new List <SkinnedVertex>();

                    var indices = new List <ushort>();

                    var vertexType = Definition.Geometry.Meshes[permutation.MeshIndex].Type;
                    var rigidNode  = Definition.Geometry.Meshes[permutation.MeshIndex].RigidNodeIndex;

                    builder.BeginPermutation(permutation.Name);
                    builder.BeginMesh();

                    foreach (var mesh in permMeshes)
                    {
                        for (var i = 0; i < mesh.VertexCount; i++)
                        {
                            var position = mesh.Vertices[i];
                            var normal   = mesh.Normals[i];

                            Vector3D uv;

                            try
                            {
                                uv = mesh.TextureCoordinateChannels[0][i];
                            }
                            catch
                            {
                                Console.WriteLine($"WARNING: Missing texture coordinate for vertex {i} in '{regionName}:{permName}'");
                                uv = new Vector3D();
                            }

                            var tangent   = mesh.Tangents.Count != 0 ? mesh.Tangents[i] : new Vector3D();
                            var bitangent = mesh.BiTangents.Count != 0 ? mesh.BiTangents[i] : new Vector3D();

                            if (vertexType == VertexType.Skinned)
                            {
                                var blendIndicesList = new List <byte>();
                                var blendWeightsList = new List <float>();

                                foreach (var bone in mesh.Bones)
                                {
                                    foreach (var vertexInfo in bone.VertexWeights)
                                    {
                                        if (vertexInfo.VertexID == i)
                                        {
                                            // HAX BELOW
                                            //if (bone.Name.StartsWith("_"))
                                            //bone.Name = bone.Name.Substring(4);
                                            //if (bone.Name.EndsWith("2"))
                                            //bone.Name = bone.Name.Replace("2", "_tip");
                                            //else if (bone.Name != "spine1" && bone.Name.EndsWith("1"))
                                            //bone.Name = bone.Name.Replace("1", "_low");
                                            blendIndicesList.Add((byte)nodes[bone.Name]);
                                            blendWeightsList.Add(vertexInfo.Weight);
                                        }
                                    }
                                }

                                var blendIndices = new byte[4];
                                var blendWeights = new float[4];

                                for (int j = 0; j < blendIndicesList.Count; j++)
                                {
                                    if (j < 4)
                                    {
                                        blendIndices[j] = blendIndicesList[j];
                                    }
                                }

                                for (int j = 0; j < blendWeightsList.Count; j++)
                                {
                                    if (j < 4)
                                    {
                                        blendWeights[j] = blendWeightsList[j];
                                    }
                                }

                                skinnedVertices.Add(new SkinnedVertex
                                {
                                    Position     = new RealQuaternion(position.X * 0.01f, position.Y * 0.01f, position.Z * 0.01f, 1),
                                    Texcoord     = new RealVector2d(uv.X, -uv.Y),
                                    Normal       = new RealVector3d(normal.X, normal.Y, normal.Z),
                                    Tangent      = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1),
                                    Binormal     = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z),
                                    BlendIndices = blendIndices,
                                    BlendWeights = blendWeights
                                });
                            }
                            else
                            {
                                rigidVertices.Add(new RigidVertex
                                {
                                    Position = new RealQuaternion(position.X * 0.01f, position.Y * 0.01f, position.Z * 0.01f, 1),
                                    Texcoord = new RealVector2d(uv.X, -uv.Y),
                                    Normal   = new RealVector3d(normal.X, normal.Y, normal.Z),
                                    Tangent  = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1),
                                    Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z),
                                });
                            }
                        }

                        // Build the index buffer
                        var meshIndices = mesh.GetIndices();
                        indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex)));

                        // Define a material and part for this mesh
                        var meshMaterial = scene.Materials[mesh.MaterialIndex];

                        short materialIndex = 0;

                        if (materialIndices.ContainsKey(meshMaterial.Name))
                        {
                            materialIndex = materialIndices[meshMaterial.Name];
                        }
                        else
                        {
                            materialIndex = materialIndices[meshMaterial.Name] = builder.AddMaterial(new RenderMaterial
                            {
                                RenderMethod = defaultShaderTag,
                            });
                        }

                        builder.BeginPart(materialIndex, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                        builder.DefineSubPart(partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount);
                        builder.EndPart();

                        // Move to the next part
                        partStartVertex += (ushort)mesh.VertexCount;
                        partStartIndex  += (ushort)meshIndices.Length;
                    }

                    // Bind the vertex and index buffers
                    if (vertexType == VertexType.Skinned)
                    {
                        builder.BindSkinnedVertexBuffer(skinnedVertices);
                    }
                    else
                    {
                        builder.BindRigidVertexBuffer(rigidVertices, rigidNode);
                    }

                    builder.BindIndexBuffer(indices, IndexBufferFormat.TriangleList);

                    builder.EndMesh();
                    builder.EndPermutation();
                }

                builder.EndRegion();
            }

            using (var resourceStream = new MemoryStream())
            {
                Console.Write("Building render_geometry...");

                var newDefinition = builder.Build(CacheContext.Serializer, resourceStream);
                Definition.Regions   = newDefinition.Regions;
                Definition.Geometry  = newDefinition.Geometry;
                Definition.Nodes     = newDefinition.Nodes;
                Definition.Materials = newDefinition.Materials;

                resourceStream.Position = 0;

                Definition.Geometry.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                CacheContext.AddResource(Definition.Geometry.Resource, resourceStream);

                Console.WriteLine("done.");
            }

            //
            // TODO: Build the new render_model and update the original render_model here...
            //

            Console.Write("Writing render_model tag data...");

            using (var cacheStream = CacheContext.OpenTagCacheReadWrite())
                CacheContext.Serialize(cacheStream, Tag, Definition);

            Console.WriteLine("done.");

            if (stringIdCount != CacheContext.StringIdCache.Strings.Count)
            {
                Console.Write("Saving string ids...");

                using (var stream = CacheContext.OpenStringIdCacheReadWrite())
                    CacheContext.StringIdCache.Save(stream);

                Console.WriteLine("done");
            }

            Console.WriteLine("Replaced render_geometry successfully.");

            return(true);
        }
示例#4
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            var resourceFile = new FileInfo(args[0]);
            var fileSize     = 0;

            if (!resourceFile.Exists)
            {
                Console.WriteLine($"ERROR: File not found: \"{resourceFile.FullName}\"");
                return(true);
            }

            //
            // Create new resource
            //

            Console.Write("Creating new sound resource...");

            Definition.Unknown12 = 0;

            using (var dataStream = resourceFile.OpenRead())
            {
                fileSize = (int)dataStream.Length;
                var resourceContext = new ResourceSerializationContext(CacheContext, Definition.Resource);
                CacheContext.Serializer.Serialize(resourceContext,
                                                  new SoundResourceDefinition
                {
                    Data = new TagData(fileSize, new CacheAddress(CacheAddressType.Resource, 0))
                });

                Definition.Resource = new PageableResource
                {
                    Page = new RawPage
                    {
                        Index = -1
                    },
                    Resource = new TagResourceGen3
                    {
                        ResourceType      = TagResourceTypeGen3.Sound,
                        DefinitionData    = new byte[20],
                        DefinitionAddress = new CacheAddress(CacheAddressType.Definition, 536870912),
                        ResourceFixups    = new List <TagResourceGen3.ResourceFixup>
                        {
                            new TagResourceGen3.ResourceFixup
                            {
                                BlockOffset = 12,
                                Address     = new CacheAddress(CacheAddressType.Resource, 1073741824)
                            }
                        },
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        Unknown2 = 1
                    }
                };

                Definition.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                CacheContext.AddResource(Definition.Resource, dataStream);

                for (int i = 0; i < 4; i++)
                {
                    Definition.Resource.Resource.DefinitionData[i] = (byte)(Definition.Resource.Page.UncompressedBlockSize >> (i * 8));
                }

                Console.WriteLine("done.");
            }

            //
            // Adjust tag definition to use correctly the sound file.
            //

            var chunkSize = (ushort)fileSize;

            var permutationChunk = new PermutationChunk(0, chunkSize);

            var permutation = Definition.PitchRanges[0].Permutations[0];

            permutation.PermutationChunks = new List <PermutationChunk>
            {
                permutationChunk
            };

            permutation.PermutationNumber     = 0;
            permutation.SampleSize            = 0;
            permutation.IsNotFirstPermutation = 0;

            Definition.PitchRanges[0].Permutations = new List <Permutation>
            {
                permutation
            };

            Definition.PlatformCodec.Compression = Compression.MP3;

            return(true);
        }