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";
///
/// Find a path to the Polybrush metadata for a shader.
///
/// Shader associated with the metadata
/// The path found, null if not found.
[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;
}
///
/// Try to read AttributeLayouts from a .pbs.json file located at "path"
///
/// Path of the file to read from
/// AttributeLayoutContainer retrieved from the json
/// true if it worked, false if the file doesn't exist or is empty
[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();
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();
JsonUtility.FromJsonOverwrite(jsonText, container);
ResolveShaderReference(container);
return true;
}
///
/// Store user-set shader attribute information.
///
/// container that will have the shader and the metadata to write
/// overwrite data if already existing
/// log errors or not
/// Returns the path written to on success, null otherwise.
[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);
}
///
/// Saves the metadata of the shader passed in parameters, can overwrite if necessary
///
/// Shader associated with the metadata
/// Metadata to write
/// Will overwrite if already existing fileparam>
/// Log errors or not
///
[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;
}
}
///
/// Searches only by looking for a compatibly named file in the same directory.
///
/// Shader associated with the metadata
/// result if any metadata found
///
[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);
}
///
/// Store the shader's attributes in the new format.
/// Erase the .pbs.json on success.
///
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();
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
///
/// 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.
///
///
///
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;
}
///
/// Deserialize the shader's attributes from UserData in the shader's importer.
/// If none exists, it returns a new AttributeLayoutContainer instance.
///
///
///
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;
}
///
/// Serialize the shader's attributes as UserData in the shader's importer.
///
///
///
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();
}
}
}