using System; using System.Collections; using System.Linq; using LibMMD.Model; using UnityEngine; namespace LibMMD.Unity3D { internal sealed class MmdMaterialController { internal IEnumerator LoadAsync(MmdModel model, MaterialLoader loader, MmdUnityConfig config, MmdModelResourceCache.Entry cacheEntry, UnityEngine.Material[] currentMaterials, Action completed) { if (cacheEntry != null && cacheEntry.Materials != null) { var materials = cacheEntry.Materials; if (materials.Length != model.Parts.Length) { materials = new UnityEngine.Material[model.Parts.Length]; cacheEntry.Materials = materials; } for (var i = 0; i < materials.Length; i++) { if (materials[i] == null) { var index = i; var materialLoader = loader.LoadMaterialAsync(model.Parts[i].Material, config, value => materials[index] = value); while (materialLoader.MoveNext()) yield return materialLoader.Current; } else loader.RefreshMaterialConfig(model.Parts[i].Material, config, materials[i]); yield return null; } ReorderRender(materials); completed(materials); yield break; } Release(currentMaterials, cacheEntry); var loaded = new UnityEngine.Material[model.Parts.Length]; for (var i = 0; i < loaded.Length; i++) { var index = i; var materialLoader = loader.LoadMaterialAsync(model.Parts[i].Material, config, value => loaded[index] = value); while (materialLoader.MoveNext()) yield return materialLoader.Current; yield return null; } ReorderRender(loaded); if (cacheEntry != null) cacheEntry.Materials = loaded; completed(loaded); } internal void Refresh(MmdModel model, MaterialLoader loader, UnityEngine.Material[] materials, MmdUnityConfig config) { if (model == null) return; if (materials.Length != model.Parts.Length) throw new ArgumentException("UpdateMaterialsConfig: material count should be equal to model part count"); for (var i = 0; i < model.Parts.Length; i++) loader.RefreshMaterialConfig(model.Parts[i].Material, config, materials[i]); } internal void Release(UnityEngine.Material[] materials, MmdModelResourceCache.Entry cacheEntry) { if (materials == null || cacheEntry != null) return; foreach (var material in materials) UnityEngine.Object.Destroy(material); } private static void ReorderRender(UnityEngine.Material[] materials) { if (materials == null || materials.Length == 0) return; var order = materials.Where(material => material != null).OrderBy(material => material.renderQueue); var lastQueue = int.MinValue; foreach (var material in order) { if (lastQueue >= material.renderQueue) material.renderQueue = ++lastQueue; else lastQueue = material.renderQueue; } } } }