public static SoundCacheFileGestalt LoadSoundGestalt(HaloOnlineCacheContext cacheContext, ref CacheFile blamCache) { CacheFile.IndexItem blamTag = null; foreach (var tag in blamCache.IndexItems) { if (tag.GroupTag == "ugh!") { blamTag = tag; break; } } if (blamTag == null) { return(null); } var blamContext = new CacheSerializationContext(ref blamCache, blamTag); var ugh = blamCache.Deserializer.Deserialize <SoundCacheFileGestalt>(blamContext); // // Apply conversion to ugh! data (gain increase and such) // return(ugh); }
public void ExtractXMA(CacheFile.IndexItem blamTag, string directory) { if (BlamSoundGestalt == null) { BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache); } var blamContext = new CacheSerializationContext(ref BlamCache, blamTag); var sound = BlamCache.Deserializer.Deserialize <Sound>(blamContext); var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount); if (xmaFileSize < 0) { return; } var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize); if (xmaData == null) { Console.WriteLine($"ERROR: Failed to find sound data!"); return; } var parts = blamTag.Name.Split('\\'); string baseName = parts[parts.Length - 1]; for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++) { var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex; var permutationCount = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex); for (int i = 0; i < permutationCount; i++) { BlamSound blamSound = SoundConverter.GetXMA(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData); string permutationName = $"{baseName}_{relativePitchRangeIndex}_{i}"; var fileName = $"{directory}\\{permutationName}.xma"; using (EndianWriter output = new EndianWriter(new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian)) { XMAFile XMAfile = new XMAFile(blamSound); XMAfile.Write(output); } } } }
private void ExtractBitmap(CacheFile.IndexItem blamTag, string directory) { Console.WriteLine($"{blamTag.Name}"); // // Load the Blam tag definition // var blamContext = new CacheSerializationContext(ref BlamCache, blamTag); var bitmap = BlamCache.Deserializer.Deserialize <Bitmap>(blamContext); var ddsOutDir = directory; string bitmap_name = blamTag.Name.Replace('\\', '_'); if (bitmap.Images.Count > 1) { ddsOutDir = Path.Combine(directory, bitmap_name); Directory.CreateDirectory(ddsOutDir); } for (var i = 0; i < bitmap.Images.Count; i++) { var outPath = Path.Combine(ddsOutDir, ((bitmap.Images.Count > 1) ? i.ToString() : bitmap_name) + ".dds"); var image = bitmap.Images[i]; // // Get bitmap data and write file // BaseBitmap baseBitmap = ExtractBitmapData(bitmap, i); // Bitmap is not valid (not a failure to convert, tag data is not valid / no data to convert if (baseBitmap == null) { return; } var header = new DDSHeader(baseBitmap); using (var outStream = File.Open(outPath, FileMode.Create, FileAccess.Write)) { header.Write(new EndianWriter(outStream)); var dataStream = new MemoryStream(baseBitmap.Data); StreamUtil.Copy(dataStream, outStream, baseBitmap.Data.Length); } } }
public override void LoadResourceTags() { TagDeserializer deserializer = new TagDeserializer(Version); foreach (IndexItem item in IndexItems) { if (item.GroupTag == "play") { CacheFile cacheFile = this; var blamContext = new CacheSerializationContext(ref cacheFile, item); if (cacheFile.File.FullName != File.FullName) { throw new InvalidOperationException(); } ResourceLayoutTable = deserializer.Deserialize <CacheFileResourceLayoutTable>(blamContext); break; } } foreach (IndexItem item in IndexItems) { if (item.GroupTag == "zone") { CacheFile cacheFile = this; var blamContext = new CacheSerializationContext(ref cacheFile, item); if (cacheFile.File.FullName != File.FullName) { throw new InvalidOperationException(); } ResourceGestalt = deserializer.Deserialize <CacheFileResourceGestalt>(blamContext); foreach (var tagresource in ResourceGestalt.TagResources) { foreach (var fixup in tagresource.ResourceFixups) { fixup.Offset = (int)(fixup.Address.Value & 0x0FFFFFFF); fixup.Type = (int)(fixup.Address.Value >> 28) & 0xF; fixup.RawAddress = (int)fixup.Address.Value; } } break; } } }
public void ExtractWAV(CacheFile.IndexItem blamTag, string directory) { Console.WriteLine($"Extracting {blamTag.Name}.sound"); if (BlamSoundGestalt == null) { BlamSoundGestalt = PortingContextFactory.LoadSoundGestalt(CacheContext, ref BlamCache); } var blamContext = new CacheSerializationContext(ref BlamCache, blamTag); var sound = BlamCache.Deserializer.Deserialize <Sound>(blamContext); var xmaFileSize = BlamSoundGestalt.GetFileSize(sound.SoundReference.PitchRangeIndex, sound.SoundReference.PitchRangeCount); var xmaData = BlamCache.GetSoundRaw(sound.SoundReference.ZoneAssetHandle, xmaFileSize); if (xmaData == null) { Console.WriteLine($"ERROR: Failed to find sound data!"); return; } var OutDir = directory; string sound_name = blamTag.Name.Replace('\\', '_'); sound_name = Path.Combine(directory, sound_name); for (int pitchRangeIndex = sound.SoundReference.PitchRangeIndex; pitchRangeIndex < sound.SoundReference.PitchRangeIndex + sound.SoundReference.PitchRangeCount; pitchRangeIndex++) { var relativePitchRangeIndex = pitchRangeIndex - sound.SoundReference.PitchRangeIndex; var permutationCount = BlamSoundGestalt.GetPermutationCount(pitchRangeIndex); for (int i = 0; i < permutationCount; i++) { string permutationName = $"{sound_name}_{relativePitchRangeIndex}_{i}"; permutationName += ".mp3"; BlamSound blamSound = SoundConverter.ConvertGen3Sound(BlamCache, BlamSoundGestalt, sound, relativePitchRangeIndex, i, xmaData); using (EndianWriter output = new EndianWriter(new FileStream(permutationName, FileMode.Create, FileAccess.Write, FileShare.None), EndianFormat.BigEndian)) { output.WriteBlock(blamSound.Data); } } } }
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); }
private List <ShaderTemplateItem> CollectRmt2Info(Stream cacheStream, CacheFile.IndexItem bmRmt2Instance, List <string> bmMaps, List <string> bmArgs) { var edRmt2BestStats = new List <ShaderTemplateItem>(); var bmRmt2Context = new CacheSerializationContext(ref BlamCache, bmRmt2Instance); var bmRmt2 = BlamCache.Deserializer.Deserialize <RenderMethodTemplate>(bmRmt2Context); var bmPixlContext = new CacheSerializationContext(ref BlamCache, BlamCache.IndexItems.GetItemByID(bmRmt2.PixelShader.Index)); var bmPixl = BlamCache.Deserializer.Deserialize <PixelShader>(bmPixlContext); // loop trough all rmt2 and find the closest foreach (var edRmt2_ in Rmt2TagsInfo) { var rmt2Type = bmRmt2Instance.Name.Split("\\".ToArray())[1]; var edRmt2Tag = CacheContext.GetTag(edRmt2_.Key); // Ignore all rmt2 that are not of the same type. if (edRmt2Tag == null || !(edRmt2Tag.Name?.Contains(rmt2Type) ?? false)) { continue; } using (var reader = new EndianReader(cacheStream, true)) { reader.SeekTo(edRmt2Tag.HeaderOffset + edRmt2Tag.DefinitionOffset + 28); var edPixl = CacheContext.GetTag(reader.ReadInt32()); if (edPixl == null) { continue; } reader.SeekTo(edPixl.HeaderOffset + edPixl.DefinitionOffset + 0x4); var drawModeCount = reader.ReadInt32(); reader.SeekTo(edPixl.HeaderOffset + edPixl.DefinitionOffset + 0x14); var shaderCount = reader.ReadInt32(); if (bmPixl.DrawModes.Count > drawModeCount || bmPixl.Shaders.Count > shaderCount) { continue; } } int mapsCommon = 0; int argsCommon = 0; int mapsUncommon = 0; int argsUncommon = 0; int mapsMissing = 0; int argsMissing = 0; var edMaps_ = new List <string>(); var edArgs_ = new List <string>(); foreach (var a in edRmt2_.Value[0]) { edMaps_.Add(a); } foreach (var a in edRmt2_.Value[1]) { edArgs_.Add(a); } foreach (var a in bmMaps) { if (edMaps_.Contains(a)) { mapsCommon++; } } foreach (var a in bmMaps) { if (!edMaps_.Contains(a)) { mapsMissing++; } } foreach (var a in edMaps_) { if (!bmMaps.Contains(a)) { mapsUncommon++; } } foreach (var a in bmArgs) { if (edArgs_.Contains(a)) { argsCommon++; } } foreach (var a in bmArgs) { if (!edArgs_.Contains(a)) { argsMissing++; } } foreach (var a in edArgs_) { if (!bmArgs.Contains(a)) { argsUncommon++; } } edRmt2BestStats.Add(new ShaderTemplateItem { rmt2TagIndex = edRmt2_.Key, rmdfValuesMatchingCount = 0, mapsCountEd = edRmt2_.Value[0].Count, argsCountEd = edRmt2_.Value[1].Count, mapsCountBm = bmMaps.Count, argsCountBm = bmArgs.Count, mapsCommon = mapsCommon, argsCommon = argsCommon, mapsUncommon = mapsUncommon, argsUncommon = argsUncommon, mapsMissing = mapsMissing, argsMissing = argsMissing }); } return(edRmt2BestStats); }
private RenderMethod FixAnimationProperties(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, CacheFile blamCache, HaloOnlineCacheContext CacheContext, RenderMethod finalRm, RenderMethodTemplate edRmt2, RenderMethodTemplate bmRmt2, string blamTagName) { // finalRm is a H3 rendermethod with ported bitmaps, if (finalRm.ShaderProperties[0].AnimationProperties.Count == 0) { return(finalRm); } foreach (var properties in finalRm.ShaderProperties[0].AnimationProperties) { properties.InputName = ConvertStringId(properties.InputName); properties.RangeName = ConvertStringId(properties.RangeName); ConvertTagFunction(properties.Function); } var pixlTag = CacheContext.Deserialize(cacheStream, edRmt2.PixelShader); var edPixl = (PixelShader)pixlTag; var blamContext = new CacheSerializationContext(ref BlamCache, blamCache.IndexItems.Find(x => x.ID == bmRmt2.PixelShader.Index)); var bmPixl = BlamCache.Deserializer.Deserialize <PixelShader>(blamContext); // Make a collection of drawmodes and their DrawModeItem's // DrawModeItem are has info about all registers modified by functions for each drawmode. var bmPixlParameters = new Dictionary <int, List <ArgumentMapping> >(); // key is shader index // pixl side // For each drawmode, find its shader, and get all that shader's parameter. // Each parameter has a registerIndex, a registerType, and a registerName. // We'll use this to know which function acts on what shader and which registers var RegistersList = new Dictionary <int, string>(); foreach (var a in finalRm.ShaderProperties[0].ArgumentMappings) { if (!RegistersList.ContainsKey(a.RegisterIndex)) { RegistersList.Add(a.RegisterIndex, ""); } } var DrawModeIndex = -1; foreach (var a in bmPixl.DrawModes) { DrawModeIndex++; bmPixlParameters.Add(DrawModeIndex, new List <ArgumentMapping>()); if (a.Count == 0) { continue; } foreach (var b in bmPixl.Shaders[a.Offset].XboxParameters) { var ParameterName = BlamCache.Strings.GetItemByID(b.ParameterName.Index); bmPixlParameters[DrawModeIndex].Add(new ArgumentMapping { ShaderIndex = a.Offset, ParameterName = ParameterName, RegisterIndex = b.RegisterIndex, RegisterType = b.RegisterType }); } } // rm side var bmDrawmodesFunctions = new Dictionary <int, Unknown3Tagblock>(); // key is shader index DrawModeIndex = -1; foreach (var a in finalRm.ShaderProperties[0].DrawModes) { DrawModeIndex++; // These are not modes. This is an indireciton table of packed 10_6 shorts // from RMT2 ShaderDrawmodes to RegisterOffsets // register_offset = ShaderDrawmodes[current_drawmode].Offset var drawmodeRegisterOffset = (int)a.Offset; var drawmodeRegisterCount = (int)a.Count; var ArgumentMappingsIndexSampler = (byte)finalRm.ShaderProperties[0].Unknown3[drawmodeRegisterOffset].DataHandleSampler; var ArgumentMappingsCountSampler = finalRm.ShaderProperties[0].Unknown3[drawmodeRegisterOffset].DataHandleSampler >> 8; var ArgumentMappingsIndexUnknown = (byte)finalRm.ShaderProperties[0].Unknown3[drawmodeRegisterOffset].DataHandleUnknown; var ArgumentMappingsCountUnknown = finalRm.ShaderProperties[0].Unknown3[drawmodeRegisterOffset].DataHandleUnknown >> 8; var ArgumentMappingsIndexVector = (byte)finalRm.ShaderProperties[0].Unknown3[drawmodeRegisterOffset].DataHandleVector; var ArgumentMappingsCountVector = finalRm.ShaderProperties[0].Unknown3[drawmodeRegisterOffset].DataHandleVector >> 8; var ArgumentMappings = new List <ArgumentMapping>(); for (int j = 0; j < ArgumentMappingsCountSampler / 4; j++) { ArgumentMappings.Add(new ArgumentMapping { RegisterIndex = finalRm.ShaderProperties[0].ArgumentMappings[ArgumentMappingsIndexSampler + j].RegisterIndex, ArgumentIndex = finalRm.ShaderProperties[0].ArgumentMappings[ArgumentMappingsIndexSampler + j].ArgumentIndex, // i don't think i can use it to match stuf ArgumentMappingsTagblockIndex = ArgumentMappingsIndexSampler + j, RegisterType = TagTool.Shaders.ShaderParameter.RType.Sampler, ShaderIndex = drawmodeRegisterOffset, // WARNING i think drawmodes in rm aren't the same as in pixl, because rm drawmodes can point to a global shader . // say rm.drawmodes[17]'s value is 13, pixl.drawmodes[17] would typically be 12 }); } for (int j = 0; j < ArgumentMappingsCountUnknown / 4; j++) { ArgumentMappings.Add(new ArgumentMapping { RegisterIndex = finalRm.ShaderProperties[0].ArgumentMappings[ArgumentMappingsIndexUnknown + j].RegisterIndex, ArgumentIndex = finalRm.ShaderProperties[0].ArgumentMappings[ArgumentMappingsIndexUnknown + j].ArgumentIndex, ArgumentMappingsTagblockIndex = ArgumentMappingsIndexUnknown + j, RegisterType = TagTool.Shaders.ShaderParameter.RType.Vector, ShaderIndex = drawmodeRegisterOffset, // it's something else, uses a global shader or some shit, one water shader pointed to a vtsh in rasg, but not in H3, maybe coincidence // yeah guaranteed rmdf's glvs or rasg shaders }); } for (int j = 0; j < ArgumentMappingsCountVector / 4; j++) { ArgumentMappings.Add(new ArgumentMapping { RegisterIndex = finalRm.ShaderProperties[0].ArgumentMappings[ArgumentMappingsIndexVector + j].RegisterIndex, ArgumentIndex = finalRm.ShaderProperties[0].ArgumentMappings[ArgumentMappingsIndexVector + j].ArgumentIndex, ArgumentMappingsTagblockIndex = ArgumentMappingsIndexVector + j, RegisterType = TagTool.Shaders.ShaderParameter.RType.Vector, ShaderIndex = drawmodeRegisterOffset, }); } bmDrawmodesFunctions.Add(DrawModeIndex, new Unknown3Tagblock { Unknown3Index = drawmodeRegisterOffset, // not shader index for rm and rmt2 Unknown3Count = drawmodeRegisterCount, // should always be 4 for enabled drawmodes ArgumentMappingsIndexSampler = ArgumentMappingsIndexSampler, ArgumentMappingsCountSampler = ArgumentMappingsCountSampler, ArgumentMappingsIndexUnknown = ArgumentMappingsIndexUnknown, // no clue what it's used for, global shaders? i know one of the drawmodes will use one or more shaders from glvs, no idea if always or based on something ArgumentMappingsCountUnknown = ArgumentMappingsCountUnknown, ArgumentMappingsIndexVector = ArgumentMappingsIndexVector, ArgumentMappingsCountVector = ArgumentMappingsCountVector, ArgumentMappings = ArgumentMappings }); } DrawModeIndex = -1; foreach (var a in bmDrawmodesFunctions) { DrawModeIndex++; if (a.Value.Unknown3Count == 0) { continue; } foreach (var b in a.Value.ArgumentMappings) { foreach (var c in bmPixlParameters[a.Key]) { if (b.RegisterIndex == c.RegisterIndex && b.RegisterType == c.RegisterType) { b.ParameterName = c.ParameterName; break; } } } } // // Now that we know which register is what for each drawmode, find its halo online equivalent register indexes based on register name. // // This is where it gets tricky because drawmodes count changed in HO. foreach (var a in bmDrawmodesFunctions) { if (a.Value.Unknown3Count == 0) { continue; } foreach (var b in a.Value.ArgumentMappings) { foreach (var c in edPixl.Shaders[edPixl.DrawModes[a.Key].Offset].PCParameters) { var ParameterName = CacheContext.StringIdCache.GetString(c.ParameterName); if (ParameterName == b.ParameterName && b.RegisterType == c.RegisterType) { if (RegistersList[b.RegisterIndex] == "") { RegistersList[b.RegisterIndex] = $"{c.RegisterIndex}"; } else { RegistersList[b.RegisterIndex] = $"{RegistersList[b.RegisterIndex]},{c.RegisterIndex}"; } b.EDRegisterIndex = c.RegisterIndex; } } } } // DEBUG draw registers // DEBUG check for invalid registers foreach (var a in bmDrawmodesFunctions) { if (a.Value.Unknown3Count == 0) { continue; } foreach (var b in a.Value.ArgumentMappings) { finalRm.ShaderProperties[0].ArgumentMappings[b.ArgumentMappingsTagblockIndex].RegisterIndex = (short)b.EDRegisterIndex; } } // one final check // Gather all register indexes from pixl tag. Then check against all the converted register indexes. // It should detect registers that are invalid and would crash, but it does not verify if the register is valid. var validEDRegisters = new List <int>(); foreach (var a in edPixl.Shaders) { foreach (var b in a.PCParameters) { if (!validEDRegisters.Contains(b.RegisterIndex)) { validEDRegisters.Add(b.RegisterIndex); } } } foreach (var a in finalRm.ShaderProperties[0].ArgumentMappings) { if (!validEDRegisters.Contains((a.RegisterIndex))) { // Display a warning // Console.WriteLine($"INVALID REGISTERS IN TAG {blamTagName}!"); // Abort, disable functions finalRm.ShaderProperties[0].Unknown = new List <RenderMethod.ShaderProperty.UnknownBlock1>(); // no idea what it does, but it crashes sometimes if it's null. on Shrine, it's the shader loop effect finalRm.ShaderProperties[0].AnimationProperties = new List <RenderMethod.AnimationPropertiesBlock>(); finalRm.ShaderProperties[0].ArgumentMappings = new List <RenderMethod.ShaderProperty.ArgumentMapping>(); finalRm.ShaderProperties[0].Unknown3 = new List <RenderMethod.ShaderProperty.UnknownBlock3>(); foreach (var b in edRmt2.RegisterOffsets) // stops crashing for some shaders if the drawmodes count is still the same { finalRm.ShaderProperties[0].Unknown3.Add(new RenderMethod.ShaderProperty.UnknownBlock3()); } return(finalRm); } } return(finalRm); }
private RenderMethod ConvertRenderMethod(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, RenderMethod finalRm, string blamTagName) { // Verify that the ShaderMatcher is ready to use if (!Matcher.IsInitialized()) { Matcher.Init(cacheStream, CacheContext, BlamCache); } // Set flags Matcher.SetMS30Flag(cacheStream, FlagIsSet(PortingFlags.Ms30)); // finalRm.ShaderProperties[0].ShaderMaps are all ported bitmaps // finalRm.BaseRenderMethod is a H3 tag // finalRm.ShaderProperties[0].Template is a H3 tag // TODO hardcode shader values such as argument changes for specific shaders var bmMaps = new List <string>(); var bmArgs = new List <string>(); var edMaps = new List <string>(); var edArgs = new List <string>(); // Reset rmt2 preset var pRmt2 = 0; // Make a template of ShaderProperty, with the correct bitmaps and arguments counts. var newShaderProperty = new RenderMethod.ShaderProperty { ShaderMaps = new List <RenderMethod.ShaderProperty.ShaderMap>(), Arguments = new List <RenderMethod.ShaderProperty.Argument>() }; // Get a simple list of bitmaps and arguments names var bmRmt2Instance = BlamCache.IndexItems.Find(x => x.ID == finalRm.ShaderProperties[0].Template.Index); var blamContext = new CacheSerializationContext(ref BlamCache, bmRmt2Instance); var bmRmt2 = BlamCache.Deserializer.Deserialize <RenderMethodTemplate>(blamContext); // Get a simple list of H3 bitmaps and arguments names foreach (var a in bmRmt2.SamplerArguments) { bmMaps.Add(BlamCache.Strings.GetItemByID(a.Name.Index)); } foreach (var a in bmRmt2.VectorArguments) { bmArgs.Add(BlamCache.Strings.GetItemByID(a.Name.Index)); } // Find a HO equivalent rmt2 var edRmt2Instance = Matcher.FixRmt2Reference(cacheStream, blamTagName, bmRmt2Instance, bmRmt2, bmMaps, bmArgs); if (edRmt2Instance == null) { return(CacheContext.Deserialize <Shader>(cacheStream, CacheContext.GetTag <Shader>(@"shaders\invalid"))); } var edRmt2Tagname = edRmt2Instance.Name ?? $"0x{edRmt2Instance.Index:X4}"; // pRmsh pRmt2 now potentially have a new value if (pRmt2 != 0) { if (CacheContext.TagCache.Index.Contains(pRmt2)) { var a = CacheContext.GetTag(pRmt2); if (a != null) { edRmt2Instance = a; } } } var edRmt2 = CacheContext.Deserialize <RenderMethodTemplate>(cacheStream, edRmt2Instance); foreach (var a in edRmt2.SamplerArguments) { edMaps.Add(CacheContext.StringIdCache.GetString(a.Name)); } foreach (var a in edRmt2.VectorArguments) { edArgs.Add(CacheContext.StringIdCache.GetString(a.Name)); } // The bitmaps are default textures. // Arguments are probably default values. I took the values that appeared the most frequently, assuming they are the default value. foreach (var a in edMaps) { var newBitmap = Matcher.GetDefaultBitmapTag(a); if (!CacheContext.TagCache.Index.Contains(pRmt2)) { newBitmap = @"shaders\default_bitmaps\bitmaps\default_detail"; // would only happen for removed shaders } CachedTagInstance bitmap = null; try { bitmap = CacheContext.GetTag <Bitmap>(newBitmap); } catch { bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag($"{newBitmap}.bitm")[0]); } newShaderProperty.ShaderMaps.Add( new RenderMethod.ShaderProperty.ShaderMap { Bitmap = bitmap }); } foreach (var a in edArgs) { newShaderProperty.Arguments.Add(Matcher.DefaultArgumentsValues(a)); } // Reorder blam bitmaps to match the HO rmt2 order // Reorder blam arguments to match the HO rmt2 order foreach (var eM in edMaps) { foreach (var bM in bmMaps) { if (eM == bM) { newShaderProperty.ShaderMaps[edMaps.IndexOf(eM)] = finalRm.ShaderProperties[0].ShaderMaps[bmMaps.IndexOf(bM)]; } } } foreach (var eA in edArgs) { foreach (var bA in bmArgs) { if (eA == bA) { newShaderProperty.Arguments[edArgs.IndexOf(eA)] = finalRm.ShaderProperties[0].Arguments[bmArgs.IndexOf(bA)]; } } } // Remove some tagblocks // finalRm.Unknown = new List<RenderMethod.UnknownBlock>(); // hopefully not used; this gives rmt2's name. They correspond to the first tagblocks in rmdf, they tell what the shader does finalRm.ImportData = new List <RenderMethod.ImportDatum>(); // most likely not used finalRm.ShaderProperties[0].Template = edRmt2Instance; finalRm.ShaderProperties[0].ShaderMaps = newShaderProperty.ShaderMaps; finalRm.ShaderProperties[0].Arguments = newShaderProperty.Arguments; Matcher.FixRmdfTagRef(finalRm); FixAnimationProperties(cacheStream, resourceStreams, BlamCache, CacheContext, finalRm, edRmt2, bmRmt2, blamTagName); // Fix any null bitmaps, caused by bitm port failure foreach (var a in finalRm.ShaderProperties[0].ShaderMaps) { if (a.Bitmap != null) { continue; } var defaultBitmap = Matcher.GetDefaultBitmapTag(edMaps[finalRm.ShaderProperties[0].ShaderMaps.IndexOf(a)]); try { a.Bitmap = CacheContext.GetTag <Bitmap>(defaultBitmap); } catch { a.Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag($"{defaultBitmap}.bitm")[0]); } } if (Matcher.RmhgUnknownTemplates.Contains(edRmt2Instance.Name)) { if (finalRm.ShaderProperties[0].Unknown.Count == 0) { finalRm.ShaderProperties[0].Unknown = new List <RenderMethod.ShaderProperty.UnknownBlock1> { new RenderMethod.ShaderProperty.UnknownBlock1 { Unknown = 1 } } } } ; switch (blamTagName) { case @"levels\dlc\chillout\shaders\chillout_flood_godrays" when finalRm is ShaderHalogram: { // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { if (CacheContext.GetString(edRmt2.SamplerArguments[i].Name) == "overlay_map") { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\dlc\chillout\bitmaps\chillout_flood_godrays.bitmap")[0]); break; } } // Fixup arguments for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; switch (CacheContext.GetString(templateArg.Name)) { case "overlay_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 0f, 0f }; break; case "overlay_tint": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.3764706f, 0.7254902f, 0.9215687f, 1f }; break; case "overlay_intensity": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1.25f, 1.25f, 1.25f, 1.25f }; break; } } break; } case @"levels\dlc\chillout\shaders\chillout_invis_godrays" when finalRm is ShaderHalogram: { // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { if (CacheContext.GetString(edRmt2.SamplerArguments[i].Name) == "overlay_map") { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\dlc\chillout\bitmaps\chillout_invis_godrays.bitmap")[0]); break; } } // Fixup arguments for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; switch (CacheContext.GetString(templateArg.Name)) { case "overlay_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 0f, 0f }; break; case "overlay_tint": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.3058824f, 0.7098039f, 0.937255f, 1f }; break; case "overlay_intensity": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 1f, 1f }; break; } } break; } case @"levels\solo\020_base\lights\light_volume_hatlight" when finalRm is ShaderHalogram: { // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { if (CacheContext.GetString(edRmt2.SamplerArguments[i].Name) == "overlay_map") { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\solo\020_base\bitmaps\light_volume_hatlight.bitmap")[0]); break; } } // Fixup arguments for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; switch (CacheContext.GetString(templateArg.Name)) { case "overlay_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 2f, 1f, 0f, 0f }; break; case "overlay_tint": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.9960785f, 1f, 0.8039216f, 1f }; break; case "overlay_intensity": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 1f, 1f }; break; } } break; } case @"objects\vehicles\ghost\shaders\ghost_dash_zcam" when finalRm is ShaderHalogram: case @"objects\weapons\rifle\sniper_rifle\shaders\scope_alpha" when finalRm is ShaderHalogram: finalRm.InputVariable = TagTool.Tags.TagMapping.VariableTypeValue.ParticleRandom1; finalRm.RangeVariable = TagTool.Tags.TagMapping.VariableTypeValue.ParticleAge; break; case @"levels\dlc\armory\shaders\concrete_floor_smooth" when finalRm is Shader: { // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { if (CacheContext.GetString(edRmt2.SamplerArguments[i].Name) == "bump_map") { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\dlc\armory\bitmaps\concrete_floor_bump.bitmap")[0]); break; } } break; } case @"levels\dlc\sidewinder\shaders\side_tree_branch_snow" when finalRm is Shader: for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; if (CacheContext.GetString(templateArg.Name) == "env_tint_color") { finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0f, 0f, 0f, 0f }; break; } } break; case @"levels\multi\isolation\sky\shaders\skydome" when finalRm is Shader: for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; if (CacheContext.GetString(templateArg.Name) == "albedo_color") { finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.447059f, 0.376471f, 0.898039f, 1.0f }; break; } } break; case @"levels\multi\snowbound\shaders\cov_grey_icy" when finalRm is Shader: { // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { switch (CacheContext.GetString(edRmt2.SamplerArguments[i].Name)) { case "base_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_dif.bitmap")[0]); } catch { } break; case "detail_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_icy.bitmap")[0]); } catch { } break; case "bump_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_platebump.bitmap")[0]); } catch { } break; case "bump_detail_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\for_metal_greytech_bump.bitmap")[0]); } catch { } break; } } // Fixup arguments for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; switch (CacheContext.GetString(templateArg.Name)) { case "base_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 0f, 0f }; break; case "detail_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1.5f, 1.5f, 0f, 0f }; break; case "albedo_color": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.554902f, 0.5588236f, 0.5921569f, 1f }; break; case "bump_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 0f, 0f }; break; case "bump_detail_map": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 2f, 2f, 0f, 0f }; break; case "diffuse_coefficient": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.4f, 0.4f, 0.4f, 0.4f }; break; case "specular_coefficient": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 1f, 1f }; break; case "roughness": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.2f, 0.2f, 0.2f, 0.2f }; break; case "analytical_specular_contribution": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.2f, 0.2f, 0.2f, 0.2f }; break; case "area_specular_contribution": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.1f, 0.1f, 0.1f, 0.1f }; break; case "environment_map_specular_contribution": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.15f, 0.15f, 0.15f, 0.15f }; break; case "specular_tint": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0.8431373f, 0.8470589f, 0.8117648f, 1f }; break; } } break; } case @"levels\multi\snowbound\shaders\rock_cliffs" when finalRm is Shader: case @"levels\multi\snowbound\shaders\rock_rocky" when finalRm is Shader: case @"levels\multi\snowbound\shaders\rock_rocky_icy" when finalRm is Shader: { // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { switch (CacheContext.GetString(edRmt2.SamplerArguments[i].Name)) { case "base_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_horiz.bitmap")[0]); } catch { } break; case "detail_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_granite_detail.bitmap")[0]); } catch { } break; case "detail_map2": try { switch (blamTagName) { case @"levels\multi\snowbound\shaders\rock_rocky_icy": finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_icy_blend.bitmap")[0]); break; default: finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_cliff_dif.bitmap")[0]); break; } } catch { } break; case "bump_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_horiz_bump.bitmap")[0]); } catch { } break; case "bump_detail_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_granite_bump.bitmap")[0]); } catch { } break; case "height_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"levels\multi\snowbound\bitmaps\rock_horiz_parallax.bitmap")[0]); } catch { } break; case "environment_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = ConvertTag(cacheStream, resourceStreams, ParseLegacyTag(@"shaders\default_bitmaps\bitmaps\color_white.bitmap")[0]); } catch { } break; } } // Fixup arguments for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; switch (CacheContext.GetString(templateArg.Name)) { case "base_map": switch (blamTagName) { case @"levels\multi\snowbound\shaders\rock_cliffs": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 16f, 2f, 0f, 0.5f }; break; } break; case "detail_map": switch (blamTagName) { case @"levels\multi\snowbound\shaders\rock_cliffs": case @"levels\multi\snowbound\shaders\rock_rocky": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 320f, 20f, 0f, 0f }; break; } break; case "detail_map2": switch (blamTagName) { case @"levels\multi\snowbound\shaders\rock_cliffs": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1f, 1f, 0f, 0f }; break; } break; case "bump_detail_map": switch (blamTagName) { case @"levels\multi\snowbound\shaders\rock_cliffs": case @"levels\multi\snowbound\shaders\rock_rocky": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 320f, 20f, 0f, 0f }; break; } break; case "diffuse_coefficient": switch (blamTagName) { case @"levels\multi\snowbound\shaders\rock_rocky_icy": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 1.2f, 1.2f, 1.2f, 1.2f }; break; } break; } } break; } case @"levels\multi\snowbound\shaders\cov_metalplates_icy" when finalRm is Shader: // Fixup bitmaps for (var i = 0; i < edRmt2.SamplerArguments.Count; i++) { switch (CacheContext.GetString(edRmt2.SamplerArguments[i].Name)) { case "detail_map": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = CacheContext.GetTag <Bitmap>(@"levels\multi\snowbound\bitmaps\for_metal_greytech_icy4"); } catch { } break; case "detail_map2": try { finalRm.ShaderProperties[0].ShaderMaps[i].Bitmap = CacheContext.GetTag <Bitmap>(@"levels\multi\snowbound\bitmaps\for_metal_greytech_icy3"); } catch { } break; } } break; case @"levels\multi\snowbound\shaders\invis_col_glass" when finalRm is Shader: // Fixup arguments for (var i = 0; i < edRmt2.VectorArguments.Count; i++) { var templateArg = edRmt2.VectorArguments[i]; switch (CacheContext.GetString(templateArg.Name)) { case "albedo_color": finalRm.ShaderProperties[0].Arguments[i].Values = new float[] { 0f, 0f, 0f, 0f }; break; } } break; } return(finalRm); }