You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
12 KiB
C#
309 lines
12 KiB
C#
using System;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
using UnityEngine.Polybrush;
|
|
|
|
namespace UnityEditor.Polybrush
|
|
{
|
|
static class ShaderMetaDataUtility
|
|
{
|
|
#pragma warning disable 0618
|
|
[Obsolete("Format is deprecated. Please use ShaderMetaDataUtility.LoadShaderMetaData and ShaderMetaDataUtility.SaveShaderMetaData.")]
|
|
const string SHADER_ATTRIB_FILE_EXTENSION = "pbs.json";
|
|
|
|
/// <summary>
|
|
/// Find a path to the Polybrush metadata for a shader.
|
|
/// </summary>
|
|
/// <param name="shader">Shader associated with the metadata</param>
|
|
/// <returns>The path found, null if not found.</returns>
|
|
[Obsolete("Please use ShaderMetaDataUtility.LoadShaderMetaData.")]
|
|
internal static string FindPolybrushMetaDataForShader(Shader shader)
|
|
{
|
|
if (shader == null)
|
|
return null;
|
|
|
|
string path = AssetDatabase.GetAssetPath(shader);
|
|
|
|
if (string.IsNullOrEmpty(path))
|
|
return null;
|
|
|
|
string filename = Path.GetFileNameWithoutExtension(path);
|
|
string directory = Path.GetDirectoryName(path);
|
|
|
|
string[] paths = new string[]
|
|
{
|
|
string.Format("{0}/{1}.{2}", directory, PolyShaderUtil.GetMetaDataPath(shader), SHADER_ATTRIB_FILE_EXTENSION),
|
|
string.Format("{0}/{1}.{2}", directory, filename, SHADER_ATTRIB_FILE_EXTENSION)
|
|
};
|
|
|
|
// @todo verify that the json is actually valid
|
|
foreach (string str in paths)
|
|
{
|
|
if (File.Exists(str))
|
|
{
|
|
// remove `..` from path since `AssetDatabase.LoadAssetAtPath` doesn't like 'em
|
|
string full = Path.GetFullPath(str).Replace("\\", "/");
|
|
string resolved = full.Replace(Application.dataPath, "Assets");
|
|
return resolved;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Try to read AttributeLayouts from a .pbs.json file located at "path"
|
|
/// </summary>
|
|
/// <param name="path">Path of the file to read from</param>
|
|
/// <param name="container">AttributeLayoutContainer retrieved from the json</param>
|
|
/// <returns>true if it worked, false if the file doesn't exist or is empty</returns>
|
|
[Obsolete("Please use ShaderMetaDataUtility.LoadShaderMetaData.")]
|
|
public static bool TryReadAttributeLayoutsFromJsonFile(string path, out AttributeLayoutContainer container)
|
|
{
|
|
container = null;
|
|
|
|
if (!File.Exists(path))
|
|
return false;
|
|
|
|
string json = File.ReadAllText(path);
|
|
|
|
if (string.IsNullOrEmpty(json))
|
|
return false;
|
|
|
|
container = ScriptableObject.CreateInstance<AttributeLayoutContainer>();
|
|
JsonUtility.FromJsonOverwrite(json, container);
|
|
|
|
ResolveShaderReference(container);
|
|
|
|
return true;
|
|
}
|
|
|
|
[Obsolete("Please use ShaderMetaDataUtility.LoadShaderMetaData.")]
|
|
public static bool TryReadAttributeLayoutsFromJson(string jsonText, out AttributeLayoutContainer container)
|
|
{
|
|
container = ScriptableObject.CreateInstance<AttributeLayoutContainer>();
|
|
JsonUtility.FromJsonOverwrite(jsonText, container);
|
|
|
|
ResolveShaderReference(container);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Store user-set shader attribute information.
|
|
/// </summary>
|
|
/// <param name="container">container that will have the shader and the metadata to write</param>
|
|
/// <param name="overwrite">overwrite data if already existing</param>
|
|
/// <param name="logErrors">log errors or not</param>
|
|
/// <returns>Returns the path written to on success, null otherwise.</returns>
|
|
[Obsolete("Please use ShaderMetaDataUtility.SaveShaderMetaData.")]
|
|
internal static string SaveMeshAttributesData(AttributeLayoutContainer container, bool overwrite = false, bool logErrors = true)
|
|
{
|
|
if (container == null) return string.Empty;
|
|
|
|
return SaveMeshAttributesData(container.shader, container.attributes, overwrite);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves the metadata of the shader passed in parameters, can overwrite if necessary
|
|
/// </summary>
|
|
/// <param name="shader">Shader associated with the metadata</param>
|
|
/// <param name="attributes">Metadata to write</param>
|
|
/// <param name="overwrite">Will overwrite if already existing file</param>param>
|
|
/// <param name="logErrors">Log errors or not</
|
|
/// <returns></returns>
|
|
[Obsolete("Please use ShaderMetaDataUtility.SaveShaderMetaData.")]
|
|
internal static string SaveMeshAttributesData(Shader shader, AttributeLayout[] attributes, bool overwrite = false, bool logErrors = true)
|
|
{
|
|
if (shader == null || attributes == null)
|
|
{
|
|
if (logErrors)
|
|
{
|
|
Debug.LogError("Cannot save null attributes for shader.");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
string path = FindPolybrushMetaDataForShader(shader);
|
|
string shader_path = AssetDatabase.GetAssetPath(shader);
|
|
string shader_directory = Path.GetDirectoryName(shader_path);
|
|
string shader_filename = Path.GetFileNameWithoutExtension(path);
|
|
|
|
// metadata didn't exist before
|
|
if (string.IsNullOrEmpty(path))
|
|
{
|
|
if (string.IsNullOrEmpty(shader_path))
|
|
{
|
|
// how!?
|
|
path = EditorUtility.SaveFilePanelInProject(
|
|
"Save Polybrush Shader Attributes",
|
|
shader_filename,
|
|
SHADER_ATTRIB_FILE_EXTENSION,
|
|
"Please enter a file name to save Polybrush shader metadata to.");
|
|
|
|
if (string.IsNullOrEmpty(path))
|
|
{
|
|
Debug.LogWarning(string.Format("Could not save Polybrush shader metadata. Please try again, possibly with a different file name or folder path."));
|
|
return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
shader_filename = Path.GetFileNameWithoutExtension(shader_path);
|
|
path = string.Format("{0}/{1}.{2}", shader_directory, shader_filename, SHADER_ATTRIB_FILE_EXTENSION);
|
|
}
|
|
}
|
|
|
|
if (!overwrite && File.Exists(path))
|
|
{
|
|
// @todo
|
|
Debug.LogWarning("shader metadata exists. calling function refuses to overwrite and lazy developer didn't add a save dialog here.");
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
AttributeLayoutContainer container = AttributeLayoutContainer.Create(shader, attributes);
|
|
string json = JsonUtility.ToJson(container, true);
|
|
File.WriteAllText(path, json);
|
|
|
|
//note: convert it here to be able to load it using AssetDatabase functions
|
|
shader_filename = Path.GetFileNameWithoutExtension(shader_path);
|
|
path = string.Format("{0}/{1}.{2}", shader_directory, shader_filename, SHADER_ATTRIB_FILE_EXTENSION);
|
|
//-------
|
|
|
|
return path;
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
if (logErrors)
|
|
{
|
|
Debug.LogError("Failed saving Polybrush Shader MetaData\n" + e.ToString());
|
|
}
|
|
return path;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Searches only by looking for a compatibly named file in the same directory.
|
|
/// </summary>
|
|
/// <param name="shader">Shader associated with the metadata</param>
|
|
/// <param name="attributes">result if any metadata found</param>
|
|
/// <returns></returns>
|
|
[Obsolete("Please use ShaderMetaDataUtility.LoadShaderMetaData.")]
|
|
internal static bool FindMeshAttributesForShader(Shader shader, out AttributeLayoutContainer attributes)
|
|
{
|
|
attributes = null;
|
|
|
|
string path = AssetDatabase.GetAssetPath(shader);
|
|
string filename = Path.GetFileNameWithoutExtension(path);
|
|
string directory = Path.GetDirectoryName(path);
|
|
|
|
string[] paths = new string[]
|
|
{
|
|
string.Format("{0}/{1}.{2}", directory, filename, SHADER_ATTRIB_FILE_EXTENSION),
|
|
string.Format("{0}/{1}.{2}", directory, PolyShaderUtil.GetMetaDataPath(shader), SHADER_ATTRIB_FILE_EXTENSION)
|
|
};
|
|
|
|
foreach (string str in paths)
|
|
{
|
|
if (TryReadAttributeLayoutsFromJsonFile(str, out attributes))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
[Obsolete("Method is deprecated. Please use ShaderMetaDataUtility.LoadShaderMetaData and ShaderMetaDataUtility.SaveShaderMetaData.")]
|
|
static void ResolveShaderReference(AttributeLayoutContainer container)
|
|
{
|
|
container.shader = Shader.Find(container.shaderPath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Store the shader's attributes in the new format.
|
|
/// Erase the .pbs.json on success.
|
|
/// </summary>
|
|
internal static void ConvertMetaDataToNewFormat(Shader shader)
|
|
{
|
|
if (shader == null)
|
|
throw new NullReferenceException("shader");
|
|
|
|
string path = ShaderMetaDataUtility.FindPolybrushMetaDataForShader(shader);
|
|
|
|
// If not null, it means we have data stored with the old format.
|
|
// Proceed to conversion.
|
|
if (path != null)
|
|
{
|
|
AttributeLayoutContainer attributesContainer = ScriptableObject.CreateInstance<AttributeLayoutContainer>();
|
|
ShaderMetaDataUtility.TryReadAttributeLayoutsFromJsonFile(path, out attributesContainer);
|
|
if (attributesContainer != null)
|
|
{
|
|
ShaderMetaDataUtility.SaveShaderMetaData(shader, attributesContainer);
|
|
FileUtil.DeleteFileOrDirectory(path);
|
|
FileUtil.DeleteFileOrDirectory(path + ".meta");
|
|
AssetDatabase.Refresh();
|
|
}
|
|
}
|
|
}
|
|
#pragma warning restore 0618
|
|
|
|
/// <summary>
|
|
/// Check if the given shader is an asset we can work with.
|
|
/// We will verify if it comes from the project by checking its importer.
|
|
/// </summary>
|
|
/// <param name="shader"></param>
|
|
/// <returns></returns>
|
|
internal static bool IsValidShader(Shader shader)
|
|
{
|
|
if (shader == null)
|
|
throw new ArgumentNullException("shader");
|
|
|
|
string path = AssetDatabase.GetAssetPath(shader);
|
|
AssetImporter importer = AssetImporter.GetAtPath(path);
|
|
|
|
return importer != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deserialize the shader's attributes from UserData in the shader's importer.
|
|
/// If none exists, it returns a new AttributeLayoutContainer instance.
|
|
/// </summary>
|
|
/// <param name="shader"></param>
|
|
/// <returns></returns>
|
|
internal static AttributeLayoutContainer LoadShaderMetaData(Shader shader)
|
|
{
|
|
if (shader == null)
|
|
throw new ArgumentNullException("shader");
|
|
|
|
string path = AssetDatabase.GetAssetPath(shader);
|
|
AssetImporter importer = AssetImporter.GetAtPath(path);
|
|
|
|
AttributeLayoutContainer data = AttributeLayoutContainer.Create(shader, null);
|
|
JsonUtility.FromJsonOverwrite(importer.userData, data);
|
|
return data;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serialize the shader's attributes as UserData in the shader's importer.
|
|
/// </summary>
|
|
/// <param name="shader"></param>
|
|
/// <param name="attributes"></param>
|
|
internal static void SaveShaderMetaData(Shader shader, AttributeLayoutContainer attributes)
|
|
{
|
|
if (shader == null)
|
|
throw new ArgumentNullException("shader");
|
|
|
|
if (attributes == null)
|
|
throw new ArgumentNullException("attributes");
|
|
|
|
string path = AssetDatabase.GetAssetPath(shader);
|
|
AssetImporter importer = AssetImporter.GetAtPath(path);
|
|
|
|
importer.userData = JsonUtility.ToJson(attributes);
|
|
importer.SaveAndReimport();
|
|
}
|
|
}
|
|
}
|