#nullable enable using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using nadena.dev.ndmf.preview; using UnityEngine; namespace nadena.dev.modular_avatar.core.editor { internal class RemoveVertexColorPreview : IRenderFilter { private static string ToPathString(ComputeContext ctx, Transform t) { return string.Join("/", ctx.ObservePath(t).Select(t2 => t2.gameObject.name).Reverse()); } public ImmutableList GetTargetGroups(ComputeContext context) { var roots = context.GetAvatarRoots(); var removers = roots .SelectMany(r => context.GetComponentsInChildren(r, true)) .Select(rvc => (ToPathString(context, rvc.transform), context.Observe(rvc, r => r.Mode) == ModularAvatarRemoveVertexColor.RemoveMode.Remove)) .OrderBy(pair => pair.Item1) .ToList(); var targets = roots.SelectMany( r => context.GetComponentsInChildren(r, true) .Concat( context.GetComponentsInChildren(r, true) .SelectMany(mf => context.GetComponents(mf.gameObject)) ) ); targets = targets.Where(target => { var stringPath = ToPathString(context, target.transform); var index = removers.BinarySearch((stringPath, true)); if (index >= 0) { // There is a component on this mesh return true; } var priorIndex = ~index - 1; if (priorIndex < 0) return false; // no match var (maybeParent, mode) = removers[priorIndex]; if (!stringPath.StartsWith(maybeParent)) return false; // no parent matched return mode; }); return targets.Select(RenderGroup.For).ToImmutableList(); } public Task Instantiate(RenderGroup group, IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context) { Dictionary conversionMap = new(); foreach (var (_, proxy) in proxyPairs) { Component c = proxy; if (!(c is SkinnedMeshRenderer)) { c = context.GetComponent(proxy.gameObject); } if (c == null) continue; RemoveVertexColorPass.ForceRemove(_ => false, c, conversionMap); } return Task.FromResult(new Node(conversionMap.Values.FirstOrDefault())); } private class Node : IRenderFilterNode { private readonly Mesh? _theMesh; public Node(Mesh? theMesh) { _theMesh = theMesh; } public Task Refresh(IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context, RenderAspects updatedAspects) { if (updatedAspects.HasFlag(RenderAspects.Mesh)) return Task.FromResult(null); if (_theMesh == null) return Task.FromResult(null); return Task.FromResult(this); } public RenderAspects WhatChanged => RenderAspects.Mesh; public void Dispose() { if (_theMesh != null) Object.DestroyImmediate(_theMesh); } public void OnFrame(Renderer original, Renderer proxy) { if (_theMesh == null) return; switch (proxy) { case SkinnedMeshRenderer smr: smr.sharedMesh = _theMesh; break; default: { var mf = proxy.GetComponent(); if (mf != null) mf.sharedMesh = _theMesh; break; } } } } } }