mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-22 02:24:57 -05:00
Merge pull request #1673 from ousttrue/fix/PathObject
VRMShaders.PathObject を追加。 MigrationMenu で使う。
This commit is contained in:
@@ -343,8 +343,8 @@ namespace UniGLTF
|
||||
}
|
||||
|
||||
public static UnityPath FromAsset(UnityEngine.Object asset)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(asset);
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(asset);
|
||||
if (string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
throw new System.ArgumentNullException();
|
||||
|
||||
@@ -6,14 +6,18 @@ namespace UniVRM10
|
||||
{
|
||||
public static class MigrationMenu
|
||||
{
|
||||
static string s_lastPath = Application.dataPath;
|
||||
static VRMShaders.PathObject s_lastPath = VRMShaders.PathObject.UnityAssets;
|
||||
|
||||
const string CONTEXT_MENU = "Assets/Migration: Vrm1";
|
||||
|
||||
[MenuItem(CONTEXT_MENU, true)]
|
||||
static bool Enable()
|
||||
{
|
||||
var path = UniGLTF.UnityPath.FromAsset(Selection.activeObject);
|
||||
if (Selection.activeObject == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var path = VRMShaders.PathObject.FromAsset(Selection.activeObject);
|
||||
var isVrm = path.Extension.ToLower() == ".vrm";
|
||||
return isVrm;
|
||||
}
|
||||
@@ -21,27 +25,30 @@ namespace UniVRM10
|
||||
[MenuItem(CONTEXT_MENU, false)]
|
||||
static void Exec()
|
||||
{
|
||||
var path = UniGLTF.UnityPath.FromAsset(Selection.activeObject);
|
||||
var isVrm = path.Extension.ToLower() == ".vrm";
|
||||
var path = VRMShaders.PathObject.FromAsset(Selection.activeObject);
|
||||
|
||||
var vrm1Bytes = MigrationVrm.Migrate(File.ReadAllBytes(path.FullPath));
|
||||
// migrate
|
||||
var vrm1Bytes = MigrationVrm.Migrate(path.ReadAllBytes());
|
||||
|
||||
var dst = EditorUtility.SaveFilePanel(
|
||||
"Save vrm1 file",
|
||||
s_lastPath,
|
||||
$"{path.FileNameWithoutExtension}_vrm1",
|
||||
"vrm");
|
||||
if (string.IsNullOrEmpty(dst))
|
||||
if (!s_lastPath.TrySaveDialog("Save vrm1 file", $"{path.Stem}_vrm1", out VRMShaders.PathObject dst))
|
||||
{
|
||||
return;
|
||||
}
|
||||
s_lastPath = Path.GetDirectoryName(dst);
|
||||
s_lastPath = dst.Parent;
|
||||
|
||||
// write result
|
||||
File.WriteAllBytes(dst, vrm1Bytes);
|
||||
dst.WriteAllBytes(vrm1Bytes);
|
||||
|
||||
// immediately import for GUI update
|
||||
UniGLTF.UnityPath.FromFullpath(dst).ImportAsset();
|
||||
if (dst.IsUnderAsset)
|
||||
{
|
||||
// immediately import for GUI update
|
||||
Debug.Log($"import: {dst}");
|
||||
dst.ImportAsset();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"write: {dst}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
183
Assets/VRMShaders/GLTF/IO/Editor/PathObject.cs
Normal file
183
Assets/VRMShaders/GLTF/IO/Editor/PathObject.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
/// <summary>
|
||||
/// UniGLTF.UnityPath (Assets の ひとつ上がルート) をすべてのパスが扱えるように拡張するのが趣旨。
|
||||
/// readonly struct で Immutable であるという主張。
|
||||
/// </summary>
|
||||
public readonly struct PathObject
|
||||
{
|
||||
/// <summary>
|
||||
/// * Delemeter は / を保証
|
||||
/// * .. を解決済み
|
||||
/// * フルパス
|
||||
/// * 末尾に / を付けない
|
||||
/// </summary>
|
||||
public string FullPath { get; }
|
||||
|
||||
public string Extension => Path.GetExtension(FullPath);
|
||||
|
||||
public string Stem => Path.GetFileNameWithoutExtension(FullPath);
|
||||
|
||||
public PathObject Parent => FromFullPath(Path.GetDirectoryName(FullPath));
|
||||
|
||||
public bool IsUnderAsset => IsDescendantOf(UnityAssets);
|
||||
|
||||
/// <summary>
|
||||
/// AssetDatabase の引き数になるパスを想定。
|
||||
/// Assets のひとつ上を 基準とする相対パス。
|
||||
/// Application.dataPath は Assets を得る。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string UnityPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var root = UnityRoot;
|
||||
if (!IsDescendantOf(UnityRoot))
|
||||
{
|
||||
throw new ArgumentException($"{FullPath} is not under UnityPath");
|
||||
}
|
||||
return FullPath.Substring(root.FullPath.Length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static PathObject? _root;
|
||||
public static PathObject UnityRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_root.HasValue)
|
||||
{
|
||||
_root = FromFullPath(Path.GetDirectoryName(Application.dataPath));
|
||||
}
|
||||
return _root.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static PathObject UnityAssets => UnityRoot.Child("Assets/");
|
||||
|
||||
PathObject(string src)
|
||||
{
|
||||
if (string.IsNullOrEmpty(src))
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
src = Path.GetFullPath(src).Replace('\\', '/');
|
||||
if (src.Length > 1 && src[src.Length - 1] == '/')
|
||||
{
|
||||
// drop last /
|
||||
src = src.Substring(0, src.Length - 1);
|
||||
}
|
||||
if (src[0] == '/')
|
||||
{
|
||||
FullPath = src;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src.Length >= 3 && src[1] == ':' && src[2] == '/')
|
||||
{
|
||||
FullPath = src;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"{src} is not fullpath");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
try
|
||||
{
|
||||
var unityPath = UnityPath;
|
||||
return $"<unity:{unityPath}>";
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return $"<file:{FullPath}>";
|
||||
}
|
||||
}
|
||||
|
||||
/// <param name="src">start with "X:/" on Windows else "/"</param>
|
||||
/// <returns></returns>
|
||||
public static PathObject FromFullPath(string src)
|
||||
{
|
||||
return new PathObject(src);
|
||||
}
|
||||
|
||||
/// <param name="src">AssetDatabase が使うパス</param>
|
||||
/// <returns></returns>
|
||||
public static PathObject FromUnityPath(string src)
|
||||
{
|
||||
return UnityRoot.Child(src);
|
||||
}
|
||||
|
||||
public static PathObject FromAsset(UnityEngine.Object src)
|
||||
{
|
||||
if (src == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
var assetPath = AssetDatabase.GetAssetPath(src);
|
||||
if (string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
throw new ArgumentException($"{src} is not asset");
|
||||
}
|
||||
return FromUnityPath(assetPath);
|
||||
}
|
||||
|
||||
public PathObject Child(string child)
|
||||
{
|
||||
return FromFullPath(Path.Combine(FullPath, child));
|
||||
}
|
||||
|
||||
public bool IsDescendantOf(PathObject ascendant)
|
||||
{
|
||||
if (!FullPath.StartsWith(ascendant.FullPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (FullPath.Length <= ascendant.FullPath.Length || FullPath[ascendant.FullPath.Length] != '/')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] ReadAllBytes()
|
||||
{
|
||||
return File.ReadAllBytes(FullPath);
|
||||
}
|
||||
|
||||
public void WriteAllBytes(byte[] data)
|
||||
{
|
||||
File.WriteAllBytes(FullPath, data);
|
||||
}
|
||||
|
||||
public void ImportAsset()
|
||||
{
|
||||
AssetDatabase.ImportAsset(UnityPath);
|
||||
}
|
||||
|
||||
public bool TrySaveDialog(string title, string name, out PathObject dst)
|
||||
{
|
||||
var path = EditorUtility.SaveFilePanel(
|
||||
title,
|
||||
FullPath,
|
||||
name,
|
||||
"vrm");
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
dst = default;
|
||||
return false;
|
||||
}
|
||||
dst = PathObject.FromFullPath(path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRMShaders/GLTF/IO/Editor/PathObject.cs.meta
Normal file
11
Assets/VRMShaders/GLTF/IO/Editor/PathObject.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d16607c9cf9d05e46b5beec82002d4ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs
Normal file
28
Assets/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
public sealed class PathObjectTests
|
||||
{
|
||||
[Test]
|
||||
public void Test()
|
||||
{
|
||||
var dataPath = PathObject.FromFullPath(Application.dataPath);
|
||||
|
||||
Assert.AreEqual("Assets", dataPath.Stem);
|
||||
|
||||
// UnityRoot
|
||||
Assert.True(dataPath.IsDescendantOf(PathObject.UnityRoot));
|
||||
// UnityRoot/Assets
|
||||
Assert.False(dataPath.IsDescendantOf(PathObject.UnityAssets));
|
||||
Assert.AreEqual(dataPath, PathObject.UnityAssets);
|
||||
|
||||
Assert.AreEqual(PathObject.UnityRoot.Child("Assets"), PathObject.UnityAssets);
|
||||
Assert.AreEqual(PathObject.UnityAssets.Parent, PathObject.UnityRoot);
|
||||
Assert.AreEqual("Assets", PathObject.UnityAssets.UnityPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs.meta
Normal file
11
Assets/VRMShaders/GLTF/IO/Tests/PathObjectTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45383f6fca5a57246b70f3919b582b7d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb31f565eeca6164694b06ccfe3bc251
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user