private void FindClosestShaderTemplate(CachedTag sourceRmt2) { // somehow build a list of rmt2 of the same type List <CachedTag> candidateTemplates = new List <CachedTag>(); // defined method search order, ignore last method from ms30 List <int> methodOrder = new List <int> { 0, 2, 3, 1, 6, 4, 5, 7, 8, 9, 10 }; Dictionary <CachedTag, int> matchLevelDictionary = new Dictionary <CachedTag, int>(); Rmt2Descriptor sourceRmt2Desc; if (!Rmt2Descriptor.TryParse(sourceRmt2.Name, out sourceRmt2Desc)) { return; } while (candidateTemplates.Count != 0) { var template = candidateTemplates.Last(); Rmt2Descriptor destRmt2Desc; if (!Rmt2Descriptor.TryParse(template.Name, out destRmt2Desc)) { candidateTemplates.Remove(template); matchLevelDictionary[template] = 0; } else { var matchLevel = 0; for (int i = 0; i < methodOrder.Count; i++) { var methodIndex = methodOrder[i]; // we need to define a ordering on the method options, so that there is a single best rmt2 if (sourceRmt2Desc.Options[methodIndex] == destRmt2Desc.Options[methodIndex]) { matchLevel++; } else { break; } } matchLevelDictionary[template] = matchLevel; } } CachedTag bestRmt2 = null; var bestScore = -1; }
/// <summary> /// Find the closest template in the base cache to the input template. /// </summary> private CachedTag FindClosestTemplate(CachedTag sourceRmt2Tag, RenderMethodTemplate sourceRmt2) { Debug.Assert(IsInitialized); Rmt2Descriptor sourceRmt2Desc; if (!Rmt2Descriptor.TryParse(sourceRmt2Tag.Name, out sourceRmt2Desc)) { throw new ArgumentException($"Invalid rmt2 name '{sourceRmt2Tag.Name}'", nameof(sourceRmt2Tag)); } var relevantRmt2s = new List <Rmt2Pairing>(); foreach (var rmt2Tag in BaseCache.TagCache.NonNull().Where(tag => tag.IsInGroup("rmt2"))) { Rmt2Descriptor destRmt2Desc; if (!Rmt2Descriptor.TryParse(rmt2Tag.Name, out destRmt2Desc)) { continue; } // ignore ms30 templates if desired if (!UseMs30 && destRmt2Desc.IsMs30) { continue; } // ignore templates that are not of the same type if (destRmt2Desc.Type != sourceRmt2Desc.Type) { continue; } // match the options from the rmt2 tag names int commonOptions = 0; for (int i = 0; i < sourceRmt2Desc.Options.Length; i++) { if (sourceRmt2Desc.Options[i] == destRmt2Desc.Options[i]) { commonOptions++; } } // if we found an exact match, return it if (commonOptions == sourceRmt2Desc.Options.Length) { return(rmt2Tag); } // add it to the list to be considered relevantRmt2s.Add(new Rmt2Pairing() { CommonOptions = commonOptions, DestTag = rmt2Tag, SourceTag = sourceRmt2Tag }); } // if we've reached here, we haven't found an extract match. // now we need to consider other factors such as which options they have, which parameters are missing etc.. // whatever can be used to narrow it down. foreach (var pairing in relevantRmt2s) { var rmt2 = GetTemplate(pairing.DestTag); pairing.RealParams = MatchParameterBlocks(sourceRmt2.RealParameterNames, rmt2.RealParameterNames); pairing.IntParams = MatchParameterBlocks(sourceRmt2.IntegerParameterNames, rmt2.IntegerParameterNames); pairing.BoolParams = MatchParameterBlocks(sourceRmt2.BooleanParameterNames, rmt2.BooleanParameterNames); pairing.TextureParams = MatchParameterBlocks(sourceRmt2.TextureParameterNames, rmt2.TextureParameterNames); } // finally order by some criteria var ordered = relevantRmt2s .OrderBy(x => x.CommonOptions); //.ThenByDescending(x => x.MissingFromDest); // return the best rmt2 or the default if one could not be found (only when a template type is not in the base cache) var bestRmt2 = ordered.LastOrDefault()?.DestTag; if (bestRmt2 == null) { return(BaseCache.GetTag(DefaultTemplate)); } return(bestRmt2); }