TakeOwnershipFunc

This commit is contained in:
ousttrue
2021-03-09 13:09:53 +09:00
parent 16764421ee
commit 397bd5869b
10 changed files with 184 additions and 111 deletions

View File

@@ -51,6 +51,8 @@ namespace UniGLTF
// Root GameObject is main object
context.SetMainObject(loaded.Root);
}
return true;
});
}
}

View File

@@ -206,6 +206,14 @@ namespace UniGLTF
}
}
}
void RemoveMesh(Mesh mesh)
{
var index = Meshes.FindIndex(x => x.Mesh == mesh);
if (index >= 0)
{
Meshes.RemoveAt(index);
}
}
public void EnableUpdateWhenOffscreen()
{
@@ -266,27 +274,44 @@ namespace UniGLTF
/// Root ヒエラルキーで使っているリソース
/// </summary>
/// <returns></returns>
public virtual void TransferOwnership(Action<UnityEngine.Object> add)
public virtual void TransferOwnership(TakeOwnershipFunc take)
{
var list = new List<UnityEngine.Object>();
foreach (var mesh in Meshes)
{
add(mesh.Mesh);
if (take(mesh.Mesh))
{
list.Add(mesh.Mesh);
}
}
foreach (var x in list)
{
RemoveMesh(x as Mesh);
}
Meshes.Clear();
TextureFactory.TransferOwnership(add);
MaterialFactory.TransferOwnership(add);
TextureFactory.TransferOwnership(take);
MaterialFactory.TransferOwnership(take);
list.Clear();
foreach (var animation in AnimationClips)
{
add(animation);
if (take(animation))
{
list.Add(animation);
}
}
foreach (var x in list)
{
AnimationClips.Remove(x as AnimationClip);
}
AnimationClips.Clear();
if (m_ownRoot && Root != null)
{
add(Root);
m_ownRoot = false;
if (take(Root))
{
// 所有権(Dispose権)
m_ownRoot = false;
}
}
}
@@ -302,7 +327,11 @@ namespace UniGLTF
public UnityResourceDestroyer DisposeOnGameObjectDestroyed()
{
var destroyer = Root.AddComponent<UnityResourceDestroyer>();
TransferOwnership(destroyer.Resources.Add);
TransferOwnership(o =>
{
destroyer.Resources.Add(o);
return true;
});
return destroyer;
}
}

View File

@@ -75,6 +75,15 @@ namespace UniGLTF
List<MaterialLoadInfo> m_materials = new List<MaterialLoadInfo>();
public IReadOnlyList<MaterialLoadInfo> Materials => m_materials;
void Remove(Material material)
{
var index = m_materials.FindIndex(x => x.Asset == material);
if (index >= 0)
{
m_materials.RemoveAt(index);
}
}
public void Dispose()
{
@@ -82,6 +91,7 @@ namespace UniGLTF
{
if (!x.UseExternal)
{
// 外部の '.asset' からロードしていない
#if VRM_DEVELOP
Debug.Log($"Destroy {x.Asset}");
#endif
@@ -90,16 +100,28 @@ namespace UniGLTF
}
}
public void TransferOwnership(Action<UnityEngine.Object> add)
/// <summary>
/// 所有権(Dispose権)を移譲する
/// </summary>
/// <param name="take"></param>
public void TransferOwnership(TakeOwnershipFunc take)
{
var list = new List<Material>();
foreach (var x in m_materials)
{
if (!x.UseExternal)
{
add(x.Asset);
// 外部の '.asset' からロードしていない
if (take(x.Asset))
{
list.Add(x.Asset);
}
}
}
m_materials.Clear();
foreach (var x in list)
{
Remove(x);
}
}
public Material GetMaterial(int index)

View File

@@ -0,0 +1,13 @@
namespace UniGLTF
{
/// <summary>
/// 所有権を移動する関数。
///
/// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
/// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
///
/// </summary>
/// <param name="o">対象のオブジェクト</param>
/// <returns>所有権が移動したらtrue</returns>
public delegate bool TakeOwnershipFunc(UnityEngine.Object o);
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ab2b998b9235dc94a90ccaf2e40a50a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -98,15 +98,23 @@ namespace UniGLTF
m_textureCache.Clear();
}
public void TransferOwnership(Action<UnityEngine.Object> add)
/// <summary>
/// 所有権(Dispose権)を移譲する
/// </summary>
/// <param name="take"></param>
public void TransferOwnership(TakeOwnershipFunc take)
{
var keys = new List<string>();
foreach (var x in m_textureCache)
{
if (x.Value.IsUsed && !x.Value.IsExternal)
{
keys.Add(x.Key);
add(x.Value.Texture);
// マテリアルから参照されていて
// 外部のAssetからロードしていない。
if (take(x.Value.Texture))
{
keys.Add(x.Key);
}
}
}
foreach (var x in keys)

View File

@@ -10,10 +10,14 @@ namespace VRM
public class VRMEditorImporterContext
{
VRMImporterContext m_context;
UnityPath m_prefabPath;
List<UnityPath> m_paths = new List<UnityPath>();
public VRMEditorImporterContext(VRMImporterContext context)
public VRMEditorImporterContext(VRMImporterContext context, UnityPath prefabPath)
{
m_context = context;
m_prefabPath = prefabPath;
}
public bool AvoidOverwriteAndLoad(UnityPath assetPath, UnityEngine.Object o)
@@ -57,7 +61,7 @@ namespace VRM
return false;
}
public UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o, bool meshAsSubAsset)
public UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o)
{
if (o is BlendShapeAvatar
|| o is BlendShapeClip)
@@ -96,7 +100,7 @@ namespace VRM
var texturePath = textureDir.Child(o.name.EscapeFilePath() + ".asset");
return texturePath;
}
else if (o is Mesh && !meshAsSubAsset)
else if (o is Mesh)
{
var meshDir = prefabPath.GetAssetFolder(".Meshes");
var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset");
@@ -146,85 +150,64 @@ namespace VRM
TextureExtractor.ExtractTextures(assetPath.Value, subAssets, _ => { }, onTextureReloaded);
}
public void SaveAsAsset(UnityPath prefabPath, bool meshAsSubAsset = false)
bool SaveAsAsset(UnityEngine.Object o)
{
m_context.ShowMeshes();
//var prefabPath = PrefabPath;
if (prefabPath.IsFileExists)
if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o)))
{
// clear SubAssets
foreach (var x in prefabPath.GetSubAssets().Where(x => !(x is GameObject) && !(x is Component)))
// already exists. not dispose
return true;
}
var assetPath = GetAssetPath(m_prefabPath, o);
if (assetPath.IsNull)
{
return false;
}
if (assetPath.IsFileExists)
{
if (AvoidOverwriteAndLoad(assetPath, o))
{
GameObject.DestroyImmediate(x, true);
// 上書きせずに既存のアセットからロードして置き換えた
return true;
}
}
// アセットとして書き込む
assetPath.Parent.EnsureFolder();
assetPath.CreateAsset(o);
m_paths.Add(assetPath);
// 所有権が移動
return true;
}
public void SaveAsAsset()
{
m_context.ShowMeshes();
//
// save sub assets
//
var paths = new List<UnityPath>(){
prefabPath
};
// backup
var root = m_context.Root;
m_context.TransferOwnership(o =>
{
if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o)))
{
// already exists
return;
}
var assetPath = GetAssetPath(prefabPath, o, meshAsSubAsset);
if (!assetPath.IsNull)
{
if (assetPath.IsFileExists)
{
if (AvoidOverwriteAndLoad(assetPath, o))
{
// 上書きせずに既存のアセットからロードして置き換えた
return;
}
}
// アセットとして書き込む
assetPath.Parent.EnsureFolder();
assetPath.CreateAsset(o);
paths.Add(assetPath);
}
else
{
// save as subasset
if (o is GameObject)
{
}
else
{
prefabPath.AddObjectToAsset(o);
}
}
});
m_paths.Clear();
m_paths.Add(m_prefabPath);
m_context.TransferOwnership(SaveAsAsset);
// Create or update Main Asset
if (prefabPath.IsFileExists)
if (m_prefabPath.IsFileExists)
{
Debug.LogFormat("replace prefab: {0}", prefabPath);
var prefab = prefabPath.LoadAsset<GameObject>();
PrefabUtility.SaveAsPrefabAssetAndConnect(root, prefabPath.Value, InteractionMode.AutomatedAction);
Debug.LogFormat("replace prefab: {0}", m_prefabPath);
var prefab = m_prefabPath.LoadAsset<GameObject>();
PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction);
}
else
{
Debug.LogFormat("create prefab: {0}", prefabPath);
PrefabUtility.SaveAsPrefabAssetAndConnect(root, prefabPath.Value, InteractionMode.AutomatedAction);
Debug.LogFormat("create prefab: {0}", m_prefabPath);
PrefabUtility.SaveAsPrefabAssetAndConnect(m_context.Root, m_prefabPath.Value, InteractionMode.AutomatedAction);
}
foreach (var x in paths)
foreach (var x in m_paths)
{
x.ImportAsset();
}

View File

@@ -64,15 +64,15 @@ namespace VRM
//
using (var context = new VRMImporterContext(parser))
{
var editor = new VRMEditorImporterContext(context);
var editor = new VRMEditorImporterContext(context, prefabPath);
context.Load();
editor.SaveAsAsset(prefabPath);
editor.SaveAsAsset();
}
};
using (var context = new VRMImporterContext(parser))
{
var editor = new VRMEditorImporterContext(context);
var editor = new VRMEditorImporterContext(context, prefabPath);
editor.ConvertAndExtractImages(UnityPath.FromFullpath(path), onCompleted);
}
}

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UniGLTF;
using UnityEditor;
using UnityEngine;
@@ -38,16 +36,7 @@ namespace VRM
}
var parser = new GltfParser();
try
{
parser.ParseGlb(File.ReadAllBytes(path.FullPath));
}
catch (KeyNotFoundException)
{
// invalid VRM-0.X.
// maybe VRM-1.0.do nothing
return;
}
parser.ParseGlb(File.ReadAllBytes(path.FullPath));
var prefabPath = path.Parent.Child(path.FileNameWithoutExtension + ".prefab");
@@ -55,15 +44,15 @@ namespace VRM
{
using (var context = new VRMImporterContext(parser))
{
var editor = new VRMEditorImporterContext(context);
var editor = new VRMEditorImporterContext(context, prefabPath);
context.Load();
editor.SaveAsAsset(prefabPath);
editor.SaveAsAsset();
}
};
using (var context = new VRMImporterContext(parser))
{
var editor = new VRMEditorImporterContext(context);
var editor = new VRMEditorImporterContext(context, prefabPath);
editor.ConvertAndExtractImages(path, onCompleted);
}
}

View File

@@ -304,28 +304,44 @@ namespace VRM
return meta;
}
public override void TransferOwnership(Action<UnityEngine.Object> add)
public override void TransferOwnership(TakeOwnershipFunc take)
{
// VRM 固有のリソース(ScriptableObject)
add(HumanoidAvatar);
HumanoidAvatar = null;
if (take(HumanoidAvatar))
{
HumanoidAvatar = null;
}
add(Meta);
Meta = null;
if (take(Meta))
{
Meta = null;
}
add(AvatarDescription);
AvatarDescription = null;
if (take(AvatarDescription))
{
AvatarDescription = null;
}
var list = new List<BlendShapeClip>();
foreach (var x in BlendShapeAvatar.Clips)
{
add(x);
if (take(x))
{
list.Add(x);
}
}
foreach (var x in list)
{
BlendShapeAvatar.Clips.Remove(x);
}
BlendShapeAvatar.Clips.Clear();
add(BlendShapeAvatar);
BlendShapeAvatar = null;
if (take(BlendShapeAvatar))
{
BlendShapeAvatar = null;
}
base.TransferOwnership(add);
// GLTF のリソース
base.TransferOwnership(take);
}
}
}