diff --git a/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/BeeBuildProgramCommon.Data.gen.csproj b/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/BeeBuildProgramCommon.Data.gen.csproj
new file mode 100644
index 0000000000..3672103003
--- /dev/null
+++ b/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/BeeBuildProgramCommon.Data.gen.csproj
@@ -0,0 +1,17 @@
+
+
+
+
+ BeeBuildProgramCommon.Data
+ netstandard2.1
+ false
+ false
+ false
+ latest
+ 1701
+
+
+
+
+
+
diff --git a/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs b/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs
new file mode 100644
index 0000000000..0a7938fabc
--- /dev/null
+++ b/Editor/IncrementalBuildPipeline/BeeBuildProgramCommon.Data/Data.cs
@@ -0,0 +1,41 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+namespace BeeBuildProgramCommon.Data
+{
+ public class PackageInfo
+ {
+ public string Name;
+ public string ResolvedPath;
+ }
+
+ public struct Version
+ {
+ public int Release, Major, Minor;
+
+ public Version(int release, int major, int minor)
+ {
+ Release = release;
+ Major = major;
+ Minor = minor;
+ }
+ }
+
+ public class ConfigurationData
+ {
+ public string Il2CppDir;
+ public string UnityLinkerPath;
+ public string Il2CppPath;
+ public string NetCoreRunPath;
+ public string DotNetExe;
+ public string EditorContentsPath;
+ public PackageInfo[] Packages;
+ public string UnityVersion;
+ public Version UnityVersionNumeric;
+ public string UnitySourceCodePath;
+ public bool Batchmode;
+ public bool EmitDataForBeeWhy;
+ public string NamedPipeOrUnixSocket;
+ }
+}
diff --git a/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs b/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs
new file mode 100644
index 0000000000..48b52443eb
--- /dev/null
+++ b/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs
@@ -0,0 +1,132 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+namespace PlayerBuildProgramLibrary.Data
+{
+ public class Plugin
+ {
+ public string AssetPath;
+ public string DestinationPath;
+ public string Architecture;
+ public string CompileFlags;
+ public bool AddToEmbeddedBinaries;
+ public override string ToString()
+ {
+ return $"'{AssetPath} -> '{DestinationPath}' ({Architecture})";
+ }
+ }
+
+ public class PluginsData
+ {
+ public Plugin[] Plugins = new Plugin[0];
+ }
+
+ public class GenerateNativePluginsForAssembliesArgs
+ {
+ public string PluginOutputFolder;
+ public string SymbolOutputFolder;
+ public string[] Assemblies;
+ }
+
+ public class GenerateNativePluginsForAssembliesSettings
+ {
+ public bool HasCallback;
+ public string DisplayName;
+ public string[] AdditionalInputFiles = new string[0];
+ }
+
+ public class PlayerBuildConfig
+ {
+ public string DestinationPath;
+ public string StagingArea;
+ public string DataFolder;
+ public string CompanyName;
+ public string ProductName;
+ public string PlayerPackage;
+ public string ApplicationIdentifier;
+ public string Architecture;
+ public ScriptingBackend ScriptingBackend;
+ public bool NoGUID;
+ public bool InstallIntoBuildsFolder;
+ public bool GenerateIdeProject;
+ public bool Development;
+ public bool UseNewInputSystem;
+ public GenerateNativePluginsForAssembliesSettings GenerateNativePluginsForAssembliesSettings;
+ public Services Services;
+ public string[] ManagedAssemblies;
+ public StreamingAssetsFile[] StreamingAssetsFiles;
+ }
+
+ public class BuiltFilesOutput
+ {
+ public string[] Files = new string[0];
+ public string BootConfigArtifact;
+ }
+
+ public class LinkerConfig
+ {
+ public string[] LinkXmlFiles = new string[0];
+ public string[] AssembliesToProcess = new string[0];
+ public string EditorToLinkerData;
+ public string Runtime;
+ public string Profile;
+ public string Ruleset;
+ public string ModulesAssetPath;
+ public string[] AdditionalArgs = new string[0];
+ public bool AllowDebugging;
+ public bool PerformEngineStripping;
+ }
+
+ public class Il2CppConfig
+ {
+ public bool EnableDeepProfilingSupport;
+ public bool EnableFullGenericSharing;
+ public string Profile;
+ public string[] IDEProjectDefines;
+
+ public string ConfigurationName;
+ public bool GcWBarrierValidation;
+ public bool GcIncremental;
+
+ public string[] AdditionalCppFiles = new string[0];
+ public string[] AdditionalArgs = new string[0];
+ public string CompilerFlags;
+ public string[] AdditionalLibraries;
+ public string[] AdditionalDefines;
+ public string[] AdditionalIncludeDirectories;
+ public string[] AdditionalLinkDirectories;
+ public string LinkerFlags;
+ public string LinkerFlagsFile;
+ public string ExtraTypes;
+ public bool CreateSymbolFiles;
+ public bool AllowDebugging;
+ public string SysRootPath;
+ public string ToolChainPath;
+ public string RelativeDataPath;
+ public bool GenerateUsymFile;
+ public string UsymtoolPath;
+ }
+
+ public class Services
+ {
+ public bool EnableUnityConnect;
+ public bool EnablePerformanceReporting;
+ public bool EnableAnalytics;
+ public bool EnableCrashReporting;
+ public bool EnableInsights;
+ }
+
+ public class StreamingAssetsFile
+ {
+ public string File;
+ public string RelativePath;
+ }
+
+ public enum ScriptingBackend
+ {
+ Mono,
+ IL2CPP,
+ CoreCLR,
+ }
+}
diff --git a/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/PlayerBuildProgramLibrary.Data.gen.csproj b/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/PlayerBuildProgramLibrary.Data.gen.csproj
new file mode 100644
index 0000000000..3f29c8f429
--- /dev/null
+++ b/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/PlayerBuildProgramLibrary.Data.gen.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+ PlayerBuildProgramLibrary.Data
+ netstandard2.1
+ false
+ false
+ false
+ latest
+ 1701
+ PlayerBuildProgramLibrary.Data
+
+
+
+
+
+
+
diff --git a/Editor/IncrementalBuildPipeline/ScriptCompilationBuildProgram.Data/Data.cs b/Editor/IncrementalBuildPipeline/ScriptCompilationBuildProgram.Data/Data.cs
new file mode 100644
index 0000000000..fc674d689c
--- /dev/null
+++ b/Editor/IncrementalBuildPipeline/ScriptCompilationBuildProgram.Data/Data.cs
@@ -0,0 +1,68 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+namespace ScriptCompilationBuildProgram.Data
+{
+ public static class Constants
+ {
+ public const string ScriptAssembliesTarget = "ScriptAssemblies";
+ public const string ScriptAssembliesAndTypeDBTarget = "ScriptAssembliesAndTypeDB";
+ public const string MovedFromExtension = "mvfrm";
+ }
+
+ public class ScriptCompilationData
+ {
+ public AssemblyData[] Assemblies;
+ public AssemblyData[] CodegenAssemblies;
+ public string DotnetRuntimePath;
+ public string DotnetRoslynPath;
+ public string MovedFromExtractorPath;
+ public string OutputDirectory;
+ public bool Debug;
+ public string BuildTarget;
+ public string Localization;
+ public string BuildPlayerDataOutput;
+ public bool ExtractRuntimeInitializeOnLoads;
+ public bool EnableDiagnostics;
+ public bool EmitInfoForScriptUpdater;
+ public string[] AssembliesToScanForTypeDB;
+ public string[] SearchPaths;
+ }
+
+ public class AssemblyData
+ {
+ public string Name;
+ public string[] SourceFiles = new string[0];
+ public string[] Defines = new string[0];
+ public string[] PrebuiltReferences = new string[0];
+ public int[] References = new int[0];
+ public bool AllowUnsafeCode;
+ public string RuleSet;
+ public string AnalyzerConfigPath;
+ public string LanguageVersion;
+ public bool UseDeterministicCompilation;
+ public bool SuppressCompilerWarnings;
+ public string[] Analyzers = new string[0];
+ public string[] AdditionalFiles = new string[0];
+ public string Asmdef;
+ public string[] BclDirectories = new string[0];
+ public string[] CustomCompilerOptions = new string[0];
+ public int DebugIndex;
+ public bool SkipCodeGen;
+ public string Path;
+ }
+
+ public class ScriptCompilationData_Out
+ {
+ public AssemblyData_Out[] Assemblies;
+ public bool LocalizeCompilerMessages;
+ }
+
+ public class AssemblyData_Out
+ {
+ public string Path;
+ public string ScriptUpdaterRsp;
+ public string MovedFromExtractorFile;
+ }
+}
diff --git a/Editor/IncrementalBuildPipeline/ScriptCompilationBuildProgram.Data/ScriptCompilationBuildProgram.Data.gen.csproj b/Editor/IncrementalBuildPipeline/ScriptCompilationBuildProgram.Data/ScriptCompilationBuildProgram.Data.gen.csproj
new file mode 100644
index 0000000000..d714f512c1
--- /dev/null
+++ b/Editor/IncrementalBuildPipeline/ScriptCompilationBuildProgram.Data/ScriptCompilationBuildProgram.Data.gen.csproj
@@ -0,0 +1,18 @@
+
+
+
+
+ ScriptCompilationBuildProgram.Data
+ netstandard2.1
+ false
+ false
+ false
+ latest
+ 1701
+
+
+
+
+
+
+
diff --git a/Editor/Mono/2D/Common/TexturePlatformSettingsView.cs b/Editor/Mono/2D/Common/TexturePlatformSettingsView.cs
index 9432ed2b11..e46d1314a0 100644
--- a/Editor/Mono/2D/Common/TexturePlatformSettingsView.cs
+++ b/Editor/Mono/2D/Common/TexturePlatformSettingsView.cs
@@ -20,7 +20,7 @@ class Styles
public readonly GUIContent compressionQualityLabel = EditorGUIUtility.TrTextContent("Compressor Quality");
public readonly GUIContent compressionQualitySliderLabel = EditorGUIUtility.TrTextContent("Compressor Quality", "Use the slider to adjust compression quality from 0 (Fastest) to 100 (Best)");
- public readonly int[] kMaxTextureSizeValues = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
+ public readonly int[] kMaxTextureSizeValues = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
public readonly GUIContent[] kMaxTextureSizeStrings;
public readonly GUIContent[] kTextureCompressionOptions =
diff --git a/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs b/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs
index 6c1eb58feb..bf615783af 100644
--- a/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs
+++ b/Editor/Mono/2D/SpriteAtlas/EditorSpriteAtlas.bindings.cs
@@ -6,6 +6,8 @@
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.Bindings;
+using System;
+using UnityEditor.AssetImporters;
namespace UnityEditor.U2D
{
@@ -13,6 +15,12 @@ namespace UnityEditor.U2D
[NativeHeader("Editor/Src/2D/SpriteAtlas/SpriteAtlasPackingUtilities.h")]
public class SpriteAtlasUtility
{
+ [FreeFunction("SpriteAtlasExtensions::EnableV2Import")]
+ extern internal static void EnableV2Import(bool onOff);
+
+ [FreeFunction("SpriteAtlasExtensions::CleanupAtlasPacking")]
+ extern public static void CleanupAtlasPacking();
+
[FreeFunction("CollectAllSpriteAtlasesAndPack")]
extern public static void PackAllAtlases(BuildTarget target, bool canCancel = true);
@@ -21,6 +29,11 @@ public class SpriteAtlasUtility
public static void PackAtlases(SpriteAtlas[] atlases, BuildTarget target, bool canCancel = true)
{
+ if (atlases == null)
+ throw new ArgumentNullException("atlases", "Value for parameter atlases is null");
+ foreach (var atlas in atlases)
+ if (atlas == null)
+ throw new ArgumentNullException("atlases", "One of the elements in atlases is null. Please check your Inputs.");
PackAtlasesInternal(atlases, target, canCancel, false, true);
}
}
@@ -47,6 +60,7 @@ public struct SpriteAtlasTextureSettings
[NativeName("sRGB")]
private bool m_sRGB;
+ public int maxTextureSize { get { return m_MaxTextureSize; } }
public int anisoLevel { get { return m_AnisoLevel; } set { m_AnisoLevel = value; } }
public FilterMode filterMode { get { return (FilterMode)m_FilterMode; } set { m_FilterMode = (int)value; } }
public bool generateMipMaps { get { return m_GenerateMipMaps; } set { m_GenerateMipMaps = value; } }
@@ -67,11 +81,14 @@ public struct SpriteAtlasPackingSettings
private bool m_EnableRotation;
[NativeName("enableTightPacking")]
private bool m_EnableTightPacking;
+ [NativeName("enableAlphaDilation")]
+ private bool m_EnableAlphaDilation;
public int blockOffset { get { return m_BlockOffset; } set { m_BlockOffset = value; } }
public int padding { get { return m_Padding; } set { m_Padding = value; } }
public bool enableRotation { get { return m_EnableRotation; } set { m_EnableRotation = value; } }
public bool enableTightPacking { get { return m_EnableTightPacking; } set { m_EnableTightPacking = value; } }
+ public bool enableAlphaDilation { get { return m_EnableAlphaDilation; } set { m_EnableAlphaDilation = value; } }
}
[NativeHeader("Editor/Src/AssetPipeline/TextureImporting/TextureImporterTypes.h")]
@@ -80,31 +97,71 @@ public struct SpriteAtlasPackingSettings
[NativeHeader("Runtime/2D/SpriteAtlas/SpriteAtlas.h")]
public static class SpriteAtlasExtensions
{
- extern public static void Add(this SpriteAtlas spriteAtlas, UnityEngine.Object[] objects);
- extern public static void Remove(this SpriteAtlas spriteAtlas, UnityEngine.Object[] objects);
- extern internal static void RemoveAt(this SpriteAtlas spriteAtlas, int index);
- extern public static UnityEngine.Object[] GetPackables(this SpriteAtlas spriteAtlas);
- extern public static SpriteAtlasTextureSettings GetTextureSettings(this SpriteAtlas spriteAtlas);
- extern public static void SetTextureSettings(this SpriteAtlas spriteAtlas, SpriteAtlasTextureSettings src);
- extern public static SpriteAtlasPackingSettings GetPackingSettings(this SpriteAtlas spriteAtlas);
- extern public static void SetPackingSettings(this SpriteAtlas spriteAtlas, SpriteAtlasPackingSettings src);
- extern public static TextureImporterPlatformSettings GetPlatformSettings(this SpriteAtlas spriteAtlas, string buildTarget);
- extern public static void SetPlatformSettings(this SpriteAtlas spriteAtlas, TextureImporterPlatformSettings src);
- extern public static void SetIncludeInBuild(this SpriteAtlas spriteAtlas, bool value);
- extern public static void SetIsVariant(this SpriteAtlas spriteAtlas, bool value);
- extern public static void SetMasterAtlas(this SpriteAtlas spriteAtlas, SpriteAtlas value);
- extern public static void SetVariantScale(this SpriteAtlas spriteAtlas, float value);
- extern internal static void CopyMasterAtlasSettings(this SpriteAtlas spriteAtlas);
- extern internal static string GetHash(this SpriteAtlas spriteAtlas);
- extern internal static Texture2D[] GetPreviewTextures(this SpriteAtlas spriteAtlas);
- extern internal static Texture2D[] GetPreviewAlphaTextures(this SpriteAtlas spriteAtlas);
- extern internal static TextureFormat GetTextureFormat(this SpriteAtlas spriteAtlas, BuildTarget target);
- extern internal static Sprite[] GetPackedSprites(this SpriteAtlas spriteAtlas);
- extern internal static Hash128 GetStoredHash(this SpriteAtlas spriteAtlas);
- extern internal static TextureImporterPlatformSettings GetSecondaryPlatformSettings(this SpriteAtlas spriteAtlas, string buildTarget, string secondaryTextureName);
- extern internal static void SetSecondaryPlatformSettings(this SpriteAtlas spriteAtlas, TextureImporterPlatformSettings src, string secondaryTextureName);
- extern internal static bool GetSecondaryColorSpace(this SpriteAtlas spriteAtlas, string secondaryTextureName);
- extern internal static void SetSecondaryColorSpace(this SpriteAtlas spriteAtlas, string secondaryTextureName, bool srGB);
- extern internal static void DeleteSecondaryPlatformSettings(this SpriteAtlas spriteAtlas, string secondaryTextureName);
+ extern public static void Add([NotNull] this SpriteAtlas spriteAtlas, UnityEngine.Object[] objects);
+ extern public static void Remove([NotNull] this SpriteAtlas spriteAtlas, UnityEngine.Object[] objects);
+ extern internal static void RemoveAt([NotNull] this SpriteAtlas spriteAtlas, int index);
+ extern public static UnityEngine.Object[] GetPackables([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static void SetV2([NotNull] this SpriteAtlas spriteAtlas);
+ internal static void RegisterAndPackAtlas(this SpriteAtlas spriteAtlas, AssetImportContext context, AssetImporter importer, U2D.ScriptablePacker scriptablePacker)
+ {
+ RegisterAndPackAtlasInternal(spriteAtlas, context, importer, scriptablePacker);
+ }
+ extern private static void RegisterAndPackAtlasInternal([NotNull] this SpriteAtlas spriteAtlas, [NotNull] AssetImportContext context, [NotNull] AssetImporter importer, UnityEngine.Object scriptablePacker);
+ extern public static SpriteAtlasTextureSettings GetTextureSettings([NotNull] this SpriteAtlas spriteAtlas);
+ extern public static void SetTextureSettings([NotNull] this SpriteAtlas spriteAtlas, SpriteAtlasTextureSettings src);
+ extern public static SpriteAtlasPackingSettings GetPackingSettings([NotNull] this SpriteAtlas spriteAtlas);
+ extern public static void SetPackingSettings([NotNull] this SpriteAtlas spriteAtlas, SpriteAtlasPackingSettings src);
+
+ [NativeName("GetPlatformSettings")]
+ extern private static TextureImporterPlatformSettings GetPlatformSettings_Internal([NotNull] this SpriteAtlas spriteAtlas, string buildTarget);
+ public static TextureImporterPlatformSettings GetPlatformSettings(this SpriteAtlas spriteAtlas, string buildTarget)
+ {
+ buildTarget = TextureImporter.GetTexturePlatformSerializationName(buildTarget); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ return GetPlatformSettings_Internal(spriteAtlas, buildTarget);
+ }
+
+ [NativeName("SetPlatformSettings")]
+ extern private static void SetPlatformSettings_Internal([NotNull] this SpriteAtlas spriteAtlas, TextureImporterPlatformSettings src);
+ public static void SetPlatformSettings(this SpriteAtlas spriteAtlas, TextureImporterPlatformSettings src)
+ {
+ src.name = TextureImporter.GetTexturePlatformSerializationName(src.name); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ SetPlatformSettings_Internal(spriteAtlas, src);
+ }
+
+ extern public static void SetIncludeInBuild([NotNull] this SpriteAtlas spriteAtlas, bool value);
+ extern public static void SetIsVariant([NotNull] this SpriteAtlas spriteAtlas, bool value);
+ extern public static void SetMasterAtlas([NotNull] this SpriteAtlas spriteAtlas, SpriteAtlas value);
+ extern public static void SetVariantScale([NotNull] this SpriteAtlas spriteAtlas, float value);
+ extern public static bool IsIncludeInBuild([NotNull] this SpriteAtlas spriteAtlas);
+ extern public static SpriteAtlas GetMasterAtlas([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static void CopyMasterAtlasSettings([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static string GetHash([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static Texture2D[] GetPreviewTextures([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static Texture2D[] GetPreviewAlphaTextures([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static TextureFormat GetTextureFormat([NotNull] this SpriteAtlas spriteAtlas, BuildTarget target);
+ extern internal static Sprite[] GetPackedSprites([NotNull] this SpriteAtlas spriteAtlas);
+ extern internal static Hash128 GetStoredHash([NotNull] this SpriteAtlas spriteAtlas);
+
+ [NativeName("GetSecondaryPlatformSettings")]
+ extern private static TextureImporterPlatformSettings GetSecondaryPlatformSettings_Internal([NotNull] this SpriteAtlas spriteAtlas, string buildTarget, string secondaryTextureName);
+ internal static TextureImporterPlatformSettings GetSecondaryPlatformSettings(this SpriteAtlas spriteAtlas, string buildTarget, string secondaryTextureName)
+ {
+ buildTarget = TextureImporter.GetTexturePlatformSerializationName(buildTarget); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ return GetSecondaryPlatformSettings_Internal(spriteAtlas, buildTarget, secondaryTextureName);
+ }
+
+ [NativeName("SetSecondaryPlatformSettings")]
+ extern private static void SetSecondaryPlatformSettings_Internal([NotNull] this SpriteAtlas spriteAtlas, TextureImporterPlatformSettings src, string secondaryTextureName);
+ internal static void SetSecondaryPlatformSettings(this SpriteAtlas spriteAtlas, TextureImporterPlatformSettings src, string secondaryTextureName)
+ {
+ src.name = TextureImporter.GetTexturePlatformSerializationName(src.name); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ SetSecondaryPlatformSettings_Internal(spriteAtlas, src, secondaryTextureName);
+ }
+
+ extern internal static bool GetSecondaryColorSpace([NotNull] this SpriteAtlas spriteAtlas, string secondaryTextureName);
+ extern internal static void SetSecondaryColorSpace([NotNull] this SpriteAtlas spriteAtlas, string secondaryTextureName, bool srGB);
+ extern internal static void DeleteSecondaryPlatformSettings([NotNull] this SpriteAtlas spriteAtlas, string secondaryTextureName);
+ extern internal static string GetSecondaryTextureNameInAtlas(string atlasTextureName);
+ extern internal static string GetPageNumberInAtlas(string atlasTextureName);
}
}
diff --git a/Editor/Mono/2D/SpriteAtlas/EditorSpritePacking.bindings.cs b/Editor/Mono/2D/SpriteAtlas/EditorSpritePacking.bindings.cs
new file mode 100644
index 0000000000..145e7da29f
--- /dev/null
+++ b/Editor/Mono/2D/SpriteAtlas/EditorSpritePacking.bindings.cs
@@ -0,0 +1,183 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Unity.Collections;
+using UnityEngine;
+using UnityEngine.U2D;
+using UnityEngine.Bindings;
+using UnityEngine.Scripting;
+using Unity.Collections.LowLevel.Unsafe;
+
+namespace UnityEditor.U2D.SpritePacking
+{
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SpritePackInfoInternal
+ {
+ public int guid;
+ public int texIndex;
+ public int indexCount;
+ public int vertexCount;
+ public RectInt rect;
+ public IntPtr indices;
+ public IntPtr vertices;
+ };
+
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SpritePackTextureInfoInternal
+ {
+ public int width;
+ public int height;
+ public IntPtr buffer;
+ };
+
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SpritePackDatasetInternal
+ {
+ public SpritePackInfoInternal spriteData;
+ public SpritePackTextureInfoInternal textureData;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SpritePackInfo
+ {
+ public int guid;
+ public int texIndex;
+ public int indexCount;
+ public int vertexCount;
+ public RectInt rect;
+ public NativeArray indices;
+ public NativeArray vertices;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SpritePackTextureInfo
+ {
+ public int width;
+ public int height;
+ public NativeArray buffer;
+ };
+
+ internal struct SpritePackDataset
+ {
+ public List spriteData;
+ public List textureData;
+ };
+
+ internal struct SpritePackConfig
+ {
+ public int padding;
+ };
+
+ [NativeHeader("Runtime/2D/SpriteAtlas/SpriteAtlas.h")]
+ [NativeHeader("Editor/Src/2D/SpriteAtlas/SpriteAtlasPackingUtilities.h")]
+ internal class SpritePackUtility
+ {
+ internal unsafe static SpritePackDataset PackCustomSpritesWrapper(SpritePackDataset input, SpritePackConfig packConfig, Allocator alloc)
+ {
+ var output = new SpritePackDataset();
+ var spriteCount = input.spriteData.Count;
+ if (0 == spriteCount)
+ return output;
+
+ var data = new NativeArray(spriteCount, Allocator.Temp, NativeArrayOptions.ClearMemory);
+ for (int i = 0; i < spriteCount; ++i)
+ {
+ SpritePackDatasetInternal rawData = data[i];
+ rawData.spriteData.guid = input.spriteData[i].guid;
+ int texIndex = input.spriteData[i].texIndex;
+ if (texIndex >= input.textureData.Count)
+ {
+ data.Dispose();
+ throw new ArgumentOutOfRangeException("texIndex", "texIndex must point to a valid index in textureData list.");
+ }
+ rawData.spriteData.texIndex = texIndex;
+ rawData.spriteData.indexCount = input.spriteData[i].indexCount;
+ rawData.spriteData.vertexCount = input.spriteData[i].vertexCount;
+ rawData.spriteData.rect = input.spriteData[i].rect;
+ rawData.spriteData.indices = input.spriteData[i].indices.IsCreated ? (IntPtr)input.spriteData[i].indices.GetUnsafePtr() : (IntPtr)0;
+ rawData.spriteData.vertices = input.spriteData[i].vertices.IsCreated ? (IntPtr)input.spriteData[i].vertices.GetUnsafePtr() : (IntPtr)0;
+ rawData.textureData.width = input.textureData[texIndex].width;
+ rawData.textureData.height = input.textureData[texIndex].height;
+ rawData.textureData.buffer = input.textureData[texIndex].buffer.IsCreated ? (IntPtr)input.textureData[texIndex].buffer.GetUnsafePtr() : (IntPtr)0;
+ data[i] = rawData;
+ }
+
+ var spriteOutput = (SpritePackDatasetInternal*)PackCustomSpritesInternal(spriteCount, (SpritePackDatasetInternal*)data.GetUnsafePtr(), packConfig);
+ if (null != spriteOutput)
+ {
+ var colorBufferArray = new SpritePackTextureInfo[spriteCount];
+ for (int i = 0; i < spriteCount; ++i)
+ {
+ SpritePackTextureInfoInternal rawBuffer = spriteOutput[i].textureData;
+ int index = spriteOutput[i].spriteData.texIndex;
+ SpritePackTextureInfo outputBuffer = colorBufferArray[index];
+ // New Texture. Copy.
+ if (!outputBuffer.buffer.IsCreated)
+ {
+ outputBuffer.width = rawBuffer.width;
+ outputBuffer.height = rawBuffer.height;
+ Color32* rawColor = (Color32*)rawBuffer.buffer;
+ if (null != rawColor)
+ {
+ outputBuffer.buffer = new NativeArray(rawBuffer.width * rawBuffer.height, alloc);
+ UnsafeUtility.MemCpy(outputBuffer.buffer.GetUnsafePtr(), rawColor, rawBuffer.width * rawBuffer.height * sizeof(Color32));
+ }
+ UnsafeUtility.Free((void*)rawBuffer.buffer, Allocator.Persistent);
+ }
+ colorBufferArray[index] = outputBuffer;
+ }
+ output.textureData = new List(colorBufferArray);
+
+ var spriteDataArray = new SpritePackInfo[spriteCount];
+ for (int i = 0; i < spriteCount; ++i)
+ {
+ SpritePackInfo spriteData = spriteDataArray[i];
+ spriteData.guid = spriteOutput[i].spriteData.guid;
+ spriteData.indexCount = spriteOutput[i].spriteData.indexCount;
+ spriteData.vertexCount = spriteOutput[i].spriteData.vertexCount;
+ spriteData.rect = spriteOutput[i].spriteData.rect;
+ if (0 != spriteData.indexCount && 0 != spriteData.vertexCount)
+ {
+ int* rawIndices = (int*)spriteOutput[i].spriteData.indices;
+ if (null != rawIndices)
+ {
+ spriteData.indices = new NativeArray(spriteOutput[i].spriteData.indexCount, alloc);
+ UnsafeUtility.MemCpy(spriteData.indices.GetUnsafePtr(), rawIndices, spriteOutput[i].spriteData.indexCount * sizeof(int));
+ }
+ Vector3* rawVertices = (Vector3*)spriteOutput[i].spriteData.vertices;
+ if (null != rawVertices)
+ {
+ spriteData.vertices = new NativeArray(spriteOutput[i].spriteData.vertexCount, alloc);
+ UnsafeUtility.MemCpy(spriteData.vertices.GetUnsafePtr(), rawVertices, spriteOutput[i].spriteData.vertexCount * sizeof(Vector3));
+ }
+ UnsafeUtility.Free((void*)spriteOutput[i].spriteData.indices, Allocator.Persistent);
+ UnsafeUtility.Free((void*)spriteOutput[i].spriteData.vertices, Allocator.Persistent);
+ }
+ spriteData.texIndex = spriteOutput[i].spriteData.texIndex;
+ spriteDataArray[i] = spriteData;
+ }
+ output.spriteData = new List(spriteDataArray);
+ UnsafeUtility.Free((void*)spriteOutput, Allocator.Persistent);
+ }
+
+ data.Dispose();
+ return output;
+ }
+
+ internal static SpritePackDataset PackCustomSprites(SpritePackDataset spriteDataInput, SpritePackConfig packConfig, Allocator outputAlloc)
+ {
+ return PackCustomSpritesWrapper(spriteDataInput, packConfig, outputAlloc);
+ }
+
+ [NativeThrows]
+ [FreeFunction("PackCustomSprites")]
+ extern internal unsafe static IntPtr PackCustomSpritesInternal(int spriteCount, SpritePackDatasetInternal* data, SpritePackConfig packConfig);
+ }
+}
diff --git a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasAsset.bindings.cs b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasAsset.bindings.cs
index 9ffbf04228..ee92ddf825 100644
--- a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasAsset.bindings.cs
+++ b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasAsset.bindings.cs
@@ -4,16 +4,115 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
-using UnityEditor.Build;
-using UnityEditor.Experimental.AssetImporters;
+using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Bindings;
using UnityEngine.Scripting;
using UnityEngine.U2D;
+using Unity.Collections.LowLevel.Unsafe;
+using Unity.Collections;
namespace UnityEditor.U2D
{
+
+ [UsedByNativeCode]
+ public abstract class ScriptablePacker : ScriptableObject
+ {
+
+ public enum PackTransform
+ {
+ None = 0,
+ FlipHorizontal = 1,
+ FlipVertical = 2,
+ Rotate180 = 3,
+ }
+
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SpritePack
+ {
+ public int x;
+ public int y;
+ public int page;
+ public PackTransform rot;
+ };
+
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SpriteData
+ {
+ public int guid;
+ public int texIndex;
+ public int indexCount;
+ public int vertexCount;
+ public int indexOffset;
+ public int vertexOffset;
+ public RectInt rect;
+ public SpritePack output;
+ };
+
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TextureData
+ {
+ public int width;
+ public int height;
+ public int bufferOffset;
+ };
+
+ [RequiredByNativeCode]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PackerDataInternal
+ {
+ public int colorCount;
+ public IntPtr colorData;
+ public int spriteCount;
+ public IntPtr spriteData;
+ public int textureCount;
+ public IntPtr textureData;
+ public int indexCount;
+ public IntPtr indexData;
+ public int vertexCount;
+ public IntPtr vertexData;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct PackerData
+ {
+ public NativeArray colorData;
+ public NativeArray spriteData;
+ public NativeArray textureData;
+ public NativeArray indexData;
+ public NativeArray vertexData;
+ };
+
+ // Public function to pack.
+ public abstract bool Pack(SpriteAtlasPackingSettings config, SpriteAtlasTextureSettings setting, PackerData input);
+
+ // Internal Glue function.
+ [RequiredByNativeCode]
+ internal bool PackInternal(SpriteAtlasPackingSettings config, SpriteAtlasTextureSettings setting, PackerDataInternal packerData)
+ {
+ var input = new PackerData();
+ unsafe
+ {
+ input.colorData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray((void*)packerData.colorData, packerData.colorCount, Allocator.None);
+ input.spriteData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray((void*)packerData.spriteData, packerData.spriteCount, Allocator.None);
+ input.textureData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray((void*)packerData.textureData, packerData.textureCount, Allocator.None);
+ input.indexData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray((void*)packerData.indexData, packerData.indexCount, Allocator.None);
+ input.vertexData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray((void*)packerData.vertexData, packerData.vertexCount, Allocator.None);
+
+ NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref input.colorData, AtomicSafetyHandle.GetTempMemoryHandle());
+ NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref input.spriteData, AtomicSafetyHandle.GetTempMemoryHandle());
+ NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref input.textureData, AtomicSafetyHandle.GetTempMemoryHandle());
+ NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref input.indexData, AtomicSafetyHandle.GetTempMemoryHandle());
+ NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref input.vertexData, AtomicSafetyHandle.GetTempMemoryHandle());
+ }
+ return Pack(config, setting, input);
+ }
+
+ };
+
// SpriteAtlas Importer lets you modify [[SpriteAtlas]]
[NativeHeader("Editor/Src/2D/SpriteAtlas/SpriteAtlasAsset.h")]
[NativeType(Header = "Editor/Src/2D/SpriteAtlas/SpriteAtlasAsset.h")]
@@ -25,25 +124,50 @@ public class SpriteAtlasAsset : UnityEngine.Object
extern public bool isVariant { [NativeMethod("GetIsVariant")] get; }
extern public void SetIsVariant(bool value);
extern public void SetMasterAtlas(SpriteAtlas atlas);
- extern public void SetIncludeInBuild(bool value);
- extern public void SetVariantScale(float value);
- extern public void SetPlatformSettings(TextureImporterPlatformSettings src);
- extern public TextureImporterPlatformSettings GetPlatformSettings(string buildTarget);
- extern public SpriteAtlasTextureSettings GetTextureSettings();
- extern public void SetTextureSettings(SpriteAtlasTextureSettings src);
- extern public SpriteAtlasPackingSettings GetPackingSettings();
- extern public void SetPackingSettings(SpriteAtlasPackingSettings src);
-
+ extern public SpriteAtlas GetMasterAtlas();
+ extern internal UnityEngine.Object GetPacker();
+ extern internal void SetPacker(UnityEngine.Object obj);
extern public void Add(UnityEngine.Object[] objects);
extern public void Remove(UnityEngine.Object[] objects);
+
+ public void SetScriptablePacker(ScriptablePacker obj)
+ {
+ SetPacker(obj);
+ }
extern internal void RemoveAt(int index);
- extern internal TextureFormat GetTextureFormat(BuildTarget target);
- extern internal void CopyMasterAtlasSettings();
- extern internal TextureImporterPlatformSettings GetSecondaryPlatformSettings(string buildTarget, string secondaryTextureName);
- extern internal void SetSecondaryPlatformSettings(TextureImporterPlatformSettings src, string secondaryTextureName);
- extern internal bool GetSecondaryColorSpace(string secondaryTextureName);
- extern internal void SetSecondaryColorSpace(string secondaryTextureName, bool srGB);
- extern internal void DeleteSecondaryPlatformSettings(string secondaryTextureName);
+ [Obsolete("SetVariantScale is no longer supported and will be removed. Use SpriteAtlasImporter.SetVariantScale instead.")]
+ public void SetVariantScale(float value) { }
+ [Obsolete("SetIncludeInBuild is no longer supported and will be removed. Use SpriteAtlasImporter.SetIncludeInBuild instead.")]
+ public void SetIncludeInBuild(bool value) { }
+ [Obsolete("IsIncludeInBuild is no longer supported and will be removed. Use SpriteAtlasImporter.IsIncludeInBuild instead.")]
+ public bool IsIncludeInBuild() { return true; }
+ [Obsolete("SetPlatformSettings is no longer supported and will be removed. Use SpriteAtlasImporter.SetPlatformSettings instead.")]
+ public void SetPlatformSettings(TextureImporterPlatformSettings src) { }
+ [Obsolete("SetTextureSettings is no longer supported and will be removed. Use SpriteAtlasImporter.SetTextureSettings instead.")]
+ public void SetTextureSettings(SpriteAtlasTextureSettings src) { }
+ [Obsolete("SetPackingSettings is no longer supported and will be removed. Use SpriteAtlasImporter.SetPackingSettings instead.")]
+ public void SetPackingSettings(SpriteAtlasPackingSettings src) { }
+ [Obsolete("GetPackingSettings is no longer supported and will be removed. Use SpriteAtlasImporter.GetPackingSettings instead.")]
+ public SpriteAtlasPackingSettings GetPackingSettings() { return new SpriteAtlasPackingSettings(); }
+ [Obsolete("GetTextureSettings is no longer supported and will be removed. Use SpriteAtlasImporter.GetTextureSettings instead.")]
+ public SpriteAtlasTextureSettings GetTextureSettings() { return new SpriteAtlasTextureSettings(); }
+ [Obsolete("GetPlatformSettings is no longer supported and will be removed. Use SpriteAtlasImporter.GetPlatformSettingss instead.")]
+ public TextureImporterPlatformSettings GetPlatformSettings(string buildTarget) { return new TextureImporterPlatformSettings(); }
+
+ // Load SpriteAtlasAsset
+ public static SpriteAtlasAsset Load(string assetPath)
+ {
+ var objs = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(assetPath);
+ return (objs.Length > 0) ? objs[0] as SpriteAtlasAsset : null;
+ }
+
+ public static void Save(SpriteAtlasAsset asset, string assetPath)
+ {
+ if (asset == null)
+ throw new ArgumentNullException("Parameter asset is null");
+ var objs = new UnityEngine.Object[] { asset };
+ UnityEditorInternal.InternalEditorUtility.SaveToSerializedFileAndForget(objs, assetPath, UnityEditor.EditorSettings.serializationMode != UnityEditor.SerializationMode.ForceBinary);
+ }
}
};
diff --git a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporter.bindings.cs b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporter.bindings.cs
index 99058c98dc..12a8178c4f 100644
--- a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporter.bindings.cs
+++ b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporter.bindings.cs
@@ -6,7 +6,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using UnityEditor.Build;
-using UnityEditor.Experimental.AssetImporters;
+using UnityEditor.AssetImporters;
using UnityEngine;
using UnityEngine.Bindings;
using UnityEngine.Scripting;
@@ -15,9 +15,52 @@
namespace UnityEditor.U2D
{
// SpriteAtlas Importer lets you modify [[SpriteAtlas]]
+ [HelpURL("https://docs.unity3d.com/6000.2/Documentation/Manual/sprite/atlas/v2/sprite-atlas-v2.html")]
[NativeHeader("Editor/Src/2D/SpriteAtlas/SpriteAtlasImporter.h")]
public sealed partial class SpriteAtlasImporter : AssetImporter
{
extern internal static void MigrateAllSpriteAtlases();
+ extern public float variantScale { get; set; }
+ extern public bool includeInBuild { get; set; }
+ extern public SpriteAtlasPackingSettings packingSettings { get; set; }
+ extern public SpriteAtlasTextureSettings textureSettings { get; set; }
+
+ [NativeName("SetPlatformSettings")]
+ extern private void SetPlatformSettings_Internal(TextureImporterPlatformSettings src);
+ public void SetPlatformSettings(TextureImporterPlatformSettings src)
+ {
+ src.name = TextureImporter.GetTexturePlatformSerializationName(src.name); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ SetPlatformSettings_Internal(src);
+ }
+
+ [NativeName("GetPlatformSettings")]
+ extern private TextureImporterPlatformSettings GetPlatformSettings_Internal(string buildTarget);
+ public TextureImporterPlatformSettings GetPlatformSettings(string buildTarget)
+ {
+ buildTarget = TextureImporter.GetTexturePlatformSerializationName(buildTarget); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ return GetPlatformSettings_Internal(buildTarget);
+ }
+
+ extern internal TextureFormat GetTextureFormat(BuildTarget target);
+
+ [NativeName("GetSecondaryPlatformSettings")]
+ extern private TextureImporterPlatformSettings GetSecondaryPlatformSettings_Internal(string buildTarget, string secondaryTextureName);
+ internal TextureImporterPlatformSettings GetSecondaryPlatformSettings(string buildTarget, string secondaryTextureName)
+ {
+ buildTarget = TextureImporter.GetTexturePlatformSerializationName(buildTarget); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ return GetSecondaryPlatformSettings_Internal(buildTarget, secondaryTextureName);
+ }
+
+ [NativeName("SetSecondaryPlatformSettings")]
+ extern private void SetSecondaryPlatformSettings_Internal(TextureImporterPlatformSettings src, string secondaryTextureName);
+ internal void SetSecondaryPlatformSettings(TextureImporterPlatformSettings src, string secondaryTextureName)
+ {
+ src.name = TextureImporter.GetTexturePlatformSerializationName(src.name); // String may refer to a platform group: if != "Standalone", ensure it refers to a platform instead. E.g.: "iOS", not "iPhone".
+ SetSecondaryPlatformSettings_Internal(src, secondaryTextureName);
+ }
+
+ extern internal bool GetSecondaryColorSpace(string secondaryTextureName);
+ extern internal void SetSecondaryColorSpace(string secondaryTextureName, bool srGB);
+ extern internal void DeleteSecondaryPlatformSettings(string secondaryTextureName);
}
};
diff --git a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporterInspector.cs b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporterInspector.cs
index 39f8b1992e..2251994103 100644
--- a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporterInspector.cs
+++ b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasImporterInspector.cs
@@ -2,6 +2,7 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
@@ -10,11 +11,12 @@
using UnityEditor.U2D.Common;
using UnityEditor.U2D.Interface;
using UnityEditorInternal;
+using UnityEditor.AssetImporters;
namespace UnityEditor.U2D
{
[CustomEditor(typeof(SpriteAtlasImporter))]
- internal class SpriteAtlasImporterInspector : Editor
+ internal class SpriteAtlasImporterInspector : AssetImporterEditor
{
class SpriteAtlasInspectorPlatformSettingView : TexturePlatformSettingsView
{
@@ -49,19 +51,22 @@ class Styles
public readonly GUIContent atlasTypeLabel = EditorGUIUtility.TrTextContent("Type");
public readonly GUIContent defaultPlatformLabel = EditorGUIUtility.TrTextContent("Default");
public readonly GUIContent masterAtlasLabel = EditorGUIUtility.TrTextContent("Master Atlas", "Assigning another Sprite Atlas asset will make this atlas a variant of it.");
+ public readonly GUIContent packerLabel = EditorGUIUtility.TrTextContent("Scriptable Packer", "Scriptable Object that implements custom packing for Sprite-Atlas.");
public readonly GUIContent bindAsDefaultLabel = EditorGUIUtility.TrTextContent("Include in Build", "Packed textures will be included in the build by default.");
public readonly GUIContent enableRotationLabel = EditorGUIUtility.TrTextContent("Allow Rotation", "Try rotating the sprite to fit better during packing.");
public readonly GUIContent enableTightPackingLabel = EditorGUIUtility.TrTextContent("Tight Packing", "Use the mesh outline to fit instead of the whole texture rect during packing.");
+ public readonly GUIContent enableAlphaDilationLabel = EditorGUIUtility.TrTextContent("Alpha Dilation", "Enable Alpha Dilation for SpriteAtlas padding pixels.");
public readonly GUIContent paddingLabel = EditorGUIUtility.TrTextContent("Padding", "The amount of extra padding between packed sprites.");
public readonly GUIContent generateMipMapLabel = EditorGUIUtility.TrTextContent("Generate Mip Maps");
+ public readonly GUIContent packPreviewLabel = EditorGUIUtility.TrTextContent("Pack Preview", "Save and preview packed Sprite Atlas textures.");
public readonly GUIContent sRGBLabel = EditorGUIUtility.TrTextContent("sRGB", "Texture content is stored in gamma space.");
- public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code.");
+ public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write", "Enable to be able to access the raw pixel data from code.");
public readonly GUIContent variantMultiplierLabel = EditorGUIUtility.TrTextContent("Scale", "Down scale ratio.");
public readonly GUIContent copyMasterButton = EditorGUIUtility.TrTextContent("Copy Master's Settings", "Copy all master's settings into this variant.");
public readonly GUIContent disabledPackLabel = EditorGUIUtility.TrTextContent("Sprite Atlas packing is disabled. Enable it in Edit > Project Settings > Editor.", null, EditorGUIUtility.GetHelpIcon(MessageType.Info));
- public readonly GUIContent packableListLabel = EditorGUIUtility.TrTextContent("Objects for Packing", "Only accepts Sprite Sheet (Texture) and Sprite.");
+ public readonly GUIContent packableListLabel = EditorGUIUtility.TrTextContent("Objects for Packing", "Only accepts Folders, Sprite Sheet (Texture) and Sprite.");
public readonly GUIContent notPowerOfTwoWarning = EditorGUIUtility.TrTextContent("This scale will produce a Variant Sprite Atlas with a packed Texture that is NPOT (non - power of two). This may cause visual artifacts in certain compression/Texture formats.");
public readonly GUIContent secondaryTextureNameLabel = EditorGUIUtility.TrTextContent("Secondary Texture Name", "The name of the Secondary Texture to apply the following settings to.");
@@ -76,6 +81,7 @@ class Styles
public readonly int packableElementHash = "PackableElement".GetHashCode();
public readonly int packableSelectorHash = "PackableSelector".GetHashCode();
+ public readonly string swapObjectRegisterUndo = L10n.Tr("Swap Packable");
public readonly string secondaryTextureNameTextControlName = "secondary_texture_name_text_field";
public readonly string defaultTextForSecondaryTextureName = L10n.Tr("(Matches the names of the Secondary Textures in your Sprites.)");
public readonly string nameUniquenessWarning = L10n.Tr("Secondary Texture names must be unique within a Sprite or Sprite Atlas.");
@@ -108,8 +114,14 @@ private static Styles styles
return s_Styles;
}
}
- private SpriteAtlasAsset spriteAtlasAsset { get { return m_TargetAsset as SpriteAtlasAsset; } }
- private SpriteAtlasImporter spriteAtlasImporter { get { return target as SpriteAtlasImporter; } }
+ private SpriteAtlasAsset spriteAtlasAsset
+ {
+ get { return m_TargetAsset; }
+ }
+ private SpriteAtlasImporter spriteAtlasImporter
+ {
+ get { return target as SpriteAtlasImporter; }
+ }
private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 }
private SerializedProperty m_FilterMode;
@@ -118,6 +130,7 @@ private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 }
private SerializedProperty m_Readable;
private SerializedProperty m_UseSRGB;
private SerializedProperty m_EnableTightPacking;
+ private SerializedProperty m_EnableAlphaDilation;
private SerializedProperty m_EnableRotation;
private SerializedProperty m_Padding;
private SerializedProperty m_BindAsDefault;
@@ -125,6 +138,7 @@ private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 }
private SerializedProperty m_MasterAtlas;
private SerializedProperty m_VariantScale;
+ private SerializedProperty m_ScriptablePacker;
private string m_Hash;
private int m_PreviewPage = 0;
@@ -141,11 +155,12 @@ private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 }
private float m_MipLevel = 0;
private bool m_ShowAlpha;
- private bool m_HasChanged = false;
+ private bool m_Discard = false;
private List m_PlatformSettingsOptions;
private int m_SelectedPlatformSettings = 0;
+ private int m_ContentHash = 0;
private List m_ValidPlatforms;
private Dictionary> m_TempPlatformSettings;
@@ -160,7 +175,7 @@ private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 }
static bool IsPackable(Object o)
{
- return o != null && (o.GetType() == typeof(Sprite) || o.GetType() == typeof(Texture2D));
+ return o != null && (o.GetType() == typeof(Sprite) || o.GetType() == typeof(Texture2D) || (o.GetType() == typeof(DefaultAsset) && ProjectWindowUtil.IsFolder(o.GetInstanceID())));
}
static Object ValidateObjectForPackableFieldAssignment(Object[] references, System.Type objType, SerializedProperty property, EditorGUI.ObjectFieldValidatorOptions options)
@@ -173,12 +188,22 @@ static Object ValidateObjectForPackableFieldAssignment(Object[] references, Syst
bool IsTargetVariant()
{
- return spriteAtlasAsset.isVariant;
+ return spriteAtlasAsset ? spriteAtlasAsset.isVariant : false;
}
bool IsTargetMaster()
{
- return !spriteAtlasAsset.isVariant;
+ return spriteAtlasAsset ? !spriteAtlasAsset.isVariant : true;
+ }
+
+ protected override bool needsApplyRevert => false;
+
+ internal override string targetTitle
+ {
+ get
+ {
+ return spriteAtlasAsset ? ( Path.GetFileNameWithoutExtension(m_AssetPath) + " (Sprite Atlas)" ) : "SpriteAtlasImporter Settings";
+ }
}
private string LoadSourceAsset()
@@ -197,6 +222,44 @@ private SerializedObject serializedAssetObject
return GetSerializedAssetObject();
}
}
+
+ internal static int SpriteAtlasAssetHash(SerializedObject obj)
+ {
+ int hashCode = 0;
+ if (obj == null)
+ return 0;
+ unchecked
+ {
+ hashCode = (int)2166136261 ^ (int) obj.FindProperty("m_MasterAtlas").contentHash;
+ hashCode = hashCode * 16777619 ^ (int) obj.FindProperty("m_ImporterData").contentHash;
+ hashCode = hashCode * 16777619 ^ (int) obj.FindProperty("m_IsVariant").contentHash;
+ hashCode = hashCode * 16777619 ^ (int)obj.FindProperty("m_ScriptablePacker").contentHash;
+ }
+ return hashCode;
+ }
+
+ internal static int SpriteAtlasImporterHash(SerializedObject obj)
+ {
+ int hashCode = 0;
+ if (obj == null)
+ return 0;
+ unchecked
+ {
+ hashCode = (int)2166136261 ^ (int)obj.FindProperty("m_PackingSettings").contentHash;
+ hashCode = hashCode * 16777619 ^ (int)obj.FindProperty("m_TextureSettings").contentHash;
+ hashCode = hashCode * 16777619 ^ (int)obj.FindProperty("m_PlatformSettings").contentHash;
+ hashCode = hashCode * 16777619 ^ (int)obj.FindProperty("m_SecondaryTextureSettings").contentHash;
+ hashCode = hashCode * 16777619 ^ (int)obj.FindProperty("m_BindAsDefault").contentHash;
+ hashCode = hashCode * 16777619 ^ (int)obj.FindProperty("m_VariantMultiplier").contentHash;
+ }
+ return hashCode;
+ }
+
+ internal int GetInspectorHash()
+ {
+ return SpriteAtlasAssetHash(m_SerializedAssetObject) * 16777619 ^ SpriteAtlasImporterHash(m_SerializedObject);
+ }
+
private SerializedObject GetSerializedAssetObject()
{
if (m_SerializedAssetObject == null)
@@ -205,6 +268,7 @@ private SerializedObject GetSerializedAssetObject()
{
m_SerializedAssetObject = new SerializedObject(spriteAtlasAsset, m_Context);
m_SerializedAssetObject.inspectorMode = inspectorMode;
+ m_ContentHash = GetInspectorHash();
m_EnabledProperty = m_SerializedAssetObject.FindProperty("m_Enabled");
}
catch (System.ArgumentException e)
@@ -217,36 +281,24 @@ private SerializedObject GetSerializedAssetObject()
return m_SerializedAssetObject;
}
- void OnEnable()
+ public override void OnEnable()
{
- m_AssetPath = LoadSourceAsset();
- if (spriteAtlasAsset == null)
- return;
-
- m_FilterMode = serializedAssetObject.FindProperty("m_ImporterData.textureSettings.filterMode");
- m_AnisoLevel = serializedAssetObject.FindProperty("m_ImporterData.textureSettings.anisoLevel");
- m_GenerateMipMaps = serializedAssetObject.FindProperty("m_ImporterData.textureSettings.generateMipMaps");
- m_Readable = serializedAssetObject.FindProperty("m_ImporterData.textureSettings.readable");
- m_UseSRGB = serializedAssetObject.FindProperty("m_ImporterData.textureSettings.sRGB");
+ base.OnEnable();
- m_EnableTightPacking = serializedAssetObject.FindProperty("m_ImporterData.packingSettings.enableTightPacking");
- m_EnableRotation = serializedAssetObject.FindProperty("m_ImporterData.packingSettings.enableRotation");
- m_Padding = serializedAssetObject.FindProperty("m_ImporterData.packingSettings.padding");
-
- m_MasterAtlas = serializedAssetObject.FindProperty("m_MasterAtlas");
- m_BindAsDefault = serializedAssetObject.FindProperty("m_ImporterData.bindAsDefault");
- m_VariantScale = serializedAssetObject.FindProperty("m_ImporterData.variantMultiplier");
+ m_FilterMode = serializedObject.FindProperty("m_TextureSettings.filterMode");
+ m_AnisoLevel = serializedObject.FindProperty("m_TextureSettings.anisoLevel");
+ m_GenerateMipMaps = serializedObject.FindProperty("m_TextureSettings.generateMipMaps");
+ m_Readable = serializedObject.FindProperty("m_TextureSettings.readable");
+ m_UseSRGB = serializedObject.FindProperty("m_TextureSettings.sRGB");
+ m_EnableTightPacking = serializedObject.FindProperty("m_PackingSettings.enableTightPacking");
+ m_EnableRotation = serializedObject.FindProperty("m_PackingSettings.enableRotation");
+ m_EnableAlphaDilation = serializedObject.FindProperty("m_PackingSettings.enableAlphaDilation");
+ m_Padding = serializedObject.FindProperty("m_PackingSettings.padding");
+ m_BindAsDefault = serializedObject.FindProperty("m_BindAsDefault");
+ m_VariantScale = serializedObject.FindProperty("m_VariantMultiplier");
PopulatePlatformSettingsOptions();
- m_Packables = serializedAssetObject.FindProperty("m_ImporterData.packables");
- m_PackableList = new ReorderableList(serializedAssetObject, m_Packables, true, true, true, true);
- m_PackableList.onAddCallback = AddPackable;
- m_PackableList.onRemoveCallback = RemovePackable;
- m_PackableList.drawElementCallback = DrawPackableElement;
- m_PackableList.elementHeight = EditorGUIUtility.singleLineHeight;
- m_PackableList.headerHeight = 0f;
-
SyncPlatformSettings();
m_TexturePlatformSettingsView = new SpriteAtlasInspectorPlatformSettingView(IsTargetMaster());
@@ -255,13 +307,26 @@ void OnEnable()
// Don't show max size option for secondary textures as they must have the same size as the main texture.
m_SecondaryTexturePlatformSettingsView = new SpriteAtlasInspectorPlatformSettingView(false);
+
+ m_AssetPath = LoadSourceAsset();
+ if (spriteAtlasAsset == null)
+ return;
+
+ m_MasterAtlas = serializedAssetObject.FindProperty("m_MasterAtlas");
+ m_ScriptablePacker = serializedAssetObject.FindProperty("m_ScriptablePacker");
+ m_Packables = serializedAssetObject.FindProperty("m_ImporterData.packables");
+ m_PackableList = new ReorderableList(serializedAssetObject, m_Packables, true, true, true, true);
+ m_PackableList.onAddCallback = AddPackable;
+ m_PackableList.drawElementCallback = DrawPackableElement;
+ m_PackableList.elementHeight = EditorGUIUtility.singleLineHeight;
+ m_PackableList.headerHeight = 0f;
}
// Populate the platform settings dropdown list with secondary texture names found through serialized properties of the Sprite Atlas assets.
private void PopulatePlatformSettingsOptions()
{
m_PlatformSettingsOptions = new List { L10n.Tr("Main Texture"), "", "", L10n.Tr("New Secondary Texture settings.") };
- SerializedProperty secondaryPlatformSettings = serializedAssetObject.FindProperty("m_ImporterData.secondaryTextureSettings");
+ SerializedProperty secondaryPlatformSettings = serializedObject.FindProperty("m_SecondaryTextureSettings");
if (secondaryPlatformSettings != null && !secondaryPlatformSettings.hasMultipleDifferentValues)
{
int numSecondaryTextures = secondaryPlatformSettings.arraySize;
@@ -289,8 +354,8 @@ void SyncPlatformSettings()
var defaultSettings = new List();
m_TempPlatformSettings.Add(TextureImporterInspector.s_DefaultPlatformName, defaultSettings);
var settings = secondaryTextureSelected
- ? spriteAtlasAsset.GetSecondaryPlatformSettings(TextureImporterInspector.s_DefaultPlatformName, secondaryTextureName)
- : spriteAtlasAsset.GetPlatformSettings(TextureImporterInspector.s_DefaultPlatformName);
+ ? spriteAtlasImporter.GetSecondaryPlatformSettings(TextureImporterInspector.s_DefaultPlatformName, secondaryTextureName)
+ : spriteAtlasImporter.GetPlatformSettings(TextureImporterInspector.s_DefaultPlatformName);
defaultSettings.Add(settings);
m_ValidPlatforms = BuildPlatforms.instance.GetValidPlatforms();
@@ -298,7 +363,7 @@ void SyncPlatformSettings()
{
var platformSettings = new List();
m_TempPlatformSettings.Add(platform.name, platformSettings);
- var perPlatformSettings = secondaryTextureSelected ? spriteAtlasAsset.GetSecondaryPlatformSettings(platform.name, secondaryTextureName) : spriteAtlasAsset.GetPlatformSettings(platform.name);
+ var perPlatformSettings = secondaryTextureSelected ? spriteAtlasImporter.GetSecondaryPlatformSettings(platform.name, secondaryTextureName) : spriteAtlasImporter.GetPlatformSettings(platform.name);
// setting will be in default state if copy failed
platformSettings.Add(perPlatformSettings);
}
@@ -306,32 +371,25 @@ void SyncPlatformSettings()
void RenameSecondaryPlatformSettings(string oldName, string newName)
{
- spriteAtlasAsset.DeleteSecondaryPlatformSettings(oldName);
+ spriteAtlasImporter.DeleteSecondaryPlatformSettings(oldName);
var defaultPlatformSettings = m_TempPlatformSettings[TextureImporterInspector.s_DefaultPlatformName];
- spriteAtlasAsset.SetSecondaryPlatformSettings(defaultPlatformSettings[0], newName);
+ spriteAtlasImporter.SetSecondaryPlatformSettings(defaultPlatformSettings[0], newName);
foreach (var buildPlatform in m_ValidPlatforms)
{
var platformSettings = m_TempPlatformSettings[buildPlatform.name];
- spriteAtlasAsset.SetSecondaryPlatformSettings(platformSettings[0], newName);
+ spriteAtlasImporter.SetSecondaryPlatformSettings(platformSettings[0], newName);
}
}
void AddPackable(ReorderableList list)
{
ObjectSelector.get.Show(null, typeof(Object), null, false);
- ObjectSelector.get.searchFilter = "t:sprite t:texture2d";
+ ObjectSelector.get.searchFilter = "t:sprite t:texture2d t:folder";
ObjectSelector.get.objectSelectorID = styles.packableSelectorHash;
}
- void RemovePackable(ReorderableList list)
- {
- var index = list.index;
- if (index != -1)
- spriteAtlasAsset.RemoveAt(index);
- }
-
void DrawPackableElement(Rect rect, int index, bool selected, bool focused)
{
var property = m_Packables.GetArrayElementAtIndex(index);
@@ -341,10 +399,7 @@ void DrawPackableElement(Rect rect, int index, bool selected, bool focused)
var changedObject = EditorGUI.DoObjectField(rect, rect, controlID, previousObject, target, typeof(Object), ValidateObjectForPackableFieldAssignment, false);
if (changedObject != previousObject)
{
- // Always call Remove() on the previous object if we swapping the object field item.
- // This ensure the Sprites was pack in this atlas will be refreshed of it unbound.
- if (previousObject != null)
- spriteAtlasAsset.Remove(new Object[] { previousObject });
+ Undo.RegisterCompleteObjectUndo(spriteAtlasAsset, styles.swapObjectRegisterUndo);
property.objectReferenceValue = changedObject;
}
@@ -352,44 +407,39 @@ void DrawPackableElement(Rect rect, int index, bool selected, bool focused)
m_PackableList.index = index;
}
- public virtual void OnDestroy()
+ protected override void Apply()
{
if (HasModified())
{
- ApplyAndImport();
- }
- }
+ if (spriteAtlasAsset)
+ {
+ SpriteAtlasAsset.Save(spriteAtlasAsset, m_AssetPath);
+ AssetDatabase.ImportAsset(m_AssetPath);
+ }
- protected void Apply()
- {
- if (HasModified())
- {
- serializedAssetObject.ApplyModifiedPropertiesWithoutUndo();
- InternalEditorUtility.SaveToSerializedFileAndForget(new Object[] { spriteAtlasAsset }, m_AssetPath, true);
+ m_ContentHash = GetInspectorHash();
}
+ base.Apply();
}
- public void ApplyAndImport()
- {
- Apply();
- AssetDatabase.ImportAsset(m_AssetPath);
- }
+ protected override bool useAssetDrawPreview { get { return false; } }
- protected void ApplyRevertGUI()
+ protected void PackPreviewGUI()
{
EditorGUILayout.Space();
using (new GUILayout.HorizontalScope())
{
- using (new EditorGUI.DisabledScope(!HasModified() || !IsValidAtlas()))
+ using (new EditorGUI.DisabledScope(!HasModified() || !IsValidAtlas() || Application.isPlaying))
{
GUILayout.FlexibleSpace();
- if (GUILayout.Button("Pack Preview"))
+ if (GUILayout.Button(styles.packPreviewLabel))
{
GUI.FocusControl(null);
- ApplyAndImport();
- m_HasChanged = false;
+ SpriteAtlasUtility.EnableV2Import(true);
+ SaveChanges();
+ SpriteAtlasUtility.EnableV2Import(false);
}
}
}
@@ -403,9 +453,9 @@ private bool IsValidAtlas()
return true;
}
- public bool HasModified()
+ public override bool HasModified()
{
- return m_HasChanged;
+ return !m_Discard && (base.HasModified() || m_ContentHash != GetInspectorHash());
}
private void ValidateMasterAtlas()
@@ -432,24 +482,27 @@ private void ValidateMasterAtlas()
public override void OnInspectorGUI()
{
- if (spriteAtlasAsset == null)
- return;
-
- EditorGUI.BeginChangeCheck();
-
// Ensure changes done through script are reflected immediately in Inspector by Syncing m_TempPlatformSettings with Actual Settings.
SyncPlatformSettings();
- serializedAssetObject.Update();
-
- HandleCommonSettingUI();
+ serializedObject.Update();
+ if (spriteAtlasAsset)
+ {
+ serializedAssetObject.Update();
+ HandleCommonSettingUI();
+ }
+ EditorGUILayout.PropertyField(m_BindAsDefault, styles.bindAsDefaultLabel);
GUILayout.Space(EditorGUI.kSpacing);
- if (IsTargetVariant())
- HandleVariantSettingUI();
- else if (IsTargetMaster())
+ bool isTargetMaster = true;
+ if (spriteAtlasAsset)
+ isTargetMaster = IsTargetMaster();
+
+ if (isTargetMaster)
HandleMasterSettingUI();
+ if (!spriteAtlasAsset || IsTargetVariant())
+ HandleVariantSettingUI();
GUILayout.Space(EditorGUI.kSpacing);
@@ -459,15 +512,16 @@ public override void OnInspectorGUI()
// Only show the packable object list when:
// - This is a master atlas.
- if (targets.Length == 1 && IsTargetMaster())
+ if (targets.Length == 1 && IsTargetMaster() && spriteAtlasAsset)
HandlePackableListUI();
- serializedAssetObject.ApplyModifiedPropertiesWithoutUndo();
-
- if (EditorGUI.EndChangeCheck())
+ serializedObject.ApplyModifiedProperties();
+ if (spriteAtlasAsset)
{
- m_HasChanged = true;
+ serializedAssetObject.ApplyModifiedProperties();
+ PackPreviewGUI();
}
+
ApplyRevertGUI();
}
@@ -491,7 +545,7 @@ private void HandleCommonSettingUI()
// Reinit the platform setting view
m_TexturePlatformSettingsView = new SpriteAtlasInspectorPlatformSettingView(IsTargetMaster());
}
-
+ m_ScriptablePacker.objectReferenceValue = EditorGUILayout.ObjectField(styles.packerLabel, m_ScriptablePacker.objectReferenceValue, typeof(UnityEditor.U2D.ScriptablePacker), false);
if (atlasType == AtlasType.Variant)
{
EditorGUI.BeginChangeCheck();
@@ -501,13 +555,10 @@ private void HandleCommonSettingUI()
ValidateMasterAtlas();
// Apply modified properties here to have latest master atlas reflected in native codes.
serializedAssetObject.ApplyModifiedPropertiesWithoutUndo();
- spriteAtlasAsset.CopyMasterAtlasSettings();
PopulatePlatformSettingsOptions();
SyncPlatformSettings();
}
}
-
- EditorGUILayout.PropertyField(m_BindAsDefault, styles.bindAsDefaultLabel);
}
private void HandleVariantSettingUI()
@@ -537,6 +588,7 @@ private void HandleMasterSettingUI()
HandleBoolToIntPropertyField(m_EnableRotation, styles.enableRotationLabel);
HandleBoolToIntPropertyField(m_EnableTightPacking, styles.enableTightPackingLabel);
+ HandleBoolToIntPropertyField(m_EnableAlphaDilation, styles.enableAlphaDilationLabel);
EditorGUILayout.IntPopup(m_Padding, styles.paddingOptions, styles.paddingValues, styles.paddingLabel);
GUILayout.Space(EditorGUI.kSpacing);
@@ -574,7 +626,6 @@ private void HandleTextureSettingUI()
m_SelectedPlatformSettings--;
EditorGUI.FocusTextInControl(s_Styles.secondaryTextureNameTextControlName);
}
- m_HasChanged = true;
SyncPlatformSettings();
}
@@ -585,7 +636,7 @@ private void HandleTextureSettingUI()
{
EditorGUI.EndEditingActiveTextField();
- spriteAtlasAsset.DeleteSecondaryPlatformSettings(m_PlatformSettingsOptions[m_SelectedPlatformSettings]);
+ spriteAtlasImporter.DeleteSecondaryPlatformSettings(m_PlatformSettingsOptions[m_SelectedPlatformSettings]);
m_PlatformSettingsOptions.RemoveAt(m_SelectedPlatformSettings);
@@ -593,7 +644,6 @@ private void HandleTextureSettingUI()
if (m_SelectedPlatformSettings == 1)
m_SelectedPlatformSettings = 0;
- m_HasChanged = true;
SyncPlatformSettings();
}
}
@@ -608,11 +658,15 @@ private void HandleTextureSettingUI()
EditorGUI.indentLevel--;
if (m_SelectedPlatformSettings == 0)
+ {
+ GUILayout.Space(EditorGUI.kSpacing);
HandlePlatformSettingUI(null);
+ }
else
{
EditorGUILayout.BeginVertical();
{
+ GUILayout.Space(EditorGUI.kSpacing);
string oldSecondaryTextureName = m_PlatformSettingsOptions[m_SelectedPlatformSettings];
GUI.SetNextControlName(s_Styles.secondaryTextureNameTextControlName);
@@ -630,14 +684,13 @@ private void HandleTextureSettingUI()
Debug.LogWarning(s_Styles.nameUniquenessWarning);
EditorGUI.FocusTextInControl(s_Styles.secondaryTextureNameTextControlName);
}
- m_HasChanged = true;
}
string secondaryTextureName = m_PlatformSettingsOptions[m_SelectedPlatformSettings];
EditorGUI.BeginChangeCheck();
- bool value = EditorGUILayout.Toggle(s_Styles.sRGBLabel, spriteAtlasAsset.GetSecondaryColorSpace(secondaryTextureName));
+ bool value = EditorGUILayout.Toggle(s_Styles.sRGBLabel, spriteAtlasImporter.GetSecondaryColorSpace(secondaryTextureName));
if (EditorGUI.EndChangeCheck())
- spriteAtlasAsset.SetSecondaryColorSpace(secondaryTextureName, value);
+ spriteAtlasImporter.SetSecondaryColorSpace(secondaryTextureName, value);
HandlePlatformSettingUI(textFieldText);
}
@@ -655,16 +708,15 @@ private void HandlePlatformSettingUI(string secondaryTextureName)
ITexturePlatformSettingsView view = isSecondary ? m_SecondaryTexturePlatformSettingsView : m_TexturePlatformSettingsView;
if (shownTextureFormatPage == -1)
{
- if (m_TexturePlatformSettingsController.HandleDefaultSettings(defaultPlatformSettings, m_TexturePlatformSettingsView, m_TexturePlatformSettingTextureHelper))
+ if (m_TexturePlatformSettingsController.HandleDefaultSettings(defaultPlatformSettings, view, m_TexturePlatformSettingTextureHelper))
{
for (var i = 0; i < defaultPlatformSettings.Count; ++i)
{
if (isSecondary)
- spriteAtlasAsset.SetSecondaryPlatformSettings(defaultPlatformSettings[i], secondaryTextureName);
+ spriteAtlasImporter.SetSecondaryPlatformSettings(defaultPlatformSettings[i], secondaryTextureName);
else
- spriteAtlasAsset.SetPlatformSettings(defaultPlatformSettings[i]);
+ spriteAtlasImporter.SetPlatformSettings(defaultPlatformSettings[i]);
}
- m_HasChanged = true;
}
}
else
@@ -680,7 +732,7 @@ private void HandlePlatformSettingUI(string secondaryTextureName)
{
if (defaultPlatformSettings[0].format == TextureImporterFormat.Automatic)
{
- settings.format = (TextureImporterFormat)spriteAtlasAsset.GetTextureFormat(buildPlatform.defaultTarget);
+ settings.format = (TextureImporterFormat)spriteAtlasImporter.GetTextureFormat(buildPlatform.defaultTarget);
}
else
{
@@ -694,16 +746,15 @@ private void HandlePlatformSettingUI(string secondaryTextureName)
}
m_TexturePlatformSettingsView.buildPlatformTitle = buildPlatform.title.text;
- if (m_TexturePlatformSettingsController.HandlePlatformSettings(buildPlatform.defaultTarget, platformSettings, m_TexturePlatformSettingsView, m_TexturePlatformSettingTextureHelper))
+ if (m_TexturePlatformSettingsController.HandlePlatformSettings(buildPlatform.defaultTarget, platformSettings, view, m_TexturePlatformSettingTextureHelper))
{
for (var i = 0; i < platformSettings.Count; ++i)
{
if (isSecondary)
- spriteAtlasAsset.SetSecondaryPlatformSettings(platformSettings[i], secondaryTextureName);
+ spriteAtlasImporter.SetSecondaryPlatformSettings(platformSettings[i], secondaryTextureName);
else
- spriteAtlasAsset.SetPlatformSettings(platformSettings[i]);
+ spriteAtlasImporter.SetPlatformSettings(platformSettings[i]);
}
- m_HasChanged = true;
}
}
@@ -788,6 +839,20 @@ private void HandlePackableListUI()
}
}
+ public override void SaveChanges()
+ {
+ if (!m_Discard)
+ base.SaveChanges();
+ m_ContentHash = GetInspectorHash();
+ }
+
+ public override void DiscardChanges()
+ {
+ m_Discard = true;
+ base.DiscardChanges();
+ m_ContentHash = GetInspectorHash();
+ }
+
void CachePreviewTexture()
{
var spriteAtlas = AssetDatabase.LoadAssetAtPath(m_AssetPath);
@@ -814,24 +879,10 @@ void CachePreviewTexture()
m_OptionValues = new int[m_TotalPages];
for (int i = 0; i < m_TotalPages; ++i)
{
- // Example texName:
- // pageNum secondaryName
- // V | V |
- // sactx-2-128x128-Uncompressed-My Sprite Atlas-0fe925a#_Glow-var-0.5...
string texName = m_PreviewTextures[i].name;
- string pageNum = texName.Split('-')[1];
- int hashTag = texName.IndexOf('#');
- int dashAfterHashTag = hashTag != -1 ? texName.IndexOf('-', hashTag) : -1;
-
- string secondaryName;
- if (hashTag == -1)
- secondaryName = "";
- else if (dashAfterHashTag == -1)
- secondaryName = "-" + texName.Substring(hashTag + 1);
- else
- secondaryName = "-" + texName.Substring(hashTag + 1, dashAfterHashTag - hashTag - 1);
-
- m_OptionDisplays[i] = string.Format("#{0}{1}", pageNum, secondaryName);
+ var pageNum = SpriteAtlasExtensions.GetPageNumberInAtlas(texName);
+ var secondaryName = SpriteAtlasExtensions.GetSecondaryTextureNameInAtlas(texName);
+ m_OptionDisplays[i] = secondaryName == "" ? string.Format("MainTex - Page ({0})", pageNum) : string.Format("{0} - Page ({1})", secondaryName, pageNum);
m_OptionValues[i] = i;
}
}
@@ -878,7 +929,7 @@ public override void OnPreviewSettings()
if (t == null)
return;
- if (TextureUtil.HasAlphaTextureFormat(t.format) || (m_PreviewAlphaTextures != null && m_PreviewAlphaTextures.Length > 0))
+ if (GraphicsFormatUtility.HasAlphaChannel(t.format) || (m_PreviewAlphaTextures != null && m_PreviewAlphaTextures.Length > 0))
m_ShowAlpha = GUILayout.Toggle(m_ShowAlpha, m_ShowAlpha ? styles.alphaIcon : styles.RGBIcon, styles.previewButton);
int mipCount = Mathf.Max(1, TextureUtil.GetMipmapCount(t));
diff --git a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs
index 2d9dcf1e96..cebb1e79ff 100644
--- a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs
+++ b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs
@@ -53,11 +53,12 @@ class Styles
public readonly GUIContent bindAsDefaultLabel = EditorGUIUtility.TrTextContent("Include in Build", "Packed textures will be included in the build by default.");
public readonly GUIContent enableRotationLabel = EditorGUIUtility.TrTextContent("Allow Rotation", "Try rotating the sprite to fit better during packing.");
public readonly GUIContent enableTightPackingLabel = EditorGUIUtility.TrTextContent("Tight Packing", "Use the mesh outline to fit instead of the whole texture rect during packing.");
+ public readonly GUIContent enableAlphaDilationLabel = EditorGUIUtility.TrTextContent("Alpha Dilation", "Enable Alpha Dilation for SpriteAtlas padding pixels.");
public readonly GUIContent paddingLabel = EditorGUIUtility.TrTextContent("Padding", "The amount of extra padding between packed sprites.");
public readonly GUIContent generateMipMapLabel = EditorGUIUtility.TrTextContent("Generate Mip Maps");
public readonly GUIContent sRGBLabel = EditorGUIUtility.TrTextContent("sRGB", "Texture content is stored in gamma space.");
- public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code.");
+ public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write", "Enable to be able to access the raw pixel data from code.");
public readonly GUIContent variantMultiplierLabel = EditorGUIUtility.TrTextContent("Scale", "Down scale ratio.");
public readonly GUIContent packButton = EditorGUIUtility.TrTextContent("Pack Preview", "Pack this atlas.");
@@ -77,6 +78,7 @@ class Styles
public readonly int packableElementHash = "PackableElement".GetHashCode();
public readonly int packableSelectorHash = "PackableSelector".GetHashCode();
+ public readonly string swapObjectRegisterUndo = L10n.Tr("Swap Packable");
public readonly string secondaryTextureNameTextControlName = "secondary_texture_name_text_field";
public readonly string defaultTextForSecondaryTextureName = L10n.Tr("(Matches the names of the Secondary Textures in your Sprites.)");
public readonly string nameUniquenessWarning = L10n.Tr("Secondary Texture names must be unique within a Sprite or Sprite Atlas.");
@@ -118,6 +120,7 @@ private enum AtlasType { Undefined = -1, Master = 0, Variant = 1 }
private SerializedProperty m_Readable;
private SerializedProperty m_UseSRGB;
private SerializedProperty m_EnableTightPacking;
+ private SerializedProperty m_EnableAlphaDilation;
private SerializedProperty m_EnableRotation;
private SerializedProperty m_Padding;
private SerializedProperty m_BindAsDefault;
@@ -191,6 +194,17 @@ bool AllTargetsAreMaster()
void OnEnable()
{
+ if (targets == null)
+ return;
+ var validCount = 0;
+ foreach (var so in targets)
+ {
+ if (so != null)
+ validCount++;
+ }
+ if (validCount == 0)
+ return;
+
m_FilterMode = serializedObject.FindProperty("m_EditorData.textureSettings.filterMode");
m_AnisoLevel = serializedObject.FindProperty("m_EditorData.textureSettings.anisoLevel");
m_GenerateMipMaps = serializedObject.FindProperty("m_EditorData.textureSettings.generateMipMaps");
@@ -198,6 +212,7 @@ void OnEnable()
m_UseSRGB = serializedObject.FindProperty("m_EditorData.textureSettings.sRGB");
m_EnableTightPacking = serializedObject.FindProperty("m_EditorData.packingSettings.enableTightPacking");
+ m_EnableAlphaDilation = serializedObject.FindProperty("m_EditorData.packingSettings.enableAlphaDilation");
m_EnableRotation = serializedObject.FindProperty("m_EditorData.packingSettings.enableRotation");
m_Padding = serializedObject.FindProperty("m_EditorData.packingSettings.padding");
@@ -208,12 +223,13 @@ void OnEnable()
PopulatePlatformSettingsOptions();
m_Packables = serializedObject.FindProperty("m_EditorData.packables");
- m_PackableList = new ReorderableList(serializedObject, m_Packables, true, false, true, true);
+ m_PackableList = new ReorderableList(serializedObject, m_Packables, true, true, true, true);
+ m_PackableList.drawHeaderCallback = DrawPackablesHeader;
m_PackableList.onAddCallback = AddPackable;
m_PackableList.onRemoveCallback = RemovePackable;
m_PackableList.drawElementCallback = DrawPackableElement;
m_PackableList.elementHeight = EditorGUIUtility.singleLineHeight;
- m_PackableList.headerHeight = 3f;
+ m_PackableList.headerHeight = 3f + EditorGUIUtility.singleLineHeight;
SyncPlatformSettings();
@@ -301,6 +317,11 @@ void RenameSecondaryPlatformSettings(string oldName, string newName)
}
}
+ void DrawPackablesHeader(Rect headerRect)
+ {
+ EditorGUI.LabelField(headerRect, EditorGUIUtility.TempContent("Packables"));
+ }
+
void AddPackable(ReorderableList list)
{
ObjectSelector.get.Show(null, typeof(Object), null, false);
@@ -326,6 +347,7 @@ void DrawPackableElement(Rect rect, int index, bool selected, bool focused)
{
// Always call Remove() on the previous object if we swapping the object field item.
// This ensure the Sprites was pack in this atlas will be refreshed of it unbound.
+ Undo.RegisterCompleteObjectUndo(spriteAtlas, styles.swapObjectRegisterUndo);
if (previousObject != null)
spriteAtlas.Remove(new Object[] { previousObject });
property.objectReferenceValue = changedObject;
@@ -363,22 +385,25 @@ public override void OnInspectorGUI()
if (targets.Length == 1 && AllTargetsAreMaster())
HandlePackableListUI();
- bool spriteAtlasPackignEnabled = (EditorSettings.spritePackerMode == SpritePackerMode.BuildTimeOnlyAtlas
+ bool spriteAtlasPackingEnabled = (EditorSettings.spritePackerMode == SpritePackerMode.BuildTimeOnlyAtlas
|| EditorSettings.spritePackerMode == SpritePackerMode.AlwaysOnAtlas || EditorSettings.spritePackerMode == SpritePackerMode.SpriteAtlasV2);
- if (spriteAtlasPackignEnabled)
+ if (spriteAtlasPackingEnabled && !Application.isPlaying)
{
- if (GUILayout.Button(styles.packButton, GUILayout.ExpandWidth(false)))
+ using (new EditorGUI.DisabledScope(!Editor.IsPersistent(spriteAtlas)))
{
- SpriteAtlas[] spriteAtlases = new SpriteAtlas[targets.Length];
- for (int i = 0; i < spriteAtlases.Length; ++i)
- spriteAtlases[i] = (SpriteAtlas)targets[i];
+ if (GUILayout.Button(styles.packButton, GUILayout.ExpandWidth(false)))
+ {
+ SpriteAtlas[] spriteAtlases = new SpriteAtlas[targets.Length];
+ for (int i = 0; i < spriteAtlases.Length; ++i)
+ spriteAtlases[i] = (SpriteAtlas)targets[i];
- SpriteAtlasUtility.PackAtlases(spriteAtlases, EditorUserBuildSettings.activeBuildTarget);
+ SpriteAtlasUtility.PackAtlases(spriteAtlases, EditorUserBuildSettings.activeBuildTarget);
- // Packing an atlas might change platform settings in the process, reinitialize
- SyncPlatformSettings();
+ // Packing an atlas might change platform settings in the process, reinitialize
+ SyncPlatformSettings();
- GUIUtility.ExitGUI();
+ GUIUtility.ExitGUI();
+ }
}
}
else
@@ -402,7 +427,10 @@ private void HandleCommonSettingUI()
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = atlasType == AtlasType.Undefined;
- atlasType = (AtlasType)EditorGUILayout.IntPopup(styles.atlasTypeLabel, (int)atlasType, styles.atlasTypeOptions, styles.atlasTypeValues);
+ using (new EditorGUI.DisabledScope(!Editor.IsPersistent(spriteAtlas)))
+ {
+ atlasType = (AtlasType)EditorGUILayout.IntPopup(styles.atlasTypeLabel, (int)atlasType, styles.atlasTypeOptions, styles.atlasTypeValues);
+ }
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
@@ -461,6 +489,7 @@ private void HandleMasterSettingUI()
HandleBoolToIntPropertyField(m_EnableRotation, styles.enableRotationLabel);
HandleBoolToIntPropertyField(m_EnableTightPacking, styles.enableTightPackingLabel);
+ HandleBoolToIntPropertyField(m_EnableAlphaDilation, styles.enableAlphaDilationLabel);
EditorGUILayout.IntPopup(m_Padding, styles.paddingOptions, styles.paddingValues, styles.paddingLabel);
GUILayout.Space(EditorGUI.kSpacing);
@@ -532,11 +561,15 @@ private void HandleTextureSettingUI()
EditorGUI.indentLevel--;
if (m_SelectedPlatformSettings == 0)
+ {
+ GUILayout.Space(EditorGUI.kSpacing);
HandlePlatformSettingUI(null);
+ }
else
{
EditorGUILayout.BeginVertical();
{
+ GUILayout.Space(EditorGUI.kSpacing);
string oldSecondaryTextureName = m_PlatformSettingsOptions[m_SelectedPlatformSettings];
GUI.SetNextControlName(s_Styles.secondaryTextureNameTextControlName);
@@ -732,24 +765,10 @@ void CachePreviewTexture()
m_OptionValues = new int[m_TotalPages];
for (int i = 0; i < m_TotalPages; ++i)
{
- // Example texName:
- // pageNum secondaryName
- // V | V |
- // sactx-2-128x128-Uncompressed-My Sprite Atlas-0fe925a#_Glow-var-0.5...
string texName = m_PreviewTextures[i].name;
- string pageNum = texName.Split('-')[1];
- int hashTag = texName.IndexOf('#');
- int dashAfterHashTag = hashTag != -1 ? texName.IndexOf('-', hashTag) : -1;
-
- string secondaryName;
- if (hashTag == -1)
- secondaryName = "";
- else if (dashAfterHashTag == -1)
- secondaryName = "-" + texName.Substring(hashTag + 1);
- else
- secondaryName = "-" + texName.Substring(hashTag + 1, dashAfterHashTag - hashTag - 1);
-
- m_OptionDisplays[i] = string.Format("#{0}{1}", pageNum, secondaryName);
+ var pageNum = SpriteAtlasExtensions.GetPageNumberInAtlas(texName);
+ var secondaryName = SpriteAtlasExtensions.GetSecondaryTextureNameInAtlas(texName);
+ m_OptionDisplays[i] = secondaryName == "" ? string.Format("MainTex - Page ({0})", pageNum) : string.Format("{0} - Page ({1})", secondaryName, pageNum);
m_OptionValues[i] = i;
}
}
@@ -788,7 +807,7 @@ public override void OnPreviewSettings()
Texture2D t = m_PreviewTextures[m_PreviewPage];
- if (TextureUtil.HasAlphaTextureFormat(t.format) || (m_PreviewAlphaTextures != null && m_PreviewAlphaTextures.Length > 0))
+ if (GraphicsFormatUtility.HasAlphaChannel(t.format) || (m_PreviewAlphaTextures != null && m_PreviewAlphaTextures.Length > 0))
m_ShowAlpha = GUILayout.Toggle(m_ShowAlpha, m_ShowAlpha ? styles.alphaIcon : styles.RGBIcon, styles.previewButton);
int mipCount = Mathf.Max(1, TextureUtil.GetMipmapCount(t));
diff --git a/Editor/Mono/Animation/AnimationUtility.bindings.cs b/Editor/Mono/Animation/AnimationUtility.bindings.cs
index f3996af8d1..0b40f052e6 100644
--- a/Editor/Mono/Animation/AnimationUtility.bindings.cs
+++ b/Editor/Mono/Animation/AnimationUtility.bindings.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using UnityEngine.Bindings;
using UnityEngine.Scripting;
using UnityEngine.Scripting.APIUpdating;
@@ -11,6 +12,7 @@
using UnityEngine.Internal;
using Object = UnityEngine.Object;
+using UnityEngine.Animations;
namespace UnityEditor
{
@@ -52,6 +54,7 @@ public AnimationClipCurveData(EditorCurveBinding binding)
}
[NativeHeader("Editor/Src/Animation/AnimationUtility.bindings.h")]
+ [NativeHeader("Modules/Animation/ScriptBindings/GenericBinding.bindings.h")]
public partial class AnimationUtility
{
public enum CurveModifiedType
@@ -78,6 +81,15 @@ internal enum PolynomialValid
TooManySegments = 3
}
+ internal enum DiscreteBindingResult
+ {
+ Valid = 0,
+ InvalidScript = 1,
+ MissingField = 2,
+ IncompatibleFieldType = 3,
+ MissingDiscreteAttribute = 4
+ }
+
public delegate void OnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, CurveModifiedType type);
public static OnCurveWasModified onCurveWasModified;
@@ -118,7 +130,12 @@ public static AnimationClip[] GetAnimationClips(GameObject gameObject)
var extraClips = new List();
clipSources[i].GetAnimationClips(extraClips);
- allClips.AddRange(extraClips);
+ allClips.Capacity = allClips.Count + extraClips.Count;
+ foreach (var clip in extraClips)
+ {
+ if (clip != null)
+ allClips.Add(clip);
+ }
}
return allClips.ToArray();
@@ -131,7 +148,7 @@ public static AnimationClip[] GetAnimationClips(GameObject gameObject)
extern internal static AnimationClip[] GetAnimationClipsInAnimationPlayer([NotNull] GameObject gameObject);
// Sets the array of AnimationClips to be referenced in the Animation component
- extern public static void SetAnimationClips([NotNull] Animation animation, AnimationClip[] clips);
+ extern public static void SetAnimationClips([NotNull] Animation animation, [Unmarshalled] AnimationClip[] clips);
public static EditorCurveBinding[] GetAnimatableBindings(GameObject targetObject, GameObject root)
{
@@ -168,13 +185,14 @@ internal static System.Type GetEditorCurveValueType(ScriptableObject scriptableO
extern private static System.Type Internal_GetScriptableObjectEditorCurveValueType([NotNull] ScriptableObject scriptableObject, EditorCurveBinding binding);
extern public static bool GetFloatValue([NotNull] GameObject root, EditorCurveBinding binding, out float data);
+ extern public static bool GetDiscreteIntValue([NotNull] GameObject root, EditorCurveBinding binding, out int data);
public static bool GetObjectReferenceValue(GameObject root, EditorCurveBinding binding, out Object data)
{
- data = Internal_GetObjectReferenceValue(root, binding);
- return data != null;
+ data = Internal_GetObjectReferenceValue(root, binding, out bool result);
+ return result;
}
- extern private static Object Internal_GetObjectReferenceValue([NotNull] GameObject root, EditorCurveBinding binding);
+ extern private static Object Internal_GetObjectReferenceValue([NotNull] GameObject root, EditorCurveBinding binding, out bool result);
extern public static Object GetAnimatedObject([NotNull] GameObject root, EditorCurveBinding binding);
@@ -197,7 +215,7 @@ public static Type PropertyModificationToEditorCurveBinding(PropertyModification
extern public static ObjectReferenceKeyframe[] GetObjectReferenceCurve([NotNull] AnimationClip clip, EditorCurveBinding binding);
- public static void SetObjectReferenceCurve(AnimationClip clip, EditorCurveBinding binding, ObjectReferenceKeyframe[] keyframes)
+ public static void SetObjectReferenceCurve(AnimationClip clip, EditorCurveBinding binding, [Unmarshalled]ObjectReferenceKeyframe[] keyframes)
{
Internal_SetObjectReferenceCurve(clip, binding, keyframes, true);
Internal_InvokeOnCurveWasModified(clip, binding, keyframes != null ? CurveModifiedType.CurveModified : CurveModifiedType.CurveDeleted);
@@ -228,7 +246,7 @@ internal static void SetObjectReferenceCurveNoSync(AnimationClip clip, EditorCur
}
[NativeThrows]
- extern private static void Internal_SetObjectReferenceCurve([NotNull] AnimationClip clip, EditorCurveBinding binding, ObjectReferenceKeyframe[] keyframes, bool updateMuscleClip);
+ extern private static void Internal_SetObjectReferenceCurve([NotNull] AnimationClip clip, EditorCurveBinding binding, [Unmarshalled] ObjectReferenceKeyframe[] keyframes, bool updateMuscleClip);
extern public static AnimationCurve GetEditorCurve([NotNull] AnimationClip clip, EditorCurveBinding binding);
@@ -266,6 +284,8 @@ internal static void SetEditorCurveNoSync(AnimationClip clip, EditorCurveBinding
[NativeThrows]
extern private static void Internal_SetEditorCurve([NotNull] AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve, bool syncEditorCurves);
+ extern internal static DiscreteBindingResult IsDiscreteIntBinding(EditorCurveBinding binding);
+
extern internal static void SyncEditorCurves([NotNull] AnimationClip clip);
private static void Internal_InvokeOnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, CurveModifiedType type)
@@ -382,12 +402,29 @@ public static AnimationCurve GetEditorCurve(AnimationClip clip, string relativeP
return GetEditorCurve(clip, EditorCurveBinding.FloatCurve(relativePath, type, propertyName));
}
- extern public static AnimationEvent[] GetAnimationEvents([NotNull] AnimationClip clip);
- [NativeThrows] extern public static void SetAnimationEvents([NotNull] AnimationClip clip, [NotNull] AnimationEvent[] events);
+ public static AnimationEvent[] GetAnimationEvents(AnimationClip clip)
+ {
+ var blittableEvents = GetAnimationEventsInternal(clip);
+ var animationEvents = blittableEvents.Select(AnimationEventBlittable.ToAnimationEvent).ToArray();
+ foreach (var blittableEvent in blittableEvents)
+ blittableEvent.Dispose();
+ return animationEvents;
+ }
+ [return:Unmarshalled]
+ extern internal static AnimationEventBlittable[] GetAnimationEventsInternal([NotNull] AnimationClip clip);
+ public static void SetAnimationEvents(AnimationClip clip, AnimationEvent[] events)
+ {
+ var blittableEvents = events.Select(AnimationEventBlittable.FromAnimationEvent).ToArray();
+ SetAnimationEventsInternal(clip, blittableEvents);
+ foreach (var blittableEvent in blittableEvents)
+ blittableEvent.Dispose();
+ }
+ extern internal static void SetAnimationEventsInternal([NotNull] AnimationClip clip, [NotNull] AnimationEventBlittable[] events);
extern public static string CalculateTransformPath([NotNull] Transform targetTransform, Transform root);
extern public static AnimationClipSettings GetAnimationClipSettings([NotNull] AnimationClip clip);
+ extern internal static void RebuildMecanimData([NotNull] AnimationClip clip);
extern public static void SetAnimationClipSettings([NotNull] AnimationClip clip, AnimationClipSettings srcClipInfo);
extern internal static void SetAnimationClipSettingsNoDirty([NotNull] AnimationClip clip, AnimationClipSettings srcClipInfo);
@@ -452,5 +489,8 @@ public static void StopAnimationMode()
[Obsolete("SetAnimationType is no longer supported.")]
public static void SetAnimationType(AnimationClip clip, ModelImporterAnimationType type) {}
+
+
+ extern public static GenericBinding[] EditorCurveBindingsToGenericBindings(EditorCurveBinding[] editorCurveBindings);
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchy.cs b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchy.cs
index 4adb9ff208..cd32c12f4d 100644
--- a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchy.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchy.cs
@@ -5,6 +5,9 @@
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
+using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+using TreeViewState = UnityEditor.IMGUI.Controls.TreeViewState;
namespace UnityEditorInternal
{
diff --git a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyBuilder.cs b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyBuilder.cs
new file mode 100644
index 0000000000..51618a0dbd
--- /dev/null
+++ b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyBuilder.cs
@@ -0,0 +1,318 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+using System;
+using System.Linq;
+using UnityEditor.IMGUI.Controls;
+using Object = UnityEngine.Object;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+using TreeViewUtility = UnityEditor.IMGUI.Controls.TreeViewUtility;
+
+namespace UnityEditorInternal
+{
+ struct AddCurvesPopupHierarchyBuilder
+ {
+ struct KeyComparer : IComparer
+ {
+ static readonly Type s_GameObjectType = typeof(GameObject);
+ static readonly Type s_TransformType = typeof(Transform);
+
+ public int Compare(Key x, Key y)
+ {
+ var result = String.Compare(x.path, y.path, StringComparison.Ordinal);
+ if (result == 0 && x.type != y.type)
+ {
+ // Make sure GameObject properties appear first, then Transform.
+ if (x.type == s_GameObjectType)
+ return -1;
+ if (y.type == s_GameObjectType)
+ return 1;
+ if (x.type == typeof(Transform))
+ return -1;
+ if (y.type == typeof(Transform))
+ return 1;
+
+ return String.Compare(x.type.Name, y.type.Name, StringComparison.Ordinal);
+ }
+
+ return result;
+ }
+ }
+
+ struct Key
+ {
+ public string path;
+ public Type type;
+ }
+
+ SortedDictionary> m_AccumulatedBindings;
+ AnimationWindowState m_State;
+
+ public AddCurvesPopupHierarchyBuilder(AnimationWindowState state)
+ {
+ m_AccumulatedBindings = new SortedDictionary>(new KeyComparer());
+ m_State = state;
+ }
+
+ public void Add(EditorCurveBinding binding)
+ {
+ var key = new Key { path = binding.path, type = binding.type };
+
+ if (m_AccumulatedBindings.TryGetValue(key, out var bindings))
+ bindings.Add(binding);
+ else
+ m_AccumulatedBindings[key] = new List(new [] {binding});
+ }
+
+ void RemoveUnnecessaryBindings(List bindings)
+ {
+ for (int i = bindings.Count - 1; i >= 0; --i)
+ {
+ // Let's not add those that already have a existing curve.
+ if (AnimationWindowUtility.IsCurveCreated(m_State.activeAnimationClip, bindings[i]))
+ bindings.RemoveAt(i);
+ // Remove animator enabled property which shouldn't be animated.
+ else if (bindings[i].type == typeof(Animator) && bindings[i].propertyName == "m_Enabled")
+ bindings.RemoveAt(i);
+ // For RectTransform.position we only want .z
+ else if (AnimationWindowUtility.IsRectTransformPosition(bindings[i]) && !bindings[i].propertyName.EndsWith(".z"))
+ bindings.RemoveAt(i);
+ // Don't show for the root go
+ else if (bindings[i].type == typeof(GameObject) && string.IsNullOrEmpty(bindings[i].path))
+ bindings.RemoveAt(i);
+ }
+ }
+
+ public TreeViewItem CreateTreeView()
+ {
+ TreeViewItem rootNode;
+
+ // Bindings of a single Component/ScriptableObject, skip the group node.
+ if (m_AccumulatedBindings.Count == 1)
+ {
+ var bindings = m_AccumulatedBindings.First().Value;
+ RemoveUnnecessaryBindings(bindings);
+
+ if (bindings.Count > 0)
+ {
+ rootNode = AddAnimatableObjectToHierarchy(bindings, null, "");
+ }
+ else
+ {
+ rootNode = new AddCurvesPopupObjectNode(null, string.Empty, string.Empty);
+ }
+ }
+ else
+ {
+ var groupNodes = new Dictionary();
+ var childNodes = new Dictionary>();
+ var inheritedNodeWeights = new Dictionary();
+
+ rootNode = new AddCurvesPopupObjectNode(null, string.Empty, string.Empty);
+
+ TreeViewItem groupNode = rootNode;
+
+ groupNodes.Add(string.Empty, (rootNode));
+ childNodes.Add(groupNode, new List());
+ inheritedNodeWeights.Add(groupNode, 0);
+
+ string currentPath = string.Empty;
+ foreach (var kvp in m_AccumulatedBindings)
+ {
+ if (!currentPath.Equals(kvp.Key.path))
+ {
+ TreeViewItem parentNode = rootNode;
+ var parentPath = GetParentPath(kvp.Key.path);
+
+ while (parentPath != null)
+ {
+ if (groupNodes.TryGetValue(parentPath, out var node))
+ {
+ parentNode = node;
+ break;
+ }
+
+ parentPath = GetParentPath(parentPath);
+ }
+
+ groupNode = new AddCurvesPopupObjectNode(parentNode, kvp.Key.path, "", GetObjectName(kvp.Key.path));
+ groupNodes.Add(kvp.Key.path, groupNode);
+ childNodes.Add(groupNode, new List());
+ inheritedNodeWeights.Add(groupNode, 0);
+
+ childNodes[parentNode].Add(groupNode);
+
+ currentPath = kvp.Key.path;
+ }
+
+ var bindings = kvp.Value;
+ RemoveUnnecessaryBindings(bindings);
+
+ if (bindings.Count > 0)
+ {
+ // Builtin GameObject attributes.
+ if (kvp.Key.type == typeof(GameObject))
+ {
+ TreeViewItem newNode = CreateNode(bindings.ToArray(), groupNode, null);
+ if (newNode != null)
+ childNodes[groupNode].Add(newNode);
+ }
+ else
+ {
+ childNodes[groupNode].Add(AddAnimatableObjectToHierarchy(bindings, groupNode, kvp.Key.path));
+
+ var parentGroupNode = groupNode;
+ while (parentGroupNode != null)
+ {
+ inheritedNodeWeights[parentGroupNode] += bindings.Count;
+ parentGroupNode = parentGroupNode.parent;
+ }
+ }
+ }
+ }
+
+ // Remove empty leaves from tree view.
+ foreach (var kvp in inheritedNodeWeights)
+ {
+ // Remove Leaves nodes without properties.
+ if (inheritedNodeWeights[kvp.Key] == 0 && kvp.Key.parent != null)
+ {
+ childNodes[kvp.Key.parent].Remove(kvp.Key);
+ kvp.Key.parent = null;
+ }
+ }
+
+ // Set child parent references.
+ foreach (var kvp in childNodes)
+ {
+ TreeViewUtility.SetChildParentReferences(kvp.Value, kvp.Key);
+ }
+ }
+
+ m_AccumulatedBindings.Clear();
+
+ return rootNode;
+ }
+
+ private string GetParentPath(string path)
+ {
+ if (String.IsNullOrEmpty(path))
+ return null;
+
+ int index = path.LastIndexOf('/');
+ if (index == -1)
+ return string.Empty;
+
+ return path.Substring(0, index);
+ }
+
+ private string GetObjectName(string path)
+ {
+ if (String.IsNullOrEmpty(path))
+ return null;
+
+ int index = path.LastIndexOf('/');
+ if (index == -1)
+ return path;
+
+ return path.Substring(index + 1);
+ }
+
+ private string GetClassName(EditorCurveBinding binding)
+ {
+ if (m_State.activeRootGameObject != null)
+ {
+ Object target = AnimationUtility.GetAnimatedObject(m_State.activeRootGameObject, binding);
+ if (target != null)
+ return ObjectNames.GetInspectorTitle(target);
+ }
+
+ return binding.type.Name;
+ }
+
+ private Texture2D GetIcon(EditorCurveBinding binding)
+ {
+ return AssetPreview.GetMiniTypeThumbnail(binding.type);
+ }
+
+ private TreeViewItem AddAnimatableObjectToHierarchy(List curveBindings, TreeViewItem parentNode, string path)
+ {
+ TreeViewItem node = new AddCurvesPopupObjectNode(parentNode, path, GetClassName(curveBindings[0]));
+ node.icon = GetIcon(curveBindings[0]);
+
+ List childNodes = new List();
+ List singlePropertyBindings = new List();
+ SerializedObject so = null;
+
+ for (int i = 0; i < curveBindings.Count; i++)
+ {
+ EditorCurveBinding curveBinding = curveBindings[i];
+ if (m_State.activeRootGameObject && curveBinding.isSerializeReferenceCurve)
+ {
+ var animatedObject = AnimationUtility.GetAnimatedObject(m_State.activeRootGameObject, curveBinding);
+ if (animatedObject != null && (so == null || so.targetObject != animatedObject))
+ so = new SerializedObject(animatedObject);
+ }
+
+ singlePropertyBindings.Add(curveBinding);
+
+ // We expect curveBindings to come sorted by propertyname
+ if (i == curveBindings.Count - 1 || AnimationWindowUtility.GetPropertyGroupName(curveBindings[i + 1].propertyName) != AnimationWindowUtility.GetPropertyGroupName(curveBinding.propertyName))
+ {
+ TreeViewItem newNode = CreateNode(singlePropertyBindings.ToArray(), node, so);
+ if (newNode != null)
+ childNodes.Add(newNode);
+ singlePropertyBindings.Clear();
+ }
+ }
+
+ childNodes.Sort();
+
+ TreeViewUtility.SetChildParentReferences(childNodes, node);
+ return node;
+ }
+
+ private TreeViewItem CreateNode(EditorCurveBinding[] curveBindings, TreeViewItem parentNode, SerializedObject so)
+ {
+ var node = new AddCurvesPopupPropertyNode(parentNode, curveBindings, AnimationWindowUtility.GetNicePropertyGroupDisplayName(curveBindings[0], so));
+ node.icon = parentNode.icon;
+ return node;
+ }
+ }
+
+ class AddCurvesPopupObjectNode : TreeViewItem
+ {
+ public AddCurvesPopupObjectNode(TreeViewItem parent, string path, string className, string displayName = null)
+ : base((path + className).GetHashCode(), parent != null ? parent.depth + 1 : -1, parent, displayName ?? className)
+ {
+ }
+ }
+
+ class AddCurvesPopupPropertyNode : TreeViewItem
+ {
+ public EditorCurveBinding[] curveBindings;
+
+ public AddCurvesPopupPropertyNode(TreeViewItem parent, EditorCurveBinding[] curveBindings, string displayName)
+ : base(curveBindings[0].GetHashCode(), parent.depth + 1, parent, displayName)
+ {
+ this.curveBindings = curveBindings;
+ }
+
+ public override int CompareTo(TreeViewItem other)
+ {
+ AddCurvesPopupPropertyNode otherNode = other as AddCurvesPopupPropertyNode;
+ if (otherNode != null)
+ {
+ if (displayName.Contains("Rotation") && otherNode.displayName.Contains("Position"))
+ return 1;
+ if (displayName.Contains("Position") && otherNode.displayName.Contains("Rotation"))
+ return -1;
+ }
+ return base.CompareTo(other);
+ }
+ }
+}
diff --git a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs
index 738cf9fe1f..cb9654a3ff 100644
--- a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyDataSource.cs
@@ -2,20 +2,15 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
-using System.Collections.Generic;
using UnityEditor;
-using UnityEngine;
-using System;
-using System.Linq;
using UnityEditor.IMGUI.Controls;
-using Object = UnityEngine.Object;
+using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController;
+using TreeViewDataSource = UnityEditor.IMGUI.Controls.TreeViewDataSource;
namespace UnityEditorInternal
{
- internal class AddCurvesPopupHierarchyDataSource : TreeViewDataSource
+ class AddCurvesPopupHierarchyDataSource : TreeViewDataSource
{
- public static bool showEntireHierarchy { get; set; }
-
public AddCurvesPopupHierarchyDataSource(TreeViewController treeView)
: base(treeView)
{
@@ -34,196 +29,29 @@ public override void FetchData()
m_RootItem = null;
if (AddCurvesPopup.s_State.selection.canAddCurves)
{
- GameObject rootGameObject = AddCurvesPopup.s_State.activeRootGameObject;
- ScriptableObject scriptableObject = AddCurvesPopup.s_State.activeScriptableObject;
-
- if (rootGameObject != null)
- {
- AddGameObjectToHierarchy(rootGameObject, rootGameObject, AddCurvesPopup.s_State.activeAnimationClip, m_RootItem);
- }
- else if (scriptableObject != null)
- {
- AddScriptableObjectToHierarchy(scriptableObject, AddCurvesPopup.s_State.activeAnimationClip, m_RootItem);
- }
+ var state = AddCurvesPopup.s_State;
+ AddBindingsToHierarchy(state.controlInterface.GetAnimatableBindings());
}
SetupRootNodeSettings();
m_NeedRefreshRows = true;
}
- private TreeViewItem AddGameObjectToHierarchy(GameObject gameObject, GameObject rootGameObject, AnimationClip animationClip, TreeViewItem parent)
- {
- string path = AnimationUtility.CalculateTransformPath(gameObject.transform, rootGameObject.transform);
- AddCurvesPopupGameObjectNode node = new AddCurvesPopupGameObjectNode(gameObject, parent, gameObject.name);
- List childNodes = new List();
-
- if (m_RootItem == null)
- m_RootItem = node;
-
- // Iterate over all animatable objects
- EditorCurveBinding[] allCurveBindings = AnimationUtility.GetAnimatableBindings(gameObject, rootGameObject);
- List singleObjectBindings = new List();
- for (int i = 0; i < allCurveBindings.Length; i++)
- {
- EditorCurveBinding curveBinding = allCurveBindings[i];
-
- singleObjectBindings.Add(curveBinding);
-
- // Don't create group for GameObject.m_IsActive. It looks messy
- if (curveBinding.propertyName == "m_IsActive")
- {
- // Don't show for the root go
- if (curveBinding.path != "")
- {
- TreeViewItem newNode = CreateNode(singleObjectBindings.ToArray(), node);
- if (newNode != null)
- childNodes.Add(newNode);
- singleObjectBindings.Clear();
- }
- else
- {
- singleObjectBindings.Clear();
- }
- }
- else
- {
- // We expect allCurveBindings to come sorted by type
-
- bool isLastItemOverall = (i == allCurveBindings.Length - 1);
- bool isLastItemOnThisGroup = false;
-
- if (!isLastItemOverall)
- isLastItemOnThisGroup = (allCurveBindings[i + 1].type != curveBinding.type);
-
- // Let's not add those that already have a existing curve.
- if (AnimationWindowUtility.IsCurveCreated(animationClip, curveBinding))
- singleObjectBindings.Remove(curveBinding);
-
- // Remove animator enabled property which shouldn't be animated.
- if (curveBinding.type == typeof(Animator) && curveBinding.propertyName == "m_Enabled")
- singleObjectBindings.Remove(curveBinding);
-
- if ((isLastItemOverall || isLastItemOnThisGroup) && singleObjectBindings.Count > 0)
- {
- childNodes.Add(AddAnimatableObjectToHierarchy(singleObjectBindings.ToArray(), node, path));
- singleObjectBindings.Clear();
- }
- }
- }
-
- var animator = rootGameObject.GetComponent();
- if (animator != null)
- {
- //If the Animator has a human avatar, we need to check if the avatar's hierarchy matches that of the current GameObject. If they do not match, disable the node.
- if (animator.avatarRoot != null && animator.isHuman)
- {
- if (animator.avatarRoot.Find(path) == null)
- {
- node.propertyPathMismatchWithHumanAvatar = true;
- }
- }
- }
-
-
- if (showEntireHierarchy)
- {
- // Iterate over all child GOs
- for (int i = 0; i < gameObject.transform.childCount; i++)
- {
- Transform childTransform = gameObject.transform.GetChild(i);
- TreeViewItem childNode = AddGameObjectToHierarchy(childTransform.gameObject, rootGameObject, animationClip, node);
- if (childNode != null)
- childNodes.Add(childNode);
- }
- }
-
- TreeViewUtility.SetChildParentReferences(childNodes, node);
- return node;
- }
-
- private TreeViewItem AddScriptableObjectToHierarchy(ScriptableObject scriptableObject, AnimationClip clip, TreeViewItem parent)
- {
- EditorCurveBinding[] allCurveBindings = AnimationUtility.GetAnimatableBindings(scriptableObject);
- EditorCurveBinding[] availableBindings = allCurveBindings.Where(c => !AnimationWindowUtility.IsCurveCreated(clip, c)).ToArray();
-
- TreeViewItem node = null;
- if (availableBindings.Length > 0)
- node = AddAnimatableObjectToHierarchy(availableBindings, parent, "");
- else
- node = new AddCurvesPopupObjectNode(parent, "", scriptableObject.name);
-
- if (m_RootItem == null)
- m_RootItem = node;
-
- return node;
- }
-
- static string GetClassName(EditorCurveBinding binding)
- {
- if (AddCurvesPopup.s_State.activeRootGameObject != null)
- {
- Object target = AnimationUtility.GetAnimatedObject(AddCurvesPopup.s_State.activeRootGameObject, binding);
- if (target)
- return ObjectNames.GetInspectorTitle(target);
- }
-
- return binding.type.Name;
- }
-
- static Texture2D GetIcon(EditorCurveBinding binding)
+ private void AddBindingsToHierarchy(EditorCurveBinding[] bindings)
{
- if (AddCurvesPopup.s_State.activeRootGameObject != null)
+ if (bindings == null || bindings.Length == 0)
{
- return AssetPreview.GetMiniThumbnail(AnimationUtility.GetAnimatedObject(AddCurvesPopup.s_State.activeRootGameObject, binding));
- }
- else if (AddCurvesPopup.s_State.activeScriptableObject != null)
- {
- return AssetPreview.GetMiniThumbnail(AddCurvesPopup.s_State.activeScriptableObject);
+ m_RootItem = new AddCurvesPopupObjectNode(null, "", "");
+ return;
}
- return null;
- }
-
- private TreeViewItem AddAnimatableObjectToHierarchy(EditorCurveBinding[] curveBindings, TreeViewItem parentNode, string path)
- {
- TreeViewItem node = new AddCurvesPopupObjectNode(parentNode, path, GetClassName(curveBindings[0]));
- node.icon = GetIcon(curveBindings[0]);
-
- List childNodes = new List();
- List singlePropertyBindings = new List();
-
- for (int i = 0; i < curveBindings.Length; i++)
+ var builder = new AddCurvesPopupHierarchyBuilder(AddCurvesPopup.s_State);
+ for (int i = 0; i < bindings.Length; i++)
{
- EditorCurveBinding curveBinding = curveBindings[i];
-
- singlePropertyBindings.Add(curveBinding);
-
- // We expect curveBindings to come sorted by propertyname
- if (i == curveBindings.Length - 1 || AnimationWindowUtility.GetPropertyGroupName(curveBindings[i + 1].propertyName) != AnimationWindowUtility.GetPropertyGroupName(curveBinding.propertyName))
- {
- TreeViewItem newNode = CreateNode(singlePropertyBindings.ToArray(), node);
- if (newNode != null)
- childNodes.Add(newNode);
- singlePropertyBindings.Clear();
- }
+ builder.Add(bindings[i]);
}
- childNodes.Sort();
-
- TreeViewUtility.SetChildParentReferences(childNodes, node);
- return node;
- }
-
- private TreeViewItem CreateNode(EditorCurveBinding[] curveBindings, TreeViewItem parentNode)
- {
- var node = new AddCurvesPopupPropertyNode(parentNode, curveBindings);
-
- // For RectTransform.position we only want .z
- if (AnimationWindowUtility.IsRectTransformPosition(node.curveBindings[0]))
- node.curveBindings = new EditorCurveBinding[] {node.curveBindings[2]};
-
- node.icon = parentNode.icon;
- return node;
+ m_RootItem = builder.CreateTreeView();
}
public void UpdateData()
@@ -231,45 +59,4 @@ public void UpdateData()
m_TreeView.ReloadData();
}
}
-
- internal class AddCurvesPopupGameObjectNode : TreeViewItem
- {
- internal bool propertyPathMismatchWithHumanAvatar = false;
- public AddCurvesPopupGameObjectNode(GameObject gameObject, TreeViewItem parent, string displayName)
- : base(gameObject.GetInstanceID(), parent != null ? parent.depth + 1 : -1, parent, displayName)
- {
- }
- }
-
- internal class AddCurvesPopupObjectNode : TreeViewItem
- {
- public AddCurvesPopupObjectNode(TreeViewItem parent, string path, string className)
- : base((path + className).GetHashCode(), parent != null ? parent.depth + 1 : -1, parent, className)
- {
- }
- }
-
- internal class AddCurvesPopupPropertyNode : TreeViewItem
- {
- public EditorCurveBinding[] curveBindings;
-
- public AddCurvesPopupPropertyNode(TreeViewItem parent, EditorCurveBinding[] curveBindings)
- : base(curveBindings[0].GetHashCode(), parent.depth + 1, parent, AnimationWindowUtility.NicifyPropertyGroupName(curveBindings[0].type, AnimationWindowUtility.GetPropertyGroupName(curveBindings[0].propertyName)))
- {
- this.curveBindings = curveBindings;
- }
-
- public override int CompareTo(TreeViewItem other)
- {
- AddCurvesPopupPropertyNode otherNode = other as AddCurvesPopupPropertyNode;
- if (otherNode != null)
- {
- if (displayName.Contains("Rotation") && otherNode.displayName.Contains("Position"))
- return 1;
- if (displayName.Contains("Position") && otherNode.displayName.Contains("Rotation"))
- return -1;
- }
- return base.CompareTo(other);
- }
- }
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs
index 33897a16b6..bd964f16b6 100644
--- a/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AddCurvesPopupHierarchyGUI.cs
@@ -7,6 +7,9 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEditor.ShortcutManagement;
+using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+using TreeViewGUI = UnityEditor.IMGUI.Controls.TreeViewGUI;
namespace UnityEditorInternal
{
@@ -20,38 +23,17 @@ internal class AddCurvesPopupHierarchyGUI : TreeViewGUI
private GUIContent addPropertiesContent = EditorGUIUtility.TrTextContent("Add Properties");
private const float plusButtonWidth = 17;
- static Texture2D warningIcon = (Texture2D)EditorGUIUtility.LoadRequired("Icons/ShortcutManager/alertDialog.png");
- public static GUIStyle warningIconStyle;
-
public AddCurvesPopupHierarchyGUI(TreeViewController treeView, EditorWindow owner)
: base(treeView, true)
{
this.owner = owner;
- warningIconStyle = new GUIStyle();
- warningIconStyle.margin = new RectOffset(15, 15, 15, 15);
}
public override void OnRowGUI(Rect rowRect, TreeViewItem node, int row, bool selected, bool focused)
{
- bool propertyPathMismatchWithHumanAvatar = false;
- AddCurvesPopupGameObjectNode addCurvesPopupNode = node as AddCurvesPopupGameObjectNode;
- if (addCurvesPopupNode != null)
- {
- propertyPathMismatchWithHumanAvatar = addCurvesPopupNode.propertyPathMismatchWithHumanAvatar;
- }
-
- using (new EditorGUI.DisabledScope(propertyPathMismatchWithHumanAvatar))
- {
- base.OnRowGUI(rowRect, node, row, selected, focused);
- DoAddCurveButton(rowRect, node);
- HandleContextMenu(rowRect, node);
- }
-
- if (propertyPathMismatchWithHumanAvatar)
- {
- Rect iconRect = new Rect(rowRect.width - plusButtonWidth, rowRect.yMin, plusButtonWidth, buttonStyle.fixedHeight);
- GUI.Label(iconRect, new GUIContent(warningIcon, "The Avatar definition does not match the property path. Please author using a hierarchy the Avatar was built with."), warningIconStyle);
- }
+ base.OnRowGUI(rowRect, node, row, selected, focused);
+ DoAddCurveButton(rowRect, node);
+ HandleContextMenu(rowRect, node);
}
private void DoAddCurveButton(Rect rowRect, TreeViewItem node)
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs b/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs
index d716dabb7f..7aa757d3d1 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs
@@ -4,12 +4,9 @@
using System;
using UnityEngine;
-using UnityEditor;
-using System.Collections;
using System.Collections.Generic;
using UnityEditor.ShortcutManagement;
using UnityEditorInternal;
-using Object = UnityEngine.Object;
namespace UnityEditor
{
@@ -22,7 +19,8 @@ internal enum WrapModeFixed
PingPong = (int)WrapMode.PingPong
}
- internal class AnimEditor : ScriptableObject
+ [Serializable]
+ class AnimEditor : ScriptableObject
{
// Active Animation windows
private static List s_AnimationWindows = new List();
@@ -30,12 +28,12 @@ internal class AnimEditor : ScriptableObject
public bool stateDisabled { get { return m_State.disabled; } }
[SerializeField] private SplitterState m_HorizontalSplitter;
- [SerializeField] private AnimationWindowState m_State;
- [SerializeField] private DopeSheetEditor m_DopeSheet;
+ [SerializeReference] private AnimationWindowState m_State;
+ [SerializeReference] private DopeSheetEditor m_DopeSheet;
+ [SerializeReference] private CurveEditor m_CurveEditor;
[SerializeField] private AnimationWindowHierarchy m_Hierarchy;
[SerializeField] private AnimationWindowClipPopup m_ClipPopup;
[SerializeField] private AnimationEventTimeLine m_Events;
- [SerializeField] private CurveEditor m_CurveEditor;
[SerializeField] private AnimEditorOverlay m_Overlay;
[SerializeField] private EditorWindow m_OwnerWindow;
@@ -141,7 +139,7 @@ public AnimationWindowSelectionItem selection
}
}
- public IAnimationWindowControl controlInterface
+ public IAnimationWindowController controlInterface
{
get
{
@@ -149,7 +147,7 @@ public IAnimationWindowControl controlInterface
}
}
- public IAnimationWindowControl overrideControlInterface
+ public IAnimationWindowController overrideControlInterface
{
get
{
@@ -189,8 +187,8 @@ public void OnAnimEditorGUI(EditorWindow parent, Rect position)
m_State.OnGUI();
- if (m_State.disabled && controlInterface.recording)
- m_State.StopRecording();
+ if (m_State.disabled && m_State.recording)
+ m_State.recording = false;
SynchronizeLayout();
@@ -362,14 +360,13 @@ public void Update()
public void OnEnable()
{
- hideFlags = HideFlags.HideAndDontSave;
s_AnimationWindows.Add(this);
if (m_State == null)
{
- m_State = CreateInstance(typeof(AnimationWindowState)) as AnimationWindowState;
- m_State.hideFlags = HideFlags.HideAndDontSave;
+ m_State = new AnimationWindowState();
m_State.animEditor = this;
+
InitializeHorizontalSplitter();
InitializeClipSelection();
InitializeDopeSheet();
@@ -385,6 +382,8 @@ public void OnEnable()
m_ClipPopup.state = m_State;
m_Overlay.state = m_State;
+ m_State.OnEnable();
+
m_CurveEditor.curvesUpdated += SaveChangedCurvesFromCurveEditor;
m_CurveEditor.OnEnable();
}
@@ -399,18 +398,14 @@ public void OnDisable()
m_CurveEditor.OnDisable();
}
- if (m_DopeSheet != null)
- m_DopeSheet.OnDisable();
-
+ m_DopeSheet?.OnDisable();
m_State.OnDisable();
}
public void OnDestroy()
{
- if (m_CurveEditor != null)
- m_CurveEditor.OnDestroy();
-
- DestroyImmediate(m_State);
+ m_CurveEditor?.OnDestroy();
+ m_State?.OnDestroy();
}
public void OnSelectionChanged()
@@ -433,7 +428,7 @@ public void OnStartLiveEdit()
public void OnEndLiveEdit()
{
UpdateSelectedKeysToCurveEditor();
- controlInterface.ResampleAnimation();
+ m_State.ResampleAnimation();
}
public void OnLostFocus()
@@ -448,10 +443,10 @@ public void OnLostFocus()
private void PlaybackUpdate()
{
- if (m_State.disabled && controlInterface.playing)
- controlInterface.StopPlayback();
+ if (m_State.disabled && m_State.playing)
+ m_State.playing = false;
- if (controlInterface.PlaybackUpdate())
+ if (m_State.PlaybackUpdate())
Repaint();
}
@@ -777,7 +772,7 @@ private void AddEventButtonOnGUI()
private void AddKeyframeButtonOnGUI()
{
- bool canAddKey = selection.animationIsEditable && m_State.allCurves.Count != 0;
+ bool canAddKey = selection.animationIsEditable && m_State.filteredCurves.Count != 0;
using (new EditorGUI.DisabledScope(!canAddKey))
{
if (GUILayout.Button(AnimationWindowStyles.addKeyframeContent, AnimationWindowStyles.animClipToolbarButton))
@@ -795,19 +790,19 @@ private void AddKeyframeButtonOnGUI()
private void PlayControlsOnGUI()
{
- using (new EditorGUI.DisabledScope(!controlInterface.canPreview))
+ using (new EditorGUI.DisabledScope(!m_State.canPreview))
{
PreviewButtonOnGUI();
}
- using (new EditorGUI.DisabledScope(!controlInterface.canRecord))
+ using (new EditorGUI.DisabledScope(!m_State.canRecord))
{
RecordButtonOnGUI();
}
if (GUILayout.Button(AnimationWindowStyles.firstKeyContent, EditorStyles.toolbarButton))
{
- controlInterface.GoToFirstKeyframe();
+ state.GoToFirstKeyframe();
// Stop text editing. User may be editing frame navigation ui which will not update until we exit text editing.
EditorGUI.EndEditingActiveTextField();
@@ -815,20 +810,20 @@ private void PlayControlsOnGUI()
if (GUILayout.Button(AnimationWindowStyles.prevKeyContent, EditorStyles.toolbarButton))
{
- controlInterface.GoToPreviousKeyframe();
+ state.GoToPreviousKeyframe();
// Stop text editing. User may be editing frame navigation ui which will not update until we exit text editing.
EditorGUI.EndEditingActiveTextField();
}
- using (new EditorGUI.DisabledScope(!controlInterface.canPlay))
+ using (new EditorGUI.DisabledScope(!m_State.canPlay))
{
PlayButtonOnGUI();
}
if (GUILayout.Button(AnimationWindowStyles.nextKeyContent, EditorStyles.toolbarButton))
{
- controlInterface.GoToNextKeyframe();
+ state.GoToNextKeyframe();
// Stop text editing. User may be editing frame navigation ui which will not update until we exit text editing.
EditorGUI.EndEditingActiveTextField();
@@ -836,7 +831,7 @@ private void PlayControlsOnGUI()
if (GUILayout.Button(AnimationWindowStyles.lastKeyContent, EditorStyles.toolbarButton))
{
- controlInterface.GoToLastKeyframe();
+ state.GoToLastKeyframe();
// Stop text editing. User may be editing frame navigation ui which will not update until we exit text editing.
EditorGUI.EndEditingActiveTextField();
@@ -848,7 +843,7 @@ private void PlayControlsOnGUI()
int newFrame = EditorGUILayout.DelayedIntField(m_State.currentFrame, EditorStyles.toolbarTextField, GUILayout.Width(kIntFieldWidth));
if (EditorGUI.EndChangeCheck())
{
- controlInterface.GoToFrame(newFrame);
+ state.currentFrame = newFrame;
}
}
@@ -860,6 +855,7 @@ private void LinkOptionsOnGUI()
{
m_State.linkedWithSequencer = false;
m_State.selection = null;
+ m_State.overrideControlInterface = null;
// Layout has changed, bail out now.
EditorGUIUtility.ExitGUI();
@@ -883,9 +879,9 @@ static void ExecuteShortcut(ShortcutArguments args, Action exp)
animEditor.Repaint();
}
- static void ExecuteShortcut(ShortcutArguments args, Action exp)
+ static void ExecuteShortcut(ShortcutArguments args, Action exp)
{
- ExecuteShortcut(args, animEditor => exp(animEditor.controlInterface));
+ ExecuteShortcut(args, animEditor => exp(animEditor.state));
}
[FormerlyPrefKeyAs("Animation/Show Curves", "c")]
@@ -899,12 +895,9 @@ static void ShowCurves(ShortcutArguments args)
[Shortcut("Animation/Play Animation", typeof(AnimationWindow), KeyCode.Space)]
static void TogglePlayAnimation(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface =>
+ ExecuteShortcut(args, state =>
{
- if (controlInterface.playing)
- controlInterface.StopPlayback();
- else
- controlInterface.StartPlayback();
+ state.playing = !state.playing;
});
}
@@ -912,42 +905,42 @@ static void TogglePlayAnimation(ShortcutArguments args)
[Shortcut("Animation/Next Frame", typeof(AnimationWindow), KeyCode.Period)]
static void NextFrame(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface => controlInterface.GoToNextFrame());
+ ExecuteShortcut(args, state => state.GoToNextFrame());
}
[FormerlyPrefKeyAs("Animation/Previous Frame", ",")]
[Shortcut("Animation/Previous Frame", typeof(AnimationWindow), KeyCode.Comma)]
static void PreviousFrame(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface => controlInterface.GoToPreviousFrame());
+ ExecuteShortcut(args, state => state.GoToPreviousFrame());
}
[FormerlyPrefKeyAs("Animation/Previous Keyframe", "&,")]
[Shortcut("Animation/Previous Keyframe", typeof(AnimationWindow), KeyCode.Comma, ShortcutModifiers.Alt)]
static void PreviousKeyFrame(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface => controlInterface.GoToPreviousKeyframe());
+ ExecuteShortcut(args, state => state.GoToPreviousKeyframe());
}
[FormerlyPrefKeyAs("Animation/Next Keyframe", "&.")]
[Shortcut("Animation/Next Keyframe", typeof(AnimationWindow), KeyCode.Period, ShortcutModifiers.Alt)]
static void NextKeyFrame(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface => controlInterface.GoToNextKeyframe());
+ ExecuteShortcut(args, state => state.GoToNextKeyframe());
}
[FormerlyPrefKeyAs("Animation/First Keyframe", "#,")]
[Shortcut("Animation/First Keyframe", typeof(AnimationWindow), KeyCode.Comma, ShortcutModifiers.Shift)]
static void FirstKeyFrame(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface => controlInterface.GoToFirstKeyframe());
+ ExecuteShortcut(args, state => state.GoToFirstKeyframe());
}
[FormerlyPrefKeyAs("Animation/Last Keyframe", "#.")]
[Shortcut("Animation/Last Keyframe", typeof(AnimationWindow), KeyCode.Period, ShortcutModifiers.Shift)]
static void LastKeyFrame(ShortcutArguments args)
{
- ExecuteShortcut(args, controlInterface => controlInterface.GoToLastKeyframe());
+ ExecuteShortcut(args, state => state.GoToLastKeyframe());
}
[FormerlyPrefKeyAs("Animation/Key Selected", "k")]
@@ -961,8 +954,8 @@ static void KeySelected(ShortcutArguments args)
var animEditor = animationWindow.animEditor;
animEditor.SaveCurveEditorKeySelection();
- AnimationWindowUtility.AddSelectedKeyframes(animEditor.m_State, animEditor.controlInterface.time);
- animEditor.controlInterface.ClearCandidates();
+ AnimationWindowUtility.AddSelectedKeyframes(animEditor.m_State, AnimationKeyTime.Frame(animEditor.state.currentFrame, animEditor.state.frameRate));
+ animEditor.state.ClearCandidates();
animEditor.UpdateSelectedKeysToCurveEditor();
animEditor.Repaint();
@@ -979,7 +972,7 @@ static void KeyModified(ShortcutArguments args)
var animEditor = animationWindow.animEditor;
animEditor.SaveCurveEditorKeySelection();
- animEditor.controlInterface.ProcessCandidates();
+ animEditor.state.ProcessCandidates();
animEditor.UpdateSelectedKeysToCurveEditor();
animEditor.Repaint();
@@ -1006,13 +999,10 @@ static void FrameAll(ShortcutArguments args)
private void PlayButtonOnGUI()
{
EditorGUI.BeginChangeCheck();
- bool playbackEnabled = GUILayout.Toggle(controlInterface.playing, AnimationWindowStyles.playContent, EditorStyles.toolbarButton);
+ bool playbackEnabled = GUILayout.Toggle(m_State.playing, AnimationWindowStyles.playContent, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck())
{
- if (playbackEnabled)
- controlInterface.StartPlayback();
- else
- controlInterface.StopPlayback();
+ m_State.playing = playbackEnabled;
// Stop text editing. User may be editing frame navigation ui which will not update until we exit text editing.
EditorGUI.EndEditingActiveTextField();
@@ -1023,13 +1013,10 @@ private void PreviewButtonOnGUI()
{
EditorGUI.BeginChangeCheck();
- bool recordingEnabled = GUILayout.Toggle(controlInterface.previewing, AnimationWindowStyles.previewContent, EditorStyles.toolbarButton);
+ bool recordingEnabled = GUILayout.Toggle(m_State.previewing, AnimationWindowStyles.previewContent, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck())
{
- if (recordingEnabled)
- m_State.StartPreview();
- else
- m_State.StopPreview();
+ m_State.previewing = recordingEnabled;
}
}
@@ -1038,22 +1025,20 @@ private void RecordButtonOnGUI()
EditorGUI.BeginChangeCheck();
Color backupColor = GUI.color;
- if (controlInterface.recording)
+ if (m_State.recording)
{
Color recordedColor = AnimationMode.recordedPropertyColor;
recordedColor.a *= GUI.color.a;
GUI.color = recordedColor;
}
- bool recordingEnabled = GUILayout.Toggle(controlInterface.recording, AnimationWindowStyles.recordContent, EditorStyles.toolbarButton);
+ bool recordingEnabled = GUILayout.Toggle(m_State.recording, AnimationWindowStyles.recordContent, EditorStyles.toolbarButton);
if (EditorGUI.EndChangeCheck())
{
- if (recordingEnabled)
- m_State.StartRecording();
- else
- {
- m_State.StopRecording();
+ m_State.recording = recordingEnabled;
+ if (!recordingEnabled)
+ {
// Force refresh in inspector as stopping recording does not invalidate any data.
InspectorWindow.RepaintAllInspectors();
}
@@ -1122,9 +1107,9 @@ private void RenderInRangeOverlay(Rect rect)
{
Color color = inRangeColor;
- if (controlInterface.recording)
+ if (m_State.recording)
color *= AnimationMode.recordedPropertyColor;
- else if (controlInterface.previewing)
+ else if (m_State.previewing)
color *= AnimationMode.animatedPropertyColor;
else
color = Color.clear;
@@ -1137,9 +1122,9 @@ private void RenderOutOfRangeOverlay(Rect rect)
{
Color color = outOfRangeColor;
- if (controlInterface.recording)
+ if (m_State.recording)
color *= AnimationMode.recordedPropertyColor;
- else if (controlInterface.previewing)
+ else if (m_State.previewing)
color *= AnimationMode.animatedPropertyColor;
Vector2 timeRange = m_State.timeRange;
@@ -1148,7 +1133,7 @@ private void RenderOutOfRangeOverlay(Rect rect)
private void SynchronizeLayout()
{
- m_HorizontalSplitter.realSizes[1] = (int)Mathf.Min(m_Position.width - m_HorizontalSplitter.realSizes[0], m_HorizontalSplitter.realSizes[1]);
+ m_HorizontalSplitter.realSizes[1] = (int)Mathf.Max(Mathf.Min(m_Position.width - m_HorizontalSplitter.realSizes[0], m_HorizontalSplitter.realSizes[1]), 0);
// Synchronize frame rate
if (selection.animationClip != null)
@@ -1224,7 +1209,7 @@ private void UpdateSelectedKeysFromCurveEditor()
m_State.ClearKeySelections();
foreach (CurveSelection curveSelection in m_CurveEditor.selectedCurves)
{
- AnimationWindowKeyframe keyFrame = AnimationWindowUtility.CurveSelectionToAnimationWindowKeyframe(curveSelection, m_State.allCurves);
+ AnimationWindowKeyframe keyFrame = AnimationWindowUtility.CurveSelectionToAnimationWindowKeyframe(curveSelection, m_State.filteredCurves);
if (keyFrame != null)
m_State.SelectKey(keyFrame);
}
@@ -1272,9 +1257,6 @@ public void EndKeyModification()
void HandleMainAreaCopyPaste(int controlID)
{
- if (GUIUtility.keyboardControl != controlID)
- return;
-
var evt = Event.current;
var type = evt.GetTypeForControl(controlID);
if (type != EventType.ValidateCommand && type != EventType.ExecuteCommand)
@@ -1282,6 +1264,11 @@ void HandleMainAreaCopyPaste(int controlID)
if (evt.commandName == EventCommandNames.Copy)
{
+ // If events timeline has selected events right now then bail out; copying of
+ // these will get processed later by AnimationEventTimeLine.
+ if (m_Events.HasSelectedEvents)
+ return;
+
if (type == EventType.ExecuteCommand)
{
if (m_State.showCurveEditor)
@@ -1294,9 +1281,17 @@ void HandleMainAreaCopyPaste(int controlID)
{
if (type == EventType.ExecuteCommand)
{
- SaveCurveEditorKeySelection();
- m_State.PasteKeys();
- UpdateSelectedKeysToCurveEditor();
+ // If clipboard contains events right now then paste those.
+ if (AnimationWindowEventsClipboard.CanPaste())
+ {
+ m_Events.PasteEvents(m_State.activeRootGameObject, m_State.activeAnimationClip, m_State.currentTime);
+ }
+ else
+ {
+ SaveCurveEditorKeySelection();
+ m_State.PasteKeys();
+ UpdateSelectedKeysToCurveEditor();
+ }
// data is scheduled for an update, bail out now to avoid using out of date data.
EditorGUIUtility.ExitGUI();
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimEditorOverlay.cs b/Editor/Mono/Animation/AnimationWindow/AnimEditorOverlay.cs
index f72678148c..007da0703b 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimEditorOverlay.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimEditorOverlay.cs
@@ -15,7 +15,7 @@ namespace UnityEditorInternal
[System.Serializable]
internal class AnimEditorOverlay
{
- public AnimationWindowState state;
+ [SerializeReference] public AnimationWindowState state;
private TimeCursorManipulator m_PlayHeadCursor;
@@ -71,21 +71,20 @@ public void HandleEvents()
private bool OnStartDragPlayHead(Event evt)
{
- state.controlInterface.StopPlayback();
- state.controlInterface.StartScrubTime();
- state.controlInterface.ScrubTime(MousePositionToTime(evt));
+ state.playing = false;
+
+ state.controlInterface.time = MousePositionToTime(evt);
return true;
}
private bool OnDragPlayHead(Event evt)
{
- state.controlInterface.ScrubTime(MousePositionToTime(evt));
+ state.controlInterface.time = MousePositionToTime(evt);
return true;
}
private bool OnEndDragPlayHead(Event evt)
{
- state.controlInterface.EndScrubTime();
return true;
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationClipSelectionItem.cs b/Editor/Mono/Animation/AnimationWindow/AnimationClipSelectionItem.cs
index c6942190d7..757cfbdd4a 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationClipSelectionItem.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationClipSelectionItem.cs
@@ -10,16 +10,18 @@
namespace UnityEditorInternal
{
+ [Serializable]
internal class AnimationClipSelectionItem : AnimationWindowSelectionItem
{
- public static AnimationClipSelectionItem Create(AnimationClip animationClip, Object sourceObject)
+ public static AnimationClipSelectionItem Create(AnimationClip animationClip, Object sourceObject = null)
{
- AnimationClipSelectionItem selectionItem = CreateInstance(typeof(AnimationClipSelectionItem)) as AnimationClipSelectionItem;
-
- selectionItem.gameObject = sourceObject as GameObject;
- selectionItem.scriptableObject = sourceObject as ScriptableObject;
- selectionItem.animationClip = animationClip;
- selectionItem.id = 0; // no need for id since there's only one item in selection.
+ var selectionItem = new AnimationClipSelectionItem
+ {
+ gameObject = sourceObject as GameObject,
+ scriptableObject = sourceObject as ScriptableObject,
+ animationClip = animationClip,
+ id = 0
+ };
return selectionItem;
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationContextualPropertyMenu.cs b/Editor/Mono/Animation/AnimationWindow/AnimationContextualPropertyMenu.cs
index 91c81a171e..357e1113ce 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationContextualPropertyMenu.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationContextualPropertyMenu.cs
@@ -2,16 +2,13 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
-using System;
using System.Collections.Generic;
-using System.Reflection;
using UnityEngine;
using UnityEditor;
-using Object = UnityEngine.Object;
namespace UnityEditorInternal
{
- internal class AnimationPropertyContextualMenu
+ class AnimationPropertyContextualMenu
{
public static AnimationPropertyContextualMenu Instance = new AnimationPropertyContextualMenu();
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationKeyTime.cs b/Editor/Mono/Animation/AnimationWindow/AnimationKeyTime.cs
index 35d04bed28..30a34ea21c 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationKeyTime.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationKeyTime.cs
@@ -2,9 +2,7 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
-using System;
using UnityEngine;
-using UnityEditor;
namespace UnityEditorInternal
{
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationRecording.cs b/Editor/Mono/Animation/AnimationWindow/AnimationRecording.cs
index 697f03d428..eff217eca1 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationRecording.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationRecording.cs
@@ -475,10 +475,14 @@ static bool ValueFromPropertyModification(PropertyModification modification, Edi
}
else
{
- float temp;
- if (float.TryParse(modification.value, NumberStyles.Float, CultureInfo.InvariantCulture, out temp))
+ if(binding.isDiscreteCurve && int.TryParse(modification.value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int tempInt))
{
- outObject = temp;
+ outObject = tempInt;
+ return true;
+ }
+ else if (float.TryParse(modification.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float tempFloat))
+ {
+ outObject = tempFloat;
return true;
}
else
@@ -505,7 +509,9 @@ static void AddKey(IAnimationRecordingState state, EditorCurveBinding binding, T
if (curve.length == 0)
{
if (state.currentFrame != 0)
+ {
AnimationWindowUtility.AddKeyframeToCurve(curve, previousValue, type, AnimationKeyTime.Frame(0, clip.frameRate));
+ }
}
}
@@ -632,7 +638,7 @@ static private void ProcessAnimatorModifications(IAnimationRecordingState state,
if (isHumanBone)
{
- Debug.LogWarning("Keyframing translation on humanoid rig is not supported!", target as Transform);
+ Debug.LogWarning("Keyframing translation on humanoid rig is not supported!", target);
discardListPos.Add(item.Key);
}
else if (isRootMotion)
@@ -691,7 +697,7 @@ static private void ProcessAnimatorModifications(IAnimationRecordingState state,
if (isHumanBone)
{
- Debug.LogWarning("Keyframing rotation on humanoid rig is not supported!", target as Transform);
+ Debug.LogWarning("Keyframing rotation on humanoid rig is not supported!", target);
discardListRot.Add(item.Key);
}
else if (isRootMotion)
@@ -739,7 +745,7 @@ static private void ProcessAnimatorModifications(IAnimationRecordingState state,
bool isHumanBone = isHuman && !isRootTransform && animator.IsBoneTransform(target);
if (isHumanBone)
{
- Debug.LogWarning("Keyframing scale on humanoid rig is not supported!", target as Transform);
+ Debug.LogWarning("Keyframing scale on humanoid rig is not supported!", target);
discardListScale.Add(item.Key);
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs
index fbddcca9f8..bd82bca45e 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindow.cs
@@ -4,20 +4,22 @@
using System;
using UnityEngine;
-using UnityEditor;
-using System.Collections;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
using UnityEditorInternal;
using Object = UnityEngine.Object;
namespace UnityEditor
{
[EditorWindowTitle(title = "Animation", useTypeNameAsIconName = true)]
- internal class AnimationWindow : EditorWindow, IHasCustomMenu
+ public sealed class AnimationWindow : EditorWindow, IHasCustomMenu
{
// Active Animation windows
private static List s_AnimationWindows = new List();
- public static List GetAllAnimationWindows() { return s_AnimationWindows; }
+ internal static List GetAllAnimationWindows() { return s_AnimationWindows; }
+
+ private static Type[] s_CustomControllerTypes = null;
private AnimEditor m_AnimEditor;
@@ -30,27 +32,164 @@ internal class AnimationWindow : EditorWindow, IHasCustomMenu
private GUIContent m_DefaultTitleContent;
private GUIContent m_RecordTitleContent;
- internal AnimEditor animEditor
+ internal AnimEditor animEditor => m_AnimEditor;
+
+ internal AnimationWindowState state
{
get
{
- return m_AnimEditor;
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state;
+ }
+ return null;
}
}
- internal AnimationWindowState state
+ public AnimationClip animationClip
{
get
{
if (m_AnimEditor != null)
{
- return m_AnimEditor.state;
+ return m_AnimEditor.state.activeAnimationClip;
}
return null;
}
+ set
+ {
+ if (m_AnimEditor != null)
+ {
+ m_AnimEditor.state.activeAnimationClip = value;
+ }
+ }
+ }
+
+ public bool previewing
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.previewing;
+ }
+ return false;
+ }
+ set
+ {
+ if (m_AnimEditor != null)
+ {
+ m_AnimEditor.state.previewing = value;
+ }
+ }
}
- public void ForceRefresh()
+ public bool canPreview
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.canPreview;
+ }
+
+ return false;
+ }
+ }
+
+ public bool recording
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.recording;
+ }
+ return false;
+ }
+ set
+ {
+ if (m_AnimEditor != null)
+ {
+ m_AnimEditor.state.recording = value;
+ }
+ }
+ }
+
+ public bool canRecord
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.canRecord;
+ }
+
+ return false;
+ }
+ }
+
+ public bool playing
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.playing;
+ }
+ return false;
+ }
+ set
+ {
+ if (m_AnimEditor != null)
+ {
+ m_AnimEditor.state.playing = value;
+ }
+ }
+ }
+
+ public float time
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.currentTime;
+ }
+ return 0.0f;
+ }
+ set
+ {
+ if (m_AnimEditor != null)
+ {
+ m_AnimEditor.state.currentTime = value;
+ }
+ }
+ }
+
+ public int frame
+ {
+ get
+ {
+ if (m_AnimEditor != null)
+ {
+ return m_AnimEditor.state.currentFrame;
+ }
+ return 0;
+ }
+ set
+ {
+ if (m_AnimEditor != null)
+ {
+ m_AnimEditor.state.currentFrame = value;
+ }
+ }
+ }
+
+ private AnimationWindow()
+ {}
+
+ internal void ForceRefresh()
{
if (m_AnimEditor != null)
{
@@ -58,11 +197,11 @@ public void ForceRefresh()
}
}
- public void OnEnable()
+ void OnEnable()
{
if (m_AnimEditor == null)
{
- m_AnimEditor = CreateInstance(typeof(AnimEditor)) as AnimEditor;
+ m_AnimEditor = CreateInstance();
m_AnimEditor.hideFlags = HideFlags.HideAndDontSave;
}
@@ -74,23 +213,23 @@ public void OnEnable()
OnSelectionChange();
- Undo.undoRedoPerformed += UndoRedoPerformed;
+ Undo.undoRedoEvent += UndoRedoPerformed;
}
- public void OnDisable()
+ void OnDisable()
{
s_AnimationWindows.Remove(this);
m_AnimEditor.OnDisable();
- Undo.undoRedoPerformed -= UndoRedoPerformed;
+ Undo.undoRedoEvent -= UndoRedoPerformed;
}
- public void OnDestroy()
+ void OnDestroy()
{
DestroyImmediate(m_AnimEditor);
}
- public void Update()
+ void Update()
{
if (m_AnimEditor == null)
return;
@@ -98,7 +237,7 @@ public void Update()
m_AnimEditor.Update();
}
- public void OnGUI()
+ void OnGUI()
{
if (m_AnimEditor == null)
return;
@@ -107,7 +246,7 @@ public void OnGUI()
m_AnimEditor.OnAnimEditorGUI(this, position);
}
- public void OnSelectionChange()
+ internal void OnSelectionChange()
{
if (m_AnimEditor == null)
return;
@@ -122,22 +261,19 @@ public void OnSelectionChange()
m_LockTracker.isLocked = false;
}
- GameObject activeGameObject = activeObject as GameObject;
- if (activeGameObject != null)
+ if (activeObject is GameObject activeGameObject)
{
EditGameObject(activeGameObject);
}
else
{
- Transform activeTransform = activeObject as Transform;
- if (activeTransform != null)
+ if (activeObject is Transform activeTransform)
{
EditGameObject(activeTransform.gameObject);
}
else
{
- AnimationClip activeAnimationClip = activeObject as AnimationClip;
- if (activeAnimationClip != null)
+ if (activeObject is AnimationClip activeAnimationClip)
EditAnimationClip(activeAnimationClip);
}
}
@@ -148,18 +284,18 @@ public void OnSelectionChange()
}
}
- public void OnFocus()
+ void OnFocus()
{
OnSelectionChange();
}
- public void OnControllerChange()
+ internal void OnControllerChange()
{
// Refresh selectedItem to update selected clips.
OnSelectionChange();
}
- public void OnLostFocus()
+ void OnLostFocus()
{
if (m_AnimEditor != null)
m_AnimEditor.OnLostFocus();
@@ -177,28 +313,56 @@ static bool OnOpenAsset(int instanceID, int line)
return false;
}
- public bool EditGameObject(GameObject gameObject)
+ internal bool EditGameObject(GameObject gameObject)
{
- return EditGameObjectInternal(gameObject, (IAnimationWindowControl)null);
+ if (EditorUtility.IsPersistent(gameObject))
+ return false;
+
+ if ((gameObject.hideFlags & HideFlags.NotEditable) != 0)
+ return false;
+
+ var newSelection = GameObjectSelectionItem.Create(gameObject);
+ if (ShouldUpdateGameObjectSelection(newSelection))
+ {
+ m_AnimEditor.selection = newSelection;
+
+ IAnimationWindowController controller = null;
+
+ var rootGameObject = newSelection.rootGameObject;
+ if (rootGameObject != null)
+ controller = FindCustomController(rootGameObject);
+
+ m_AnimEditor.overrideControlInterface = controller;
+
+ m_LastSelectedObjectID = gameObject != null ? gameObject.GetInstanceID() : 0;
+ }
+ else
+ m_AnimEditor.OnSelectionUpdated();
+
+ return true;
}
- public bool EditAnimationClip(AnimationClip animationClip)
+ internal bool EditAnimationClip(AnimationClip animationClip)
{
if (state.linkedWithSequencer == true)
return false;
- EditAnimationClipInternal(animationClip, (Object)null, (IAnimationWindowControl)null);
+ EditAnimationClipInternal(animationClip, (Object)null, (IAnimationWindowController)null);
return true;
}
- public bool EditSequencerClip(AnimationClip animationClip, Object sourceObject, IAnimationWindowControl controlInterface)
+ internal bool EditSequencerClip(AnimationClip animationClip, Object sourceObject, IAnimationWindowControl controlInterface)
{
EditAnimationClipInternal(animationClip, sourceObject, controlInterface);
state.linkedWithSequencer = true;
+
+ if (controlInterface != null)
+ controlInterface.Init(state);
+
return true;
}
- public void UnlinkSequencer()
+ internal void UnlinkSequencer()
{
if (state.linkedWithSequencer)
{
@@ -210,29 +374,35 @@ public void UnlinkSequencer()
}
}
- private bool EditGameObjectInternal(GameObject gameObject, IAnimationWindowControl controlInterface)
+ private IAnimationWindowController FindCustomController(GameObject gameObject)
{
- if (EditorUtility.IsPersistent(gameObject))
- return false;
+ IAnimationWindowController controller = null;
- if ((gameObject.hideFlags & HideFlags.NotEditable) != 0)
- return false;
+ if (s_CustomControllerTypes == null)
+ {
+ s_CustomControllerTypes = TypeCache
+ .GetTypesWithAttribute()
+ .Where(type => typeof(IAnimationWindowController).IsAssignableFrom(type))
+ .ToArray();
+ }
- var newSelection = GameObjectSelectionItem.Create(gameObject);
- if (ShouldUpdateGameObjectSelection(newSelection))
+ foreach (var controllerType in s_CustomControllerTypes)
{
- m_AnimEditor.selection = newSelection;
- m_AnimEditor.overrideControlInterface = controlInterface;
+ var attribute = controllerType.GetCustomAttribute();
+ var component = gameObject.GetComponent(attribute.componentType);
- m_LastSelectedObjectID = gameObject != null ? gameObject.GetInstanceID() : 0;
+ if (component != null)
+ {
+ controller = (IAnimationWindowController)Activator.CreateInstance(controllerType);
+ controller.OnCreate(this, component);
+ break;
+ }
}
- else
- m_AnimEditor.OnSelectionUpdated();
- return true;
+ return controller;
}
- private void EditAnimationClipInternal(AnimationClip animationClip, Object sourceObject, IAnimationWindowControl controlInterface)
+ private void EditAnimationClipInternal(AnimationClip animationClip, Object sourceObject, IAnimationWindowController controlInterface)
{
var newSelection = AnimationClipSelectionItem.Create(animationClip, sourceObject);
if (ShouldUpdateSelection(newSelection))
@@ -246,7 +416,7 @@ private void EditAnimationClipInternal(AnimationClip animationClip, Object sourc
m_AnimEditor.OnSelectionUpdated();
}
- protected virtual void ShowButton(Rect r)
+ void ShowButton(Rect r)
{
if (m_LockButtonStyle == null)
m_LockButtonStyle = "IN LockButton";
@@ -302,12 +472,12 @@ private bool ShouldUpdateSelection(AnimationWindowSelectionItem selectedItem)
return (selectedItem.GetRefreshHash() != currentSelection.GetRefreshHash());
}
- private void UndoRedoPerformed()
+ private void UndoRedoPerformed(in UndoRedoInfo info)
{
Repaint();
}
- public virtual void AddItemsToMenu(GenericMenu menu)
+ public void AddItemsToMenu(GenericMenu menu)
{
m_LockTracker.AddItemsToMenu(menu, m_AnimEditor.stateDisabled);
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipPopup.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipPopup.cs
index 9c9167b0c1..b0b6991af4 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipPopup.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipPopup.cs
@@ -12,7 +12,7 @@ namespace UnityEditor
[System.Serializable]
class AnimationWindowClipPopup
{
- [SerializeField] public AnimationWindowState state;
+ [SerializeReference] public AnimationWindowState state;
static int s_ClipPopupHash = "s_ClipPopupHash".GetHashCode();
@@ -214,7 +214,8 @@ private AnimationClip[] GetOrderedClipList()
if (state.activeRootGameObject != null)
clips = AnimationUtility.GetAnimationClips(state.activeRootGameObject);
- Array.Sort(clips, (AnimationClip clip1, AnimationClip clip2) => CurveUtility.GetClipName(clip1).CompareTo(CurveUtility.GetClipName(clip2)));
+ //Using AlphaNum/Natural Compare to sort clips
+ Array.Sort(clips, (AnimationClip clip1, AnimationClip clip2) => EditorUtility.NaturalCompareObjectNames(clip1, clip2));
return clips;
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipboard.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipboard.cs
index 471302ee0a..22939495c9 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipboard.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowClipboard.cs
@@ -77,6 +77,12 @@ internal static void CopyEvents(IList allEvents, bool[] selected
copyEvents.Add(new AnimationWindowEventClipboard(allEvents[explicitIndex]));
}
var data = new AnimationWindowEventsClipboard {events = copyEvents.ToArray()};
+
+ // Animation keyframes right now do not go through regular clipboard machinery,
+ // so when copying Events, make sure Keyframes are cleared from the clipboard, or things
+ // get confusing.
+ AnimationWindowState.ClearKeyframeClipboard();
+
Clipboard.SetCustomValue(data);
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowControl.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowControl.cs
index 49cf330b3f..4223a5ea38 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowControl.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowControl.cs
@@ -7,19 +7,17 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
-using System.Collections;
using Object = UnityEngine.Object;
using UnityEngine.Playables;
using UnityEngine.Animations;
-using UnityEngine.Experimental.Animations;
-
using Unity.Profiling;
namespace UnityEditorInternal
{
- internal class AnimationWindowControl : IAnimationWindowControl, IAnimationContextualResponder
+ [Serializable]
+ class AnimationWindowControl : IAnimationWindowController, IAnimationContextualResponder
{
class CandidateRecordingState : IAnimationRecordingState
{
@@ -134,95 +132,65 @@ private static bool HasFlag(ResampleFlags flags, ResampleFlags flag)
private static ProfilerMarker s_ResampleAnimationMarker = new ProfilerMarker("AnimationWindowControl.ResampleAnimation");
- public override void OnEnable()
+ public void OnEnable()
{
- base.OnEnable();
-
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
public void OnDisable()
{
- StopPreview();
- StopPlayback();
-
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
}
+ public void OnCreate(AnimationWindow animationWindow, Component component)
+ {
+ // nothing to do.
+ }
+
public void OnDestroy()
{
if (m_Driver != null)
- DestroyImmediate(m_Driver);
+ ScriptableObject.DestroyImmediate(m_Driver);
}
- public override void OnSelectionChanged()
+ public void OnSelectionChanged()
{
// Set back time at beginning and stop recording.
if (state != null)
m_Time = AnimationKeyTime.Time(0f, state.frameRate);
StopPreview();
- StopPlayback();
}
void OnPlayModeStateChanged(PlayModeStateChange state)
{
- if (state == PlayModeStateChange.ExitingPlayMode)
+ if (state == PlayModeStateChange.ExitingPlayMode ||
+ state == PlayModeStateChange.ExitingEditMode)
{
StopPreview();
- StopPlayback();
}
}
- public override AnimationKeyTime time
+ public float time
{
- get
- {
- return m_Time;
- }
+ get => m_Time.time;
+ set => SetCurrentTime(value);
}
- public override void GoToTime(float time)
+ public int frame
{
- SetCurrentTime(time);
+ get => m_Time.frame;
+ set => SetCurrentFrame(value);
}
- public override void GoToFrame(int frame)
- {
- SetCurrentFrame(frame);
- }
-
- public override void StartScrubTime()
- {
- // nothing to do...
- }
-
- public override void ScrubTime(float time)
+ public void GoToTime(float time)
{
SetCurrentTime(time);
}
- public override void EndScrubTime()
- {
- // nothing to do...
- }
-
- public override void GoToPreviousFrame()
+ public void GoToFrame(int frame)
{
- SetCurrentFrame(time.frame - 1);
- }
-
- public override void GoToNextFrame()
- {
- SetCurrentFrame(time.frame + 1);
- }
-
- public override void GoToPreviousKeyframe()
- {
- List curves = (state.showCurveEditor && state.activeCurves.Count > 0) ? state.activeCurves : state.allCurves;
-
- float newTime = AnimationWindowUtility.GetPreviousKeyframeTime(curves.ToArray(), time.time, state.clipFrameRate);
- SetCurrentTime(state.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToClipFrame));
+ SetCurrentFrame(frame);
}
public void GoToPreviousKeyframe(PropertyModification[] modifications)
@@ -232,27 +200,19 @@ public void GoToPreviousKeyframe(PropertyModification[] modifications)
return;
List curves = new List();
- for (int i = 0; i < state.allCurves.Count; ++i)
+ for (int i = 0; i < state.filteredCurves.Count; ++i)
{
- AnimationWindowCurve curve = state.allCurves[i];
+ AnimationWindowCurve curve = state.filteredCurves[i];
if (Array.Exists(bindings, binding => curve.binding.Equals(binding)))
curves.Add(curve);
}
- float newTime = AnimationWindowUtility.GetPreviousKeyframeTime(curves.ToArray(), time.time, state.clipFrameRate);
- SetCurrentTime(state.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToClipFrame));
+ float newTime = AnimationWindowUtility.GetPreviousKeyframeTime(curves.ToArray(), time, state.clipFrameRate);
+ SetCurrentTime(state.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToFrame));
state.Repaint();
}
- public override void GoToNextKeyframe()
- {
- List curves = (state.showCurveEditor && state.activeCurves.Count > 0) ? state.activeCurves : state.allCurves;
-
- float newTime = AnimationWindowUtility.GetNextKeyframeTime(curves.ToArray(), time.time, state.clipFrameRate);
- SetCurrentTime(state.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToClipFrame));
- }
-
public void GoToNextKeyframe(PropertyModification[] modifications)
{
EditorCurveBinding[] bindings = AnimationWindowUtility.PropertyModificationsToEditorCurveBindings(modifications, state.activeRootGameObject, state.activeAnimationClip);
@@ -260,40 +220,28 @@ public void GoToNextKeyframe(PropertyModification[] modifications)
return;
List curves = new List();
- for (int i = 0; i < state.allCurves.Count; ++i)
+ for (int i = 0; i < state.filteredCurves.Count; ++i)
{
- AnimationWindowCurve curve = state.allCurves[i];
+ AnimationWindowCurve curve = state.filteredCurves[i];
if (Array.Exists(bindings, binding => curve.binding.Equals(binding)))
curves.Add(curve);
}
- float newTime = AnimationWindowUtility.GetNextKeyframeTime(curves.ToArray(), time.time, state.clipFrameRate);
- SetCurrentTime(state.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToClipFrame));
+ float newTime = AnimationWindowUtility.GetNextKeyframeTime(curves.ToArray(), time, state.clipFrameRate);
+ SetCurrentTime(state.SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToFrame));
state.Repaint();
}
- public override void GoToFirstKeyframe()
- {
- if (state.activeAnimationClip)
- SetCurrentTime(state.activeAnimationClip.startTime);
- }
-
- public override void GoToLastKeyframe()
- {
- if (state.activeAnimationClip)
- SetCurrentTime(state.activeAnimationClip.stopTime);
- }
-
private void SnapTimeToFrame()
{
- float newTime = state.FrameToTime(time.frame);
+ float newTime = state.FrameToTime(frame);
SetCurrentTime(newTime);
}
private void SetCurrentTime(float value)
{
- if (!Mathf.Approximately(value, time.time))
+ if (!Mathf.Approximately(value, time))
{
m_Time = AnimationKeyTime.Time(value, state.frameRate);
StartPreview();
@@ -304,7 +252,7 @@ private void SetCurrentTime(float value)
private void SetCurrentFrame(int value)
{
- if (value != time.frame)
+ if (value != frame)
{
m_Time = AnimationKeyTime.Frame(value, state.frameRate);
StartPreview();
@@ -313,7 +261,7 @@ private void SetCurrentFrame(int value)
}
}
- public override bool canPlay
+ public bool canPlay
{
get
{
@@ -321,34 +269,35 @@ public override bool canPlay
}
}
- public override bool playing
+ public bool playing
{
get
{
return AnimationMode.InAnimationPlaybackMode() && previewing;
}
+ set
+ {
+ if (value)
+ StartPlayback();
+ else
+ StopPlayback();
+ }
}
- public override bool StartPlayback()
+ private void StartPlayback()
{
- if (!canPlay)
- return false;
-
- if (!playing)
- {
- AnimationMode.StartAnimationPlaybackMode();
+ if (!canPlay || playing)
+ return;
- m_PreviousUpdateTime = Time.realtimeSinceStartup;
+ AnimationMode.StartAnimationPlaybackMode();
- // Auto-Preview when start playing
- StartPreview();
- ClearCandidates();
- }
+ m_PreviousUpdateTime = Time.realtimeSinceStartup;
- return true;
+ // Auto-Preview when start playing
+ ClearCandidates();
}
- public override void StopPlayback()
+ private void StopPlayback()
{
if (AnimationMode.InAnimationPlaybackMode())
{
@@ -359,15 +308,12 @@ public override void StopPlayback()
}
}
- public override bool PlaybackUpdate()
+ public bool PlaybackUpdate()
{
- if (!playing)
- return false;
-
float deltaTime = Time.realtimeSinceStartup - m_PreviousUpdateTime;
m_PreviousUpdateTime = Time.realtimeSinceStartup;
- float newTime = time.time + deltaTime;
+ float newTime = time + deltaTime;
// looping
if (newTime > state.maxTime)
@@ -380,7 +326,7 @@ public override bool PlaybackUpdate()
return true;
}
- public override bool canPreview
+ public bool canPreview
{
get
{
@@ -393,7 +339,7 @@ public override bool canPreview
}
}
- public override bool previewing
+ public bool previewing
{
get
{
@@ -403,39 +349,56 @@ public override bool previewing
return AnimationMode.InAnimationMode(driver);
}
+ set
+ {
+ if (value)
+ StartPreview();
+ else
+ StopPreview();
+ }
}
- public override bool StartPreview()
+ private void StartPreview()
{
- if (previewing)
- return true;
-
- if (!canPreview)
- return false;
+ if (previewing || !canPreview)
+ return;
AnimationMode.StartAnimationMode(GetAnimationModeDriver());
AnimationPropertyContextualMenu.Instance.SetResponder(this);
Undo.postprocessModifications += PostprocessAnimationRecordingModifications;
+ PrefabUtility.allowRecordingPrefabPropertyOverridesFor += AllowRecordingPrefabPropertyOverridesFor;
DestroyGraph();
CreateCandidateClip();
+ //If a hierarchy was created and array reorder happen in the inspector prior
+ //to the preview being started we will need to ensure that the display name
+ //reflects the binding path on an array element.
+ state.UpdateCurvesDisplayName();
+
IAnimationWindowPreview[] previewComponents = FetchPostProcessComponents();
- m_UsesPostProcessComponents = previewComponents != null;
+ m_UsesPostProcessComponents = previewComponents != null && previewComponents.Length > 0;
if (previewComponents != null)
{
+ // Animation preview affects inspector values, so make sure we ignore constrain proportions
+ ConstrainProportionsTransformScale.m_IsAnimationPreview = true;
foreach (var component in previewComponents)
{
component.StartPreview();
}
}
- return true;
+ ResampleAnimation();
}
- public override void StopPreview()
+ private void StopPreview()
{
- StopPlayback();
- StopRecording();
+ if (!previewing)
+ return;
+
+ OnExitingAnimationMode();
+
+ ConstrainProportionsTransformScale.m_IsAnimationPreview = false;
+
ClearCandidates();
DestroyGraph();
DestroyCandidateClip();
@@ -470,11 +433,9 @@ public override void StopPreview()
m_UsesPostProcessComponents = false;
}
-
- Undo.postprocessModifications -= PostprocessAnimationRecordingModifications;
}
- public override bool canRecord
+ public bool canRecord
{
get
{
@@ -485,7 +446,7 @@ public override bool canRecord
}
}
- public override bool recording
+ public bool recording
{
get
{
@@ -493,37 +454,30 @@ public override bool recording
return AnimationMode.InAnimationRecording();
return false;
}
+ set
+ {
+ if (value)
+ StartRecording();
+ else
+ StopRecording();
+ }
}
- public override bool StartRecording(Object targetObject)
- {
- return StartRecording();
- }
-
- private bool StartRecording()
+ private void StartRecording()
{
- if (recording)
- return true;
-
- if (!canRecord)
- return false;
-
- if (StartPreview())
- {
- AnimationMode.StartAnimationRecording();
- ClearCandidates();
- return true;
- }
+ if (!canRecord || recording)
+ return;
- return false;
+ AnimationMode.StartAnimationRecording();
+ ClearCandidates();
}
- public override void StopRecording()
+ private void StopRecording()
{
- if (recording)
- {
- AnimationMode.StopAnimationRecording();
- }
+ if (!recording)
+ return;
+
+ AnimationMode.StopAnimationRecording();
}
private void StartCandidateRecording()
@@ -610,7 +564,7 @@ private void RebuildGraph(Animator animator)
m_GraphRoot = (Playable)motionX;
}
- var output = AnimationPlayableOutput.Create(m_Graph, "ouput", animator);
+ var output = AnimationPlayableOutput.Create(m_Graph, "output", animator);
output.SetSourcePlayable(m_GraphRoot);
output.SetWeight(0.0f);
}
@@ -625,7 +579,7 @@ private IAnimationWindowPreview[] FetchPostProcessComponents()
return null;
}
- public override void ResampleAnimation()
+ public void ResampleAnimation()
{
ResampleAnimation(ResampleFlags.Default);
}
@@ -635,9 +589,7 @@ private void ResampleAnimation(ResampleFlags flags)
if (state.disabled)
return;
- if (previewing == false)
- return;
- if (canPreview == false)
+ if (!canPreview || !previewing)
return;
s_ResampleAnimationMarker.Begin();
@@ -681,20 +633,23 @@ private void ResampleAnimation(ResampleFlags flags)
}
if (!m_CandidateClip.empty)
+ {
+ StartCandidateRecording();
AnimationMode.AddCandidates(state.activeRootGameObject, m_CandidateClip);
+ }
m_ClipPlayable.SetSampleRate(playing ? -1 : state.activeAnimationClip.frameRate);
- AnimationMode.SamplePlayableGraph(m_Graph, 0, time.time);
+ AnimationMode.SamplePlayableGraph(m_Graph, 0, time);
// This will cover euler/quaternion matching in basic playable graphs only (animation clip + candidate clip).
- AnimationUtility.SampleEulerHint(state.activeRootGameObject, state.activeAnimationClip, time.time, WrapMode.Clamp);
+ AnimationUtility.SampleEulerHint(state.activeRootGameObject, state.activeAnimationClip, time, WrapMode.Clamp);
if (!m_CandidateClip.empty)
- AnimationUtility.SampleEulerHint(state.activeRootGameObject, m_CandidateClip, time.time, WrapMode.Clamp);
+ AnimationUtility.SampleEulerHint(state.activeRootGameObject, m_CandidateClip, time, WrapMode.Clamp);
}
else
{
- AnimationMode.SampleAnimationClip(state.activeRootGameObject, state.activeAnimationClip, time.time);
+ AnimationMode.SampleAnimationClip(state.activeRootGameObject, state.activeAnimationClip, time);
if (!m_CandidateClip.empty)
AnimationMode.SampleCandidateClip(state.activeRootGameObject, m_CandidateClip, 0f);
}
@@ -719,7 +674,7 @@ private AnimationModeDriver GetAnimationModeDriver()
{
if (m_Driver == null)
{
- m_Driver = CreateInstance();
+ m_Driver = ScriptableObject.CreateInstance();
m_Driver.hideFlags = HideFlags.HideAndDontSave;
m_Driver.name = "AnimationWindowDriver";
m_Driver.isKeyCallback += (Object target, string propertyPath) =>
@@ -749,19 +704,50 @@ private AnimationModeDriver GetCandidateDriver()
{
if (m_CandidateDriver == null)
{
- m_CandidateDriver = CreateInstance();
+ m_CandidateDriver = ScriptableObject.CreateInstance();
m_CandidateDriver.name = "AnimationWindowCandidateDriver";
}
return m_CandidateDriver;
}
+ private bool AllowRecordingPrefabPropertyOverridesFor(UnityEngine.Object componentOrGameObject)
+ {
+ if (componentOrGameObject == null)
+ throw new ArgumentNullException(nameof(componentOrGameObject));
+
+ if (componentOrGameObject is not Component && componentOrGameObject is not GameObject)
+ return true;
+
+ var rootOfAnimation = state.activeRootGameObject;
+ if (rootOfAnimation == null)
+ return true;
+
+ return false;
+ }
+
+ void OnExitingAnimationMode()
+ {
+ Undo.postprocessModifications -= PostprocessAnimationRecordingModifications;
+ PrefabUtility.allowRecordingPrefabPropertyOverridesFor -= AllowRecordingPrefabPropertyOverridesFor;
+ }
+
+ void RecordPropertyOverridesForNonAnimatedProperties(UndoPropertyModification[] modifications)
+ {
+ PrefabUtility.allowRecordingPrefabPropertyOverridesFor -= AllowRecordingPrefabPropertyOverridesFor;
+ foreach (var mod in modifications)
+ {
+ PrefabUtility.RecordPrefabInstancePropertyModifications(mod.currentValue.target);
+ }
+ PrefabUtility.allowRecordingPrefabPropertyOverridesFor += AllowRecordingPrefabPropertyOverridesFor;
+ }
+
private UndoPropertyModification[] PostprocessAnimationRecordingModifications(UndoPropertyModification[] modifications)
{
- //Fix for case 751009: The animationMode can be changed outside the AnimationWindow, and this callback needs to be unregistered.
+ //Fix for case 751009: The animationMode can be changed outside the AnimationWindow, and callbacks needs to be unregistered.
if (!AnimationMode.InAnimationMode(GetAnimationModeDriver()))
{
- Undo.postprocessModifications -= PostprocessAnimationRecordingModifications;
+ OnExitingAnimationMode();
return modifications;
}
@@ -770,6 +756,11 @@ private UndoPropertyModification[] PostprocessAnimationRecordingModifications(Un
else if (previewing)
modifications = RegisterCandidates(modifications);
+ // Fix for UUM-61742: Unrecorded Prefab overloads should be recorded immediately
+ RecordPropertyOverridesForNonAnimatedProperties(modifications);
+
+ RefreshDisplayNamesOnArrayTopologicalChange(modifications);
+
// Only resample when playable graph has been customized with post process nodes.
if (m_UsesPostProcessComponents)
ResampleAnimation(ResampleFlags.None);
@@ -777,6 +768,28 @@ private UndoPropertyModification[] PostprocessAnimationRecordingModifications(Un
return modifications;
}
+ private void RefreshDisplayNamesOnArrayTopologicalChange(UndoPropertyModification[] modifications)
+ {
+ if (modifications.Length >= 2)
+ {
+ if (modifications[0].currentValue.propertyPath.EndsWith("]") &&
+ modifications[0].currentValue.propertyPath.Contains(".Array.data[") &&
+ modifications[1].currentValue.propertyPath.EndsWith("]") &&
+ modifications[1].currentValue.propertyPath.Contains(".Array.data["))
+ {
+ //Array reordering might affect curves display name
+ state.UpdateCurvesDisplayName();
+ }
+ else if (modifications[0].currentValue.propertyPath.EndsWith(".Array.size") &&
+ Convert.ToInt64(modifications[0].currentValue.value) <
+ Convert.ToInt64(modifications[0].previousValue.value))
+ {
+ //Array shrinking might affect curves display name
+ state.UpdateCurvesDisplayName();
+ }
+ }
+ }
+
private UndoPropertyModification[] ProcessAutoKey(UndoPropertyModification[] modifications)
{
BeginKeyModification();
@@ -844,7 +857,7 @@ private void DestroyCandidateClip()
m_CandidateClip = null;
}
- public override void ClearCandidates()
+ public void ClearCandidates()
{
StopCandidateRecording();
@@ -852,7 +865,7 @@ public override void ClearCandidates()
m_CandidateClip.ClearCurves();
}
- public override void ProcessCandidates()
+ public void ProcessCandidates()
{
BeginKeyModification();
@@ -861,15 +874,15 @@ public override void ProcessCandidates()
List curves = new List();
- for (int i = 0; i < state.allCurves.Count; ++i)
+ for (int i = 0; i < state.filteredCurves.Count; ++i)
{
- AnimationWindowCurve curve = state.allCurves[i];
+ AnimationWindowCurve curve = state.filteredCurves[i];
EditorCurveBinding remappedBinding = RotationCurveInterpolation.RemapAnimationBindingForRotationCurves(curve.binding, m_CandidateClip);
if (Array.Exists(bindings, binding => remappedBinding.Equals(binding)) || Array.Exists(objectCurveBindings, binding => remappedBinding.Equals(binding)))
curves.Add(curve);
}
- AnimationWindowUtility.AddKeyframes(state, curves, time);
+ AnimationWindowUtility.AddKeyframes(state, curves, m_Time);
EndKeyModification();
@@ -884,15 +897,15 @@ private List GetKeys(PropertyModification[] modificatio
if (bindings.Length == 0)
return keys;
- for (int i = 0; i < state.allCurves.Count; ++i)
+ for (int i = 0; i < state.filteredCurves.Count; ++i)
{
- AnimationWindowCurve curve = state.allCurves[i];
+ AnimationWindowCurve curve = state.filteredCurves[i];
if (Array.Exists(bindings, binding => curve.binding.Equals(binding)))
{
int keyIndex = curve.GetKeyframeIndex(state.time);
if (keyIndex >= 0)
{
- keys.Add(curve.m_Keyframes[keyIndex]);
+ keys.Add(curve.keyframes[keyIndex]);
}
}
}
@@ -985,7 +998,7 @@ public bool HasAnyCandidates()
public bool HasAnyCurves()
{
- return (state.allCurves.Count > 0);
+ return (state.filteredCurves.Count > 0);
}
public void AddKey(SerializedProperty property)
@@ -1080,7 +1093,7 @@ public void AddAnimatedKeys()
{
BeginKeyModification();
- AnimationWindowUtility.AddKeyframes(state, state.allCurves, time);
+ AnimationWindowUtility.AddKeyframes(state, state.filteredCurves, m_Time);
ClearCandidates();
EndKeyModification();
@@ -1100,5 +1113,74 @@ private void EndKeyModification()
if (animEditor != null)
animEditor.EndKeyModification();
}
+
+ public EditorCurveBinding[] GetAnimatableBindings()
+ {
+ var rootGameObject = state.activeRootGameObject;
+ var scriptableObject = state.activeScriptableObject;
+
+ if (rootGameObject != null)
+ {
+ return AnimationWindowUtility.GetAnimatableBindings(rootGameObject);
+ }
+ if (scriptableObject != null)
+ {
+ return AnimationUtility.GetAnimatableBindings(scriptableObject);
+ }
+
+ return Array.Empty();
+ }
+
+ public EditorCurveBinding[] GetAnimatableBindings(GameObject gameObject)
+ {
+ var rootGameObject = state.activeRootGameObject;
+ return AnimationUtility.GetAnimatableBindings(gameObject, rootGameObject);
+ }
+
+ public Type GetValueType(EditorCurveBinding binding)
+ {
+ var rootGameObject = state.activeRootGameObject;
+ var scriptableObject = state.activeScriptableObject;
+
+ if (rootGameObject != null)
+ {
+ return AnimationUtility.GetEditorCurveValueType(rootGameObject, binding);
+ }
+ else if (scriptableObject != null)
+ {
+ return AnimationUtility.GetEditorCurveValueType(scriptableObject, binding);
+ }
+ else
+ {
+ if (binding.isPPtrCurve)
+ {
+ // Cannot extract type of PPtrCurve.
+ return null;
+ }
+ else
+ {
+ // Cannot extract type of AnimationCurve. Default to float.
+ return typeof(float);
+ }
+ }
+ }
+
+ public float GetFloatValue(EditorCurveBinding binding)
+ {
+ AnimationUtility.GetFloatValue(state.activeRootGameObject, binding, out var value);
+ return value;
+ }
+
+ public int GetIntValue(EditorCurveBinding binding)
+ {
+ AnimationUtility.GetDiscreteIntValue(state.activeRootGameObject, binding, out var value);
+ return value;
+ }
+
+ public Object GetObjectReferenceValue(EditorCurveBinding binding)
+ {
+ AnimationUtility.GetObjectReferenceValue(state.activeRootGameObject, binding, out var value);
+ return value;
+ }
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowControllerAttribute.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowControllerAttribute.cs
new file mode 100644
index 0000000000..06a91feb10
--- /dev/null
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowControllerAttribute.cs
@@ -0,0 +1,24 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+
+using System;
+using UnityEngine;
+
+namespace UnityEditor
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ class AnimationWindowControllerAttribute : Attribute
+ {
+ public Type componentType { get; }
+
+ public AnimationWindowControllerAttribute(System.Type type)
+ {
+ if (type == null)
+ Debug.LogError("Failed to load AnimationWindowControl component type");
+ componentType = type;
+ }
+ }
+
+}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowCurve.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowCurve.cs
index 135dfd5cc2..c7d0cf939e 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowCurve.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowCurve.cs
@@ -15,7 +15,7 @@ internal class AnimationWindowCurve : IComparable, IEquata
{
public const float timeEpsilon = 0.00001f;
- public List m_Keyframes;
+ private List m_Keyframes;
private EditorCurveBinding m_Binding;
private int m_BindingHashCode;
@@ -28,6 +28,7 @@ internal class AnimationWindowCurve : IComparable, IEquata
public EditorCurveBinding binding { get { return m_Binding; } }
public bool isPPtrCurve { get { return m_Binding.isPPtrCurve; } }
public bool isDiscreteCurve { get { return m_Binding.isDiscreteCurve; } }
+ public bool isSerializeReferenceCurve{ get {return m_Binding.isSerializeReferenceCurve;}}
public bool isPhantom { get { return m_Binding.isPhantom; } }
public string propertyName { get { return m_Binding.propertyName; } }
public string path { get { return m_Binding.path; } }
@@ -45,6 +46,20 @@ internal class AnimationWindowCurve : IComparable, IEquata
public bool animationIsEditable { get { return m_SelectionBinding != null ? m_SelectionBinding.animationIsEditable : true; } }
public int selectionID { get { return m_SelectionBinding != null ? m_SelectionBinding.id : 0; } }
+ public IReadOnlyList keyframes => m_Keyframes;
+
+ private object defaultValue
+ {
+ get
+ {
+ if (isPPtrCurve)
+ return null;
+ if (isDiscreteCurve)
+ return 0;
+ return 0f;
+ }
+ }
+
public AnimationWindowSelectionItem selectionBinding { get { return m_SelectionBinding; } set { m_SelectionBinding = value; } }
public AnimationWindowCurve(AnimationClip clip, EditorCurveBinding binding, System.Type valueType)
@@ -112,12 +127,12 @@ public int CompareTo(AnimationWindowCurve obj)
// We want to sort position before rotation
if (sameTransformComponent)
{
- string propertyGroupA = AnimationWindowUtility.GetNicePropertyGroupDisplayName(typeof(Transform), AnimationWindowUtility.GetPropertyGroupName(propertyName));
- string propertyGroupB = AnimationWindowUtility.GetNicePropertyGroupDisplayName(typeof(Transform), AnimationWindowUtility.GetPropertyGroupName(obj.propertyName));
+ string propertyGroupA = AnimationWindowUtility.GetPropertyGroupName(propertyName);
+ string propertyGroupB = AnimationWindowUtility.GetPropertyGroupName(obj.propertyName);
- if (propertyGroupA.Contains("Position") && propertyGroupB.Contains("Rotation"))
+ if (propertyGroupA.Equals("m_LocalPosition") && (propertyGroupB.Equals("m_LocalRotation") || propertyGroupB.StartsWith("localEulerAngles")))
return -1;
- if (propertyGroupA.Contains("Rotation") && propertyGroupB.Contains("Position"))
+ if ((propertyGroupA.Equals("m_LocalRotation") || propertyGroupA.StartsWith("localEulerAngles")) && propertyGroupB.Equals("m_LocalPosition"))
return 1;
}
// Transform component should always come first.
@@ -177,17 +192,10 @@ public AnimationCurve ToAnimationCurve()
AnimationCurve animationCurve = new AnimationCurve();
List keys = new List();
- float lastFrameTime = float.MinValue;
-
for (int i = 0; i < length; i++)
{
- // Make sure we don't get two keyframes in an exactly the same time. We just ignore those.
- if (Mathf.Abs(m_Keyframes[i].time - lastFrameTime) > AnimationWindowCurve.timeEpsilon)
- {
- Keyframe newKeyframe = m_Keyframes[i].ToKeyframe();
- keys.Add(newKeyframe);
- lastFrameTime = m_Keyframes[i].time;
- }
+ Keyframe newKeyframe = m_Keyframes[i].ToKeyframe();
+ keys.Add(newKeyframe);
}
animationCurve.keys = keys.ToArray();
@@ -199,17 +207,10 @@ public ObjectReferenceKeyframe[] ToObjectCurve()
int length = m_Keyframes.Count;
List keys = new List();
- float lastFrameTime = float.MinValue;
-
for (int i = 0; i < length; i++)
{
- // Make sure we don't get two keyframes in an exactly the same time. We just ignore those.
- if (Mathf.Abs(m_Keyframes[i].time - lastFrameTime) > AnimationWindowCurve.timeEpsilon)
- {
- ObjectReferenceKeyframe newKeyframe = m_Keyframes[i].ToObjectReferenceKeyframe();
- lastFrameTime = newKeyframe.time;
- keys.Add(newKeyframe);
- }
+ ObjectReferenceKeyframe newKeyframe = m_Keyframes[i].ToObjectReferenceKeyframe();
+ keys.Add(newKeyframe);
}
keys.Sort((a, b) => a.time.CompareTo(b.time));
@@ -228,7 +229,7 @@ public AnimationWindowKeyframe FindKeyAtTime(AnimationKeyTime keyTime)
public object Evaluate(float time)
{
if (m_Keyframes.Count == 0)
- return isPPtrCurve ? null : (object)0f;
+ return defaultValue;
AnimationWindowKeyframe firstKey = m_Keyframes[0];
if (time <= firstKey.time)
@@ -243,9 +244,9 @@ public object Evaluate(float time)
{
AnimationWindowKeyframe nextKey = m_Keyframes[i];
- if (key.time < time && nextKey.time >= time)
+ if (key.time <= time && nextKey.time > time)
{
- if (isPPtrCurve)
+ if (isPPtrCurve || isDiscreteCurve)
{
return key.value;
}
@@ -266,7 +267,7 @@ public object Evaluate(float time)
}
// Shouldn't happen...
- return isPPtrCurve ? null : (object)0f;
+ return defaultValue;
}
public void AddKeyframe(AnimationWindowKeyframe key, AnimationKeyTime keyTime)
@@ -288,6 +289,11 @@ public void RemoveKeyframe(AnimationKeyTime time)
}
}
+ public void RemoveKeyframe(AnimationWindowKeyframe keyframe)
+ {
+ m_Keyframes.Remove(keyframe);
+ }
+
public bool HasKeyframe(AnimationKeyTime time)
{
return GetKeyframeIndex(time) != -1;
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowEvent.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowEvent.cs
index 613cfa17ff..4b3cce3606 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowEvent.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowEvent.cs
@@ -13,10 +13,46 @@
namespace UnityEditor
{
- internal struct AnimationWindowEventMethod
+ ///
+ /// Holds the context for AnimationEvent editing.
+ ///
+ class AnimationEventEditorState
{
- public string name;
- public Type parameterType;
+ static bool s_ShowOverloadedFunctionsDetails = true;
+ static bool s_ShowDuplicatedFunctionsDetails = true;
+
+ bool m_ShowOverloadedFunctionsDetails = s_ShowOverloadedFunctionsDetails;
+ bool m_ShowDuplicatedFunctionsDetails = s_ShowDuplicatedFunctionsDetails;
+
+ ///
+ /// Used to track whether or not to show extra details about duplicated function names found in among the potential supported functions
+ ///
+ public bool ShowOverloadedFunctionsDetails
+ {
+ get => m_ShowOverloadedFunctionsDetails;
+ set
+ {
+ m_ShowOverloadedFunctionsDetails = s_ShowOverloadedFunctionsDetails = value;
+ }
+ }
+
+ ///
+ /// Used to track whether or not to show extra details about overloaded function names found in among the potential supported functions
+ ///
+ public bool ShowDuplicatedFunctionsDetails
+ {
+ get => m_ShowDuplicatedFunctionsDetails;
+ set
+ {
+ m_ShowDuplicatedFunctionsDetails = s_ShowDuplicatedFunctionsDetails = value;
+ }
+ }
+
+ public AnimationEventEditorState()
+ {
+ m_ShowOverloadedFunctionsDetails = s_ShowOverloadedFunctionsDetails;
+ m_ShowDuplicatedFunctionsDetails = s_ShowDuplicatedFunctionsDetails;
+ }
}
internal class AnimationWindowEvent : ScriptableObject
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowEventInspector.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowEventInspector.cs
index 0884c194bb..584f590753 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowEventInspector.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowEventInspector.cs
@@ -5,7 +5,6 @@
using System.Linq;
using UnityEngine;
using UnityEditor;
-using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System;
@@ -17,15 +16,18 @@ namespace UnityEditor
[CanEditMultipleObjects]
internal class AnimationWindowEventInspector : Editor
{
+ public static GUIContent s_OverloadWarning = EditorGUIUtility.TrTextContent("Some functions were overloaded in MonoBehaviour components and may not work as intended if used with Animation Events!");
+ public static GUIContent s_DuplicatesWarning = EditorGUIUtility.TrTextContent("Some functions have the same name across several Monobehaviour components and may not work as intended if used with Animation Events!");
+
const string kNotSupportedPostFix = " (Function Not Supported)";
const string kNoneSelected = "(No Function Selected)";
- public static GUIContent s_OverloadWarning = EditorGUIUtility.TrTextContent("Some functions were overloaded in MonoBehaviour components and may not work as intended if used with Animation Events!");
+ AnimationEventEditorState m_State = new();
public override void OnInspectorGUI()
{
var awes = targets.Select(o => o as AnimationWindowEvent).ToArray();
- OnEditAnimationEvents(awes);
+ OnEditAnimationEvents(awes, m_State);
}
protected override void OnHeaderGUI()
@@ -34,12 +36,17 @@ protected override void OnHeaderGUI()
DrawHeaderGUI(this, targetTitle);
}
- public static void OnEditAnimationEvent(AnimationWindowEvent awe)
+ public static void OnEditAnimationEvent(AnimationWindowEvent awe, AnimationEventEditorState state)
{
- OnEditAnimationEvents(new AnimationWindowEvent[] {awe});
+ OnEditAnimationEvents(new AnimationWindowEvent[] {awe}, state);
}
- public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents)
+ // These are used so we don't alloc new lists on every call
+ static List supportedMethods;
+ static List overloads;
+ static List duplicates;
+
+ public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents, AnimationEventEditorState state)
{
AnimationWindowEventData data = GetData(awEvents);
if (data.events == null || data.selectedEvents == null || data.selectedEvents.Length == 0)
@@ -49,68 +56,64 @@ public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents)
bool singleFunctionName = Array.TrueForAll(data.selectedEvents, evt => evt.functionName == firstEvent.functionName);
- GUI.changed = false;
+ EditorGUI.BeginChangeCheck();
if (data.root != null)
{
- List methods = new List();
- HashSet overloads = new HashSet();
- CollectSupportedMethods(data.root, methods, overloads);
+ supportedMethods ??= new List();
+ overloads ??= new List();
+ duplicates ??= new List();
- var methodsFormatted = new List(methods.Count);
+ supportedMethods.Clear();
+ overloads.Clear();
+ duplicates.Clear();
+ CollectSupportedMethods(data.root, supportedMethods, overloads, duplicates);
- for (int i = 0; i < methods.Count; ++i)
- {
- AnimationWindowEventMethod method = methods[i];
+ int selected = supportedMethods.FindIndex(method => method.Name == firstEvent.functionName);
- string postFix = " ( )";
- if (method.parameterType != null)
- {
- if (method.parameterType == typeof(float))
- postFix = " ( float )";
- else if (method.parameterType == typeof(int))
- postFix = " ( int )";
- else
- postFix = string.Format(" ( {0} )", method.parameterType.Name);
- }
+ // A non-empty array used for rendering the contents of the popup
+ // It is of size 1 greater than the list of supported methods to account for the "None" option
+ string[] methodsFormatted = new string[supportedMethods.Count + 1];
- methodsFormatted.Add(method.name + postFix);
+ for (int i = 0; i < supportedMethods.Count; ++i)
+ {
+ AnimationMethodMap methodMap = supportedMethods[i];
+ string menuPath = methodMap.methodMenuPath;
+ methodsFormatted[i] = menuPath;
}
- int notSupportedIndex = methods.Count;
- int selected = methods.FindIndex(method => method.name == firstEvent.functionName);
+ // Add a final option to set the function to no selected function
+ int notSupportedIndex = supportedMethods.Count;
if (selected == -1)
{
- selected = methods.Count;
-
- AnimationWindowEventMethod newMethod = new AnimationWindowEventMethod();
- newMethod.name = firstEvent.functionName;
- newMethod.parameterType = null;
-
- methods.Add(newMethod);
+ selected = notSupportedIndex;
+ // Display that the current function is not supported if applicable
if (string.IsNullOrEmpty(firstEvent.functionName))
- methodsFormatted.Add(kNoneSelected);
+ methodsFormatted[notSupportedIndex] = kNoneSelected;
else
- methodsFormatted.Add(firstEvent.functionName + kNotSupportedPostFix);
+ methodsFormatted[notSupportedIndex] = firstEvent.functionName + kNotSupportedPostFix;
+
+ var emptyMethodMap = new AnimationMethodMap();
+ supportedMethods.Add(emptyMethodMap);
}
EditorGUIUtility.labelWidth = 130;
EditorGUI.showMixedValue = !singleFunctionName;
int wasSelected = singleFunctionName ? selected : -1;
- selected = EditorGUILayout.Popup("Function: ", selected, methodsFormatted.ToArray());
+ selected = EditorGUILayout.Popup("Function: ", selected, methodsFormatted);
if (wasSelected != selected && selected != -1 && selected != notSupportedIndex)
{
foreach (var evt in data.selectedEvents)
{
- evt.functionName = methods[selected].name;
+ evt.functionName = supportedMethods[selected].Name;
evt.stringParameter = string.Empty;
}
}
EditorGUI.showMixedValue = false;
- var selectedParameter = methods[selected].parameterType;
+ var selectedParameter = supportedMethods[selected].parameterType;
if (singleFunctionName && selectedParameter != null)
{
@@ -127,6 +130,24 @@ public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents)
{
EditorGUILayout.Space();
EditorGUILayout.HelpBox(s_OverloadWarning.text, MessageType.Warning, true);
+ state.ShowOverloadedFunctionsDetails = EditorGUILayout.Foldout(state.ShowOverloadedFunctionsDetails, "Show Details");
+ if (state.ShowOverloadedFunctionsDetails)
+ {
+ string overloadedFunctionDetails = "Overloaded Functions: \n" + GetFormattedMethodsText(overloads);
+ GUILayout.Label(overloadedFunctionDetails, EditorStyles.helpBox);
+ }
+ }
+
+ if (duplicates.Count > 0)
+ {
+ EditorGUILayout.Space();
+ EditorGUILayout.HelpBox(s_DuplicatesWarning.text, MessageType.Warning, true);
+ state.ShowDuplicatedFunctionsDetails = EditorGUILayout.Foldout(state.ShowDuplicatedFunctionsDetails, "Show Details");
+ if (state.ShowDuplicatedFunctionsDetails)
+ {
+ string duplicatedFunctionDetails = "Duplicated Functions: \n" + GetFormattedMethodsText(duplicates);
+ GUILayout.Label(duplicatedFunctionDetails, EditorStyles.helpBox);
+ }
}
}
else
@@ -139,7 +160,6 @@ public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents)
foreach (var evt in data.selectedEvents)
{
evt.functionName = functionName;
- evt.stringParameter = string.Empty;
}
}
EditorGUI.showMixedValue = false;
@@ -153,15 +173,53 @@ public static void OnEditAnimationEvents(AnimationWindowEvent[] awEvents)
using (new EditorGUI.DisabledScope(true))
{
AnimationEvent dummyEvent = new AnimationEvent();
- DoEditRegularParameters(new AnimationEvent[] {dummyEvent}, typeof(AnimationEvent));
+ DoEditRegularParameters(new AnimationEvent[] { dummyEvent }, typeof(AnimationEvent));
}
}
}
- if (GUI.changed)
+ if (EditorGUI.EndChangeCheck())
SetData(awEvents, data);
}
+ static string GetFormattedMethodsText(List methods)
+ {
+ string text = "";
+ foreach (AnimationMethodMap methodMap in methods)
+ {
+ text += string.Format("{0}.{1} ( {2} )\n", methodMap.sourceBehaviour.GetType().Name, methodMap.Name, GetTypeName(methodMap.parameterType));
+ }
+ text = text.Trim();
+ return text;
+ }
+
+ static string GetTypeName(Type t)
+ {
+ if (t == null)
+ return "";
+ if (t == typeof(int))
+ return "int";
+ if (t == typeof(float))
+ return "float";
+ if (t == typeof(string))
+ return "string";
+ if (t == typeof(bool))
+ return "bool";
+ return t.Name;
+ }
+
+ static string GetFormattedMethodName(AnimationMethodMap methodMap)
+ {
+ string targetName = methodMap.sourceBehaviour.GetType().Name;
+ string methodName = methodMap.Name;
+ string args = GetTypeName(methodMap.parameterType);
+
+ if (methodName.StartsWith("set_") || methodName.StartsWith("get_"))
+ return string.Format("{0}/Properties/{1} ( {2} )", targetName, methodName, args);
+ else
+ return string.Format("{0}/Methods/{1} ( {2} )", targetName, methodName, args);
+ }
+
public static void OnDisabledAnimationEvent()
{
AnimationEvent dummyEvent = new AnimationEvent();
@@ -169,11 +227,13 @@ public static void OnDisabledAnimationEvent()
using (new EditorGUI.DisabledScope(true))
{
dummyEvent.functionName = EditorGUILayout.TextField(EditorGUIUtility.TrTextContent("Function"), dummyEvent.functionName);
- DoEditRegularParameters(new AnimationEvent[] {dummyEvent}, typeof(AnimationEvent));
+ DoEditRegularParameters(new AnimationEvent[] { dummyEvent }, typeof(AnimationEvent));
}
}
- public static void CollectSupportedMethods(GameObject gameObject, List supportedMethods, HashSet overloadedMethods)
+ static Dictionary> s_TypeAnimationMethodMapCache = new Dictionary>();
+
+ static void CollectSupportedMethods(GameObject gameObject, List supportedMethods, List overloadedMethods, List duplicatedMethods)
{
if (gameObject == null)
return;
@@ -188,59 +248,99 @@ public static void CollectSupportedMethods(GameObject gameObject, List validMethods))
{
- MethodInfo method = methods[i];
- string name = method.Name;
+ var pendingValidMethods = new List();
+ MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly );
+ for (int i = 0; i < methods.Length; i++)
+ {
+ MethodInfo method = methods[i];
+ string name = method.Name;
- if (!IsSupportedMethodName(name))
- continue;
+ if (!IsSupportedMethodName(name))
+ continue;
- ParameterInfo[] parameters = method.GetParameters();
- if (parameters.Length > 1)
- continue;
+ ParameterInfo[] parameters = method.GetParameters();
+ if (parameters.Length > 1)
+ continue;
- Type parameterType = null;
+ Type parameterType = null;
- if (parameters.Length == 1)
- {
- parameterType = parameters[0].ParameterType;
- if (!(parameterType == typeof(string) ||
- parameterType == typeof(float) ||
- parameterType == typeof(int) ||
- parameterType == typeof(AnimationEvent) ||
- parameterType == typeof(UnityEngine.Object) ||
- parameterType.IsSubclassOf(typeof(UnityEngine.Object)) ||
- parameterType.IsEnum))
- continue;
+ if (parameters.Length == 1)
+ {
+ parameterType = parameters[0].ParameterType;
+ if (!(parameterType == typeof(string) ||
+ parameterType == typeof(float) ||
+ parameterType == typeof(int) ||
+ parameterType == typeof(AnimationEvent) ||
+ parameterType == typeof(UnityEngine.Object) ||
+ parameterType.IsSubclassOf(typeof(UnityEngine.Object)) ||
+ parameterType.IsEnum))
+ continue;
+ }
+
+ AnimationMethodMap newMethodMap = new AnimationMethodMap
+ {
+ sourceBehaviour = behaviour,
+ methodInfo = method,
+ parameterType = parameterType
+ };
+
+ newMethodMap.methodMenuPath = GetFormattedMethodName(newMethodMap);
+
+ pendingValidMethods.Add(newMethodMap);
}
- AnimationWindowEventMethod newMethod = new AnimationWindowEventMethod();
- newMethod.name = method.Name;
- newMethod.parameterType = parameterType;
+ validMethods = pendingValidMethods.AsReadOnly();
+ s_TypeAnimationMethodMapCache.Add(type, validMethods);
+ }
+ foreach (var method in validMethods)
+ {
// Since AnimationEvents only stores method name, it can't handle functions with multiple overloads.
- // Only retrieve first found function, but discard overloads.
- int existingMethodIndex = supportedMethods.FindIndex(m => m.name == name);
+ // or functions with the same name across multiple monobehaviours
+ // Only retrieve first found method, and discard overloads and duplicate names.
+ int existingMethodIndex = supportedMethods.FindIndex(m => m.Name == method.Name);
if (existingMethodIndex != -1)
{
// The method is only ambiguous if it has a different signature to the one we saw before
- if (supportedMethods[existingMethodIndex].parameterType != parameterType)
+ if (supportedMethods[existingMethodIndex].parameterType != method.parameterType)
+ {
+ overloadedMethods.Add(method);
+ }
+ // Otherwise, there is another monobehaviour with the same method name.
+ else
{
- overloadedMethods.Add(name);
+ duplicatedMethods.Add(method);
}
}
else
{
- supportedMethods.Add(newMethod);
+ supportedMethods.Add(method);
}
}
+
type = type.BaseType;
}
}
}
+ ///
+ /// Maps the methodInfo and paramter type of a considered animation method to a source monobeheaviour.
+ /// Mimics the structure of
+ ///
+ struct AnimationMethodMap
+ {
+ public Object sourceBehaviour;
+ public MethodInfo methodInfo;
+ public Type parameterType;
+
+ // Used for caching
+ public string methodMenuPath;
+
+ public string Name => methodInfo?.Name ?? "";
+ }
+
public static string FormatEvent(GameObject root, AnimationEvent evt)
{
if (string.IsNullOrEmpty(evt.functionName))
@@ -273,7 +373,7 @@ public static string FormatEvent(GameObject root, AnimationEvent evt)
if (method == null)
continue;
- var parameterTypes = method.GetParameters().Select(p => p.ParameterType);
+ var parameterTypes = method.GetParameters();
return evt.functionName + FormatEventArguments(parameterTypes, evt);
}
@@ -382,15 +482,15 @@ private static bool IsSupportedMethodName(string name)
return name != "Main" && name != "Start" && name != "Awake" && name != "Update";
}
- private static string FormatEventArguments(IEnumerable paramTypes, AnimationEvent evt)
+ private static string FormatEventArguments(ParameterInfo[] paramTypes, AnimationEvent evt)
{
- if (!paramTypes.Any())
+ if (paramTypes.Length == 0)
return " ( )";
- if (paramTypes.Count() > 1)
+ if (paramTypes.Length > 1)
return kNotSupportedPostFix;
- var paramType = paramTypes.First();
+ var paramType = paramTypes[0].ParameterType;
if (paramType == typeof(string))
return " ( \"" + evt.stringParameter + "\" )";
@@ -427,6 +527,9 @@ private struct AnimationWindowEventData
public AnimationEvent[] selectedEvents;
}
+
+ // this are used so we don't alloc new lists on every call
+ static List getDataSelectedEvents;
private static AnimationWindowEventData GetData(AnimationWindowEvent[] awEvents)
{
var data = new AnimationWindowEventData();
@@ -445,14 +548,15 @@ private static AnimationWindowEventData GetData(AnimationWindowEvent[] awEvents)
if (data.events != null)
{
- List selectedEvents = new List();
+ getDataSelectedEvents ??= new List();
+ getDataSelectedEvents.Clear();
foreach (var awEvent in awEvents)
{
if (awEvent.eventIndex >= 0 && awEvent.eventIndex < data.events.Length)
- selectedEvents.Add(data.events[awEvent.eventIndex]);
+ getDataSelectedEvents.Add(data.events[awEvent.eventIndex]);
}
- data.selectedEvents = selectedEvents.ToArray();
+ data.selectedEvents = getDataSelectedEvents.ToArray();
}
return data;
@@ -478,11 +582,11 @@ private static void SetData(AnimationWindowEvent[] awEvents, AnimationWindowEven
}
}
- [MenuItem("CONTEXT/AnimationWindowEvent/Reset")]
+ [MenuItem("CONTEXT/AnimationWindowEvent/Reset", secondaryPriority = 7)]
static void ResetValues(MenuCommand command)
{
AnimationWindowEvent awEvent = command.context as AnimationWindowEvent;
- AnimationWindowEvent[] awEvents = new AnimationWindowEvent[] {awEvent};
+ AnimationWindowEvent[] awEvents = new AnimationWindowEvent[] { awEvent };
AnimationWindowEventData data = GetData(awEvents);
if (data.events == null || data.selectedEvents == null || data.selectedEvents.Length == 0)
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchy.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchy.cs
index 2147351f6a..a5e353264b 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchy.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchy.cs
@@ -6,6 +6,9 @@
using UnityEditor;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
+using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+using TreeViewState = UnityEditor.IMGUI.Controls.TreeViewState;
namespace UnityEditorInternal
{
@@ -44,6 +47,7 @@ internal class AnimationWindowHierarchy
// Animation window shared state
private AnimationWindowState m_State;
private TreeViewController m_TreeView;
+ private AnimationWindowHierarchyGUI m_HierarchyGUI;
public Vector2 GetContentSize()
{
@@ -65,6 +69,7 @@ public void OnGUI(Rect position)
{
m_TreeView.OnEvent();
m_TreeView.OnGUI(position, GUIUtility.GetControlID(FocusType.Keyboard));
+ m_HierarchyGUI.ReclaimPendingFieldFocus();
}
public void Init(EditorWindow owner, Rect rect)
@@ -74,9 +79,10 @@ public void Init(EditorWindow owner, Rect rect)
m_TreeView = new TreeViewController(owner, m_State.hierarchyState);
m_State.hierarchyData = new AnimationWindowHierarchyDataSource(m_TreeView, m_State);
+ m_HierarchyGUI = new AnimationWindowHierarchyGUI(m_TreeView, m_State);
m_TreeView.Init(rect,
m_State.hierarchyData,
- new AnimationWindowHierarchyGUI(m_TreeView, m_State),
+ m_HierarchyGUI,
null
);
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyDataSource.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyDataSource.cs
index 820a11e84c..00dbb47ccd 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyDataSource.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyDataSource.cs
@@ -7,6 +7,11 @@
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using Object = UnityEngine.Object;
+using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+using TreeViewUtility = UnityEditor.IMGUI.Controls.TreeViewUtility;
+using TreeViewDataSource = UnityEditor.IMGUI.Controls.TreeViewDataSource;
+
namespace UnityEditorInternal
{
@@ -48,10 +53,10 @@ public override void FetchData()
List childNodes = new List();
- if (state.allCurves.Count > 0)
+ if (state.filteredCurves.Count > 0)
{
AnimationWindowHierarchyMasterNode masterNode = new AnimationWindowHierarchyMasterNode();
- masterNode.curves = state.allCurves.ToArray();
+ masterNode.curves = state.filteredCurves.ToArray();
childNodes.Add(masterNode);
}
@@ -75,17 +80,25 @@ public List CreateTreeFromCurves()
List nodes = new List();
List singlePropertyCurves = new List();
- AnimationWindowCurve[] curves = state.allCurves.ToArray();
+ List curves = state.filteredCurves;
AnimationWindowHierarchyNode parentNode = (AnimationWindowHierarchyNode)m_RootItem;
+ SerializedObject so = null;
- for (int i = 0; i < curves.Length; i++)
+ for (int i = 0; i < curves.Count; i++)
{
AnimationWindowCurve curve = curves[i];
if (!state.ShouldShowCurve(curve))
continue;
- AnimationWindowCurve nextCurve = i < curves.Length - 1 ? curves[i + 1] : null;
+ AnimationWindowCurve nextCurve = i < curves.Count - 1 ? curves[i + 1] : null;
+
+ if (curve.isSerializeReferenceCurve && state.activeRootGameObject != null)
+ {
+ var animatedObject = AnimationUtility.GetAnimatedObject(state.activeRootGameObject, curve.binding);
+ if (animatedObject != null && (so == null || so.targetObject != animatedObject))
+ so = new SerializedObject(animatedObject);
+ }
singlePropertyCurves.Add(curve);
@@ -94,12 +107,12 @@ public List CreateTreeFromCurves()
// We expect curveBindings to come sorted by propertyname
// So we compare curve vs nextCurve. If its different path or different group (think "scale.xyz" as group), then we know this is the last element of such group.
- if (i == curves.Length - 1 || !areSameGroup || !areSamePathAndType)
+ if (i == curves.Count - 1 || !areSameGroup || !areSamePathAndType)
{
if (singlePropertyCurves.Count > 1)
- nodes.Add(AddPropertyGroupToHierarchy(singlePropertyCurves.ToArray(), parentNode));
+ nodes.Add(AddPropertyGroupToHierarchy(singlePropertyCurves.ToArray(), parentNode, so));
else
- nodes.Add(AddPropertyToHierarchy(singlePropertyCurves[0], parentNode));
+ nodes.Add(AddPropertyToHierarchy(singlePropertyCurves[0], parentNode, so));
singlePropertyCurves.Clear();
}
}
@@ -107,12 +120,12 @@ public List CreateTreeFromCurves()
return nodes;
}
- private AnimationWindowHierarchyPropertyGroupNode AddPropertyGroupToHierarchy(AnimationWindowCurve[] curves, AnimationWindowHierarchyNode parentNode)
+ private AnimationWindowHierarchyPropertyGroupNode AddPropertyGroupToHierarchy(AnimationWindowCurve[] curves, AnimationWindowHierarchyNode parentNode, SerializedObject so)
{
List childNodes = new List();
System.Type animatableObjectType = curves[0].type;
- AnimationWindowHierarchyPropertyGroupNode node = new AnimationWindowHierarchyPropertyGroupNode(animatableObjectType, 0, AnimationWindowUtility.GetPropertyGroupName(curves[0].propertyName), curves[0].path, parentNode);
+ AnimationWindowHierarchyPropertyGroupNode node = new AnimationWindowHierarchyPropertyGroupNode(animatableObjectType, 0, AnimationWindowUtility.GetPropertyGroupName(curves[0].propertyName), curves[0].path, parentNode, AnimationWindowUtility.GetNicePropertyGroupDisplayName(curves[0].binding, so));
node.icon = GetIcon(curves[0].binding);
@@ -121,7 +134,7 @@ private AnimationWindowHierarchyPropertyGroupNode AddPropertyGroupToHierarchy(An
foreach (AnimationWindowCurve curve in curves)
{
- AnimationWindowHierarchyPropertyNode childNode = AddPropertyToHierarchy(curve, node);
+ AnimationWindowHierarchyPropertyNode childNode = AddPropertyToHierarchy(curve, node, so);
// For child nodes we do not want to display the type in front (It is already shown by the group node)
childNode.displayName = AnimationWindowUtility.GetPropertyDisplayName(childNode.propertyName);
childNodes.Add(childNode);
@@ -131,9 +144,9 @@ private AnimationWindowHierarchyPropertyGroupNode AddPropertyGroupToHierarchy(An
return node;
}
- private AnimationWindowHierarchyPropertyNode AddPropertyToHierarchy(AnimationWindowCurve curve, AnimationWindowHierarchyNode parentNode)
+ private AnimationWindowHierarchyPropertyNode AddPropertyToHierarchy(AnimationWindowCurve curve, AnimationWindowHierarchyNode parentNode, SerializedObject so)
{
- AnimationWindowHierarchyPropertyNode node = new AnimationWindowHierarchyPropertyNode(curve.type, 0, curve.propertyName, curve.path, parentNode, curve.binding, curve.isPPtrCurve);
+ AnimationWindowHierarchyPropertyNode node = new AnimationWindowHierarchyPropertyNode(curve.type, 0, curve.propertyName, curve.path, parentNode, curve.binding, curve.isPPtrCurve, AnimationWindowUtility.GetNicePropertyDisplayName(curve.binding, so));
if (parentNode.icon != null)
node.icon = parentNode.icon;
@@ -147,13 +160,35 @@ private AnimationWindowHierarchyPropertyNode AddPropertyToHierarchy(AnimationWin
public Texture2D GetIcon(EditorCurveBinding curveBinding)
{
- if (state.activeRootGameObject != null)
+ return AssetPreview.GetMiniTypeThumbnail(curveBinding.type);
+ }
+
+ public void UpdateSerializeReferenceCurvesArrayNiceDisplayName()
+ {
+ if (state.activeRootGameObject == null)
+ return;
+
+ //This is required in the case that there might have been a topological change
+ //leading to a different display name(topological path)
+ SerializedObject so = null;
+ foreach (AnimationWindowHierarchyNode hierarchyNode in GetRows())
{
- Object animatedObject = AnimationUtility.GetAnimatedObject(state.activeRootGameObject, curveBinding);
- if (animatedObject != null)
- return AssetPreview.GetMiniThumbnail(animatedObject);
+ if (hierarchyNode.curves != null)
+ {
+ foreach (var curve in hierarchyNode.curves)
+ {
+ if (curve.isSerializeReferenceCurve && hierarchyNode.displayName.Contains(".Array.data["))
+ {
+ var animatedObject = AnimationUtility.GetAnimatedObject(state.activeRootGameObject, curve.binding);
+ if (animatedObject != null && (so == null || so.targetObject != animatedObject))
+ so = new SerializedObject(animatedObject);
+
+ hierarchyNode.displayName = AnimationWindowUtility.GetNicePropertyDisplayName(curve.binding, so);
+ }
+ }
+ }
}
- return AssetPreview.GetMiniTypeThumbnail(curveBinding.type);
+
}
public void UpdateData()
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs
index 279995baab..af65ed17fd 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyGUI.cs
@@ -9,6 +9,10 @@
using System.Linq;
using UnityEditor.IMGUI.Controls;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+using TreeViewGUI = UnityEditor.IMGUI.Controls.TreeViewGUI;
+using TreeViewController = UnityEditor.IMGUI.Controls.TreeViewController;
+
namespace UnityEditorInternal
{
internal class AnimationWindowHierarchyGUI : TreeViewGUI
@@ -30,6 +34,9 @@ internal class AnimationWindowHierarchyGUI : TreeViewGUI
private int[] m_HierarchyItemValueControlIDs;
private int[] m_HierarchyItemButtonControlIDs;
+ private bool m_NeedsToReclaimFieldFocus;
+ private int m_FieldToReclaimFocus;
+
private const float k_RowRightOffset = 10;
private const float k_ValueFieldDragWidth = 15;
private const float k_ValueFieldWidth = 80;
@@ -40,11 +47,24 @@ internal class AnimationWindowHierarchyGUI : TreeViewGUI
public const float k_AddCurveButtonNodeHeight = 40f;
public const float k_RowBackgroundColorBrightness = 0.28f;
private const float k_SelectedPhantomCurveColorMultiplier = 1.4f;
+ private const float k_CurveColorIndicatorIconSize = 11;
private readonly static Color k_KeyColorInDopesheetMode = new Color(0.7f, 0.7f, 0.7f, 1);
private readonly static Color k_KeyColorForNonCurves = new Color(0.7f, 0.7f, 0.7f, 0.5f);
private readonly static Color k_LeftoverCurveColor = Color.yellow;
+ private static readonly string k_DefaultValue = L10n.Tr(" (Default Value)");
+ private static readonly string k_TransformPosition = L10n.Tr("Transform position, rotation and scale can't be partially animated. This value will be animated to the default value");
+ private static readonly string k_Missing = L10n.Tr(" (Missing!)");
+ private static readonly string k_GameObjectComponentMissing = L10n.Tr("The GameObject or Component is missing ({0})");
+ private static readonly string k_DuplicateGameObjectName = L10n.Tr(" (Duplicate GameObject name!)");
+ private static readonly string k_TargetForCurveIsAmbigous = L10n.Tr("Target for curve is ambiguous since there are multiple GameObjects with same name ({0})");
+ private static readonly string k_RemoveProperties = L10n.Tr("Remove Properties");
+ private static readonly string k_RemoveProperty = L10n.Tr("Remove Property");
+ private static readonly string k_AddKey = L10n.Tr("Add Key");
+ private static readonly string k_DeleteKey = L10n.Tr("Delete Key");
+ private static readonly string k_RemoveCurve = L10n.Tr("Remove Curve");
+
internal static int s_WasInsideValueRectFrame = -1;
public AnimationWindowHierarchyGUI(TreeViewController treeView, AnimationWindowState state)
@@ -158,8 +178,6 @@ private void DoAddCurveButton(Rect rect, AnimationWindowHierarchyNode node, int
// the control id counter to shift when scrolling through the view.
if (DoTreeViewButton(m_HierarchyItemButtonControlIDs[row], rectWithMargin, k_AnimatePropertyLabel, GUI.skin.button))
{
- AddCurvesPopupHierarchyDataSource.showEntireHierarchy = true;
-
if (AddCurvesPopup.ShowAtPosition(rectWithMargin, state, OnNewCurveAdded))
{
GUIUtility.ExitGUI();
@@ -235,7 +253,7 @@ private void DoIconAndName(Rect rect, AnimationWindowHierarchyNode node, bool se
if (node is AnimationWindowHierarchyPropertyNode)
rect.width -= k_ValueFieldOffsetFromRightSide + 2;
- bool isLeftOverCurve = AnimationWindowUtility.IsNodeLeftOverCurve(node);
+ bool isLeftOverCurve = AnimationWindowUtility.IsNodeLeftOverCurve(state, node);
bool isAmbiguous = AnimationWindowUtility.IsNodeAmbiguous(node);
bool isPhantom = AnimationWindowUtility.IsNodePhantom(node);
@@ -243,18 +261,18 @@ private void DoIconAndName(Rect rect, AnimationWindowHierarchyNode node, bool se
string tooltipText = "";
if (isPhantom)
{
- warningText = " (Default Value)";
- tooltipText = "Transform position, rotation and scale can't be partially animated. This value will be animated to the default value";
+ warningText = k_DefaultValue;
+ tooltipText = k_TransformPosition;
}
if (isLeftOverCurve)
{
- warningText = " (Missing!)";
- tooltipText = "The GameObject or Component is missing (" + node.path + ")";
+ warningText = k_Missing;
+ tooltipText = string.Format(k_GameObjectComponentMissing, node.path);
}
if (isAmbiguous)
{
- warningText = " (Duplicate GameObject name!)";
- tooltipText = "Target for curve is ambiguous since there are multiple GameObjects with same name (" + node.path + ")";
+ warningText = k_DuplicateGameObjectName;
+ tooltipText = string.Format(k_TargetForCurveIsAmbigous, node.path);
}
Color oldColor = lineStyle.normal.textColor;
@@ -286,6 +304,7 @@ private void DoIconAndName(Rect rect, AnimationWindowHierarchyNode node, bool se
SetStyleTextColor(lineStyle, textColor);
rect.xMin += (int)(indent + foldoutStyleWidth + lineStyle.margin.left);
+ rect.yMin = rect.y + (rect.height - EditorGUIUtility.singleLineHeight) / 2;
GUI.Label(rect, Styles.content, lineStyle);
SetStyleTextColor(lineStyle, oldColor);
@@ -316,12 +335,10 @@ private void DoValueField(Rect rect, AnimationWindowHierarchyNode node, int row)
// We do valuefields for dopelines that only have single curve
AnimationWindowCurve curve = curves[0];
- object objectValue = CurveBindingUtility.GetCurrentValue(state, curve);
+ object value = CurveBindingUtility.GetCurrentValue(state, curve);
- if (objectValue is float)
+ if (!curve.isPPtrCurve)
{
- float value = (float)objectValue;
-
Rect valueFieldDragRect = new Rect(rect.xMax - k_ValueFieldOffsetFromRightSide - k_ValueFieldDragWidth, rect.y, k_ValueFieldDragWidth, rect.height);
Rect valueFieldRect = new Rect(rect.xMax - k_ValueFieldOffsetFromRightSide, rect.y, k_ValueFieldWidth, rect.height);
@@ -332,7 +349,7 @@ private void DoValueField(Rect rect, AnimationWindowHierarchyNode node, int row)
if (curve.valueType == typeof(bool))
{
- value = GUI.Toggle(valueFieldRect, m_HierarchyItemValueControlIDs[row], value != 0, GUIContent.none, EditorStyles.toggle) ? 1 : 0;
+ value = GUI.Toggle(valueFieldRect, m_HierarchyItemValueControlIDs[row], Convert.ToSingle(value) != 0f, GUIContent.none, EditorStyles.toggle) ? 1f : 0f;
}
else
{
@@ -342,48 +359,59 @@ private void DoValueField(Rect rect, AnimationWindowHierarchyNode node, int row)
&& Event.current.type == EventType.KeyDown
&& (Event.current.character == '\n' || (int)Event.current.character == 3));
- // Force back keyboard focus to float field editor when editing it.
- // TreeView forces keyboard focus on itself at mouse down and we lose focus here.
+ // Force back keyboard focus to float field editor when editing it since the TreeView forces keyboard focus on itself at mouse down.
+ // The focus will be reclaimed after the TreeViewController.OnGUI call.
if (EditorGUI.s_RecycledEditor.controlID == id && Event.current.type == EventType.MouseDown && valueFieldRect.Contains(Event.current.mousePosition))
{
- GUIUtility.keyboardControl = id;
+ m_NeedsToReclaimFieldFocus = true;
+ m_FieldToReclaimFocus = id;
}
- value = EditorGUI.DoFloatField(EditorGUI.s_RecycledEditor,
- valueFieldRect,
- valueFieldDragRect,
- id,
- value,
- "g5",
- m_AnimationSelectionTextField,
- true);
- if (enterInTextField)
+ if (curve.isDiscreteCurve)
{
- GUI.changed = true;
- Event.current.Use();
+ value = EditorGUI.DoIntField(EditorGUI.s_RecycledEditor,
+ valueFieldRect,
+ valueFieldDragRect,
+ id,
+ Convert.ToInt32(value),
+ EditorGUI.kIntFieldFormatString,
+ m_AnimationSelectionTextField,
+ true,
+ 0);
+ if (enterInTextField)
+ {
+ GUI.changed = true;
+ Event.current.Use();
+ }
+ }
+ else
+ {
+ value = EditorGUI.DoFloatField(EditorGUI.s_RecycledEditor,
+ valueFieldRect,
+ valueFieldDragRect,
+ id,
+ Convert.ToSingle(value),
+ "g5",
+ m_AnimationSelectionTextField,
+ true);
+ if (enterInTextField)
+ {
+ GUI.changed = true;
+ Event.current.Use();
+ }
+
+ var floatValue = Convert.ToSingle(value);
+ if (float.IsInfinity(floatValue) || float.IsNaN(floatValue))
+ value = 0f;
}
}
- if (float.IsInfinity(value) || float.IsNaN(value))
- value = 0;
-
if (EditorGUI.EndChangeCheck())
{
string undoLabel = "Edit Key";
AnimationKeyTime newAnimationKeyTime = AnimationKeyTime.Time(state.currentTime, curve.clip.frameRate);
-
- AnimationWindowKeyframe existingKeyframe = null;
- foreach (AnimationWindowKeyframe keyframe in curve.m_Keyframes)
- {
- if (Mathf.Approximately(keyframe.time, state.currentTime))
- existingKeyframe = keyframe;
- }
-
- if (existingKeyframe == null)
- AnimationWindowUtility.AddKeyframeToCurve(curve, value, curve.valueType, newAnimationKeyTime);
- else
- existingKeyframe.value = value;
+ AnimationWindowUtility.AddKeyframeToCurve(curve, value, curve.valueType, newAnimationKeyTime);
state.SaveCurve(curve.clip, curve, undoLabel);
curvesChanged = true;
@@ -392,7 +420,22 @@ private void DoValueField(Rect rect, AnimationWindowHierarchyNode node, int row)
}
if (curvesChanged)
+ {
+ //Fix for case 1382193: Stop recording any candidates if a property value field is modified
+ if (AnimationMode.IsRecordingCandidates())
+ state.ClearCandidates();
+
state.ResampleAnimation();
+ }
+ }
+
+ internal void ReclaimPendingFieldFocus()
+ {
+ if (m_NeedsToReclaimFieldFocus)
+ {
+ GUIUtility.keyboardControl = m_FieldToReclaimFocus;
+ m_NeedsToReclaimFieldFocus = false;
+ }
}
private bool DoTreeViewButton(int id, Rect position, GUIContent content, GUIStyle style)
@@ -431,7 +474,7 @@ private void DoCurveDropdown(Rect rect, AnimationWindowHierarchyNode node, int r
{
rect = new Rect(
rect.xMax - k_RowRightOffset - 12,
- rect.yMin + 2,
+ rect.yMin + 2 + (rect.height - EditorGUIUtility.singleLineHeight) / 2,
22, 12);
// case 767863.
@@ -466,15 +509,14 @@ private void DoCurveColorIndicator(Rect rect, AnimationWindowHierarchyNode node)
{
foreach (var curve in node.curves)
{
- if (curve.m_Keyframes.Any(key => state.time.ContainsTime(key.time)))
+ if (curve.keyframes.Any(key => state.time.ContainsTime(key.time)))
{
hasKey = true;
}
}
}
-
Texture icon = hasKey ? CurveUtility.GetIconKey() : CurveUtility.GetIconCurve();
- rect = new Rect(rect.xMax - k_RowRightOffset - (icon.width / 2) - 5, rect.yMin + k_ColorIndicatorTopMargin, icon.width, icon.height);
+ rect = new Rect(rect.xMax - k_RowRightOffset - (k_CurveColorIndicatorIconSize / 2) - 5, rect.yMin + k_ColorIndicatorTopMargin + (rect.height - EditorGUIUtility.singleLineHeight) / 2, k_CurveColorIndicatorIconSize, k_CurveColorIndicatorIconSize);
GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit, true, 1);
GUI.color = originalColor;
@@ -531,7 +573,7 @@ private GenericMenu GenerateMenu(List interactedNo
GenericMenu menu = new GenericMenu();
// Remove curves
- GUIContent removePropertyContent = new GUIContent(curves.Count > 1 || forceGroupRemove ? "Remove Properties" : "Remove Property");
+ GUIContent removePropertyContent = new GUIContent(curves.Count > 1 || forceGroupRemove ? k_RemoveProperties : k_RemoveProperty);
if (!enabled)
menu.AddDisabledItem(removePropertyContent);
else
@@ -582,13 +624,13 @@ private GenericMenu GenerateMenu(List interactedNo
string str;
- str = "Add Key";
+ str = k_AddKey;
if (allHaveKeys || !enabled)
menu.AddDisabledItem(new GUIContent(str));
else
menu.AddItem(new GUIContent(str), false, AddKeysAtCurrentTime, curves);
- str = "Delete Key";
+ str = k_DeleteKey;
if (noneHaveKeys || !enabled)
menu.AddDisabledItem(new GUIContent(str));
else
@@ -634,7 +676,7 @@ private void RemoveCurvesFromSelectedNodes()
private void RemoveCurvesFromNodes(List nodes)
{
- string undoLabel = "Remove Curve";
+ string undoLabel = k_RemoveCurve;
state.SaveKeySelection(undoLabel);
foreach (var node in nodes)
@@ -846,7 +888,7 @@ override protected void RenameEnded()
{
EditorCurveBinding newBinding = AnimationWindowUtility.GetRenamedBinding(curve.binding, newName);
- if (AnimationWindowUtility.CurveExists(newBinding, state.allCurves.ToArray()))
+ if (AnimationWindowUtility.CurveExists(newBinding, state.filteredCurves.ToArray()))
{
Debug.LogWarning("Curve already exists, renaming cancelled.");
continue;
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyNode.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyNode.cs
index 7ed4ca36a9..833ebd9bc4 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyNode.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowHierarchyNode.cs
@@ -6,6 +6,8 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
+
namespace UnityEditorInternal
{
@@ -33,8 +35,8 @@ public AnimationWindowHierarchyNode(int instanceID, int depth, TreeViewItem pare
internal class AnimationWindowHierarchyPropertyGroupNode : AnimationWindowHierarchyNode
{
- public AnimationWindowHierarchyPropertyGroupNode(System.Type animatableObjectType, int setId, string propertyName, string path, TreeViewItem parent)
- : base(AnimationWindowUtility.GetPropertyNodeID(setId, path, animatableObjectType, propertyName), parent != null ? parent.depth + 1 : -1, parent, animatableObjectType, AnimationWindowUtility.GetPropertyGroupName(propertyName), path, AnimationWindowUtility.GetNicePropertyGroupDisplayName(animatableObjectType, propertyName))
+ public AnimationWindowHierarchyPropertyGroupNode(System.Type animatableObjectType, int setId, string propertyName, string path, TreeViewItem parent, string displayName)
+ : base(AnimationWindowUtility.GetPropertyNodeID(setId, path, animatableObjectType, propertyName), parent != null ? parent.depth + 1 : -1, parent, animatableObjectType, AnimationWindowUtility.GetPropertyGroupName(propertyName), path, displayName)
{}
}
@@ -42,8 +44,8 @@ internal class AnimationWindowHierarchyPropertyNode : AnimationWindowHierarchyNo
{
public bool isPptrNode;
- public AnimationWindowHierarchyPropertyNode(System.Type animatableObjectType, int setId, string propertyName, string path, TreeViewItem parent, EditorCurveBinding binding, bool isPptrNode)
- : base(AnimationWindowUtility.GetPropertyNodeID(setId, path, animatableObjectType, propertyName), parent != null ? parent.depth + 1 : -1, parent, animatableObjectType, propertyName, path, AnimationWindowUtility.GetNicePropertyDisplayName(animatableObjectType, propertyName))
+ public AnimationWindowHierarchyPropertyNode(System.Type animatableObjectType, int setId, string propertyName, string path, TreeViewItem parent, EditorCurveBinding binding, bool isPptrNode, string displayName)
+ : base(AnimationWindowUtility.GetPropertyNodeID(setId, path, animatableObjectType, propertyName), parent != null ? parent.depth + 1 : -1, parent, animatableObjectType, propertyName, path, displayName)
{
this.binding = binding;
this.isPptrNode = isPptrNode;
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowKeyframe.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowKeyframe.cs
index 2a310b8c35..e9fa64f7fa 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowKeyframe.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowKeyframe.cs
@@ -2,6 +2,7 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+using System;
using UnityEngine;
using UnityEditor;
@@ -104,7 +105,16 @@ public AnimationWindowKeyframe(AnimationWindowKeyframe key)
public AnimationWindowKeyframe(AnimationWindowCurve curve, Keyframe key)
{
this.time = key.time;
- this.value = key.value;
+
+ if (curve.isDiscreteCurve)
+ {
+ this.value = UnityEngine.Animations.DiscreteEvaluationAttributeUtilities.ConvertFloatToDiscreteInt(key.value);
+ }
+ else
+ {
+ this.value = key.value;
+ }
+
this.curve = curve;
this.m_InTangent = key.inTangent;
this.m_OutTangent = key.outTangent;
@@ -139,9 +149,9 @@ public int GetHash()
public int GetIndex()
{
- for (int i = 0; i < curve.m_Keyframes.Count; i++)
+ for (int i = 0; i < curve.keyframes.Count; i++)
{
- if (curve.m_Keyframes[i] == this)
+ if (curve.keyframes[i] == this)
{
return i;
}
@@ -151,7 +161,20 @@ public int GetIndex()
public Keyframe ToKeyframe()
{
- var keyframe = new Keyframe(time, (float)value, inTangent, outTangent);
+ float floatValue;
+ if (curve.isDiscreteCurve)
+ {
+ // case 1395978
+ // Negative int values converted to float create NaN values. Limiting discrete int values to only positive values
+ // until we rewrite the animation backend with dedicated int curves.
+ floatValue = UnityEngine.Animations.DiscreteEvaluationAttributeUtilities.ConvertDiscreteIntToFloat(Math.Max(Convert.ToInt32(value), 0));
+ }
+ else
+ {
+ floatValue = Convert.ToSingle(value);
+ }
+
+ var keyframe = new Keyframe(time, floatValue, inTangent, outTangent);
keyframe.tangentModeInternal = m_TangentMode;
keyframe.weightedMode = weightedMode;
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowSelectionItem.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowSelectionItem.cs
index b857dccea1..98e48d56ef 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowSelectionItem.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowSelectionItem.cs
@@ -12,15 +12,14 @@
namespace UnityEditorInternal
{
- internal class AnimationWindowSelectionItem : ScriptableObject, System.IEquatable, ISelectionBinding
+ [Serializable]
+ abstract class AnimationWindowSelectionItem : System.IEquatable, ISelectionBinding
{
[SerializeField] private int m_Id;
[SerializeField] private GameObject m_GameObject;
[SerializeField] private ScriptableObject m_ScriptableObject;
[SerializeField] private AnimationClip m_AnimationClip;
- private List m_CurvesCache = null;
-
public virtual int id { get { return m_Id; } set { m_Id = value; } }
public virtual GameObject gameObject { get { return m_GameObject; } set { m_GameObject = value; } }
@@ -195,137 +194,6 @@ public virtual bool canCreateClips
public virtual bool canSyncSceneSelection { get { return true; } }
- public List curves
- {
- get
- {
- if (m_CurvesCache == null)
- {
- m_CurvesCache = new List();
-
- if (animationClip != null)
- {
- EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(animationClip);
- EditorCurveBinding[] objectCurveBindings = AnimationUtility.GetObjectReferenceCurveBindings(animationClip);
-
- List transformCurves = new List();
-
- foreach (EditorCurveBinding curveBinding in curveBindings)
- {
- if (AnimationWindowUtility.ShouldShowAnimationWindowCurve(curveBinding))
- {
- AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, curveBinding, GetEditorCurveValueType(curveBinding));
- curve.selectionBinding = this;
-
- m_CurvesCache.Add(curve);
-
- if (AnimationWindowUtility.IsActualTransformCurve(curveBinding))
- {
- transformCurves.Add(curve);
- }
- }
- }
-
- foreach (EditorCurveBinding curveBinding in objectCurveBindings)
- {
- AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, curveBinding, GetEditorCurveValueType(curveBinding));
- curve.selectionBinding = this;
-
- m_CurvesCache.Add(curve);
- }
-
- transformCurves.Sort();
- if (transformCurves.Count > 0)
- {
- FillInMissingTransformCurves(transformCurves, ref m_CurvesCache);
- }
- }
- // Curves need to be sorted with path/type/property name so it's possible to construct hierarchy from them
- // Sorting logic in AnimationWindowCurve.CompareTo()
- m_CurvesCache.Sort();
- }
-
- return m_CurvesCache;
- }
- }
-
- private void FillInMissingTransformCurves(List transformCurves, ref List curvesCache)
- {
- EditorCurveBinding lastBinding = transformCurves[0].binding;
- var propertyGroup = new EditorCurveBinding ? [3];
- string propertyGroupName;
- foreach (var transformCurve in transformCurves)
- {
- var transformBinding = transformCurve.binding;
- //if it's a new property group
- if (transformBinding.path != lastBinding.path
- || AnimationWindowUtility.GetPropertyGroupName(transformBinding.propertyName) != AnimationWindowUtility.GetPropertyGroupName(lastBinding.propertyName))
- {
- propertyGroupName = AnimationWindowUtility.GetPropertyGroupName(lastBinding.propertyName);
-
- FillPropertyGroup(ref propertyGroup, lastBinding, propertyGroupName, ref curvesCache);
-
- lastBinding = transformBinding;
-
- propertyGroup = new EditorCurveBinding ? [3];
- }
-
- AssignBindingToRightSlot(transformBinding, ref propertyGroup);
- }
- FillPropertyGroup(ref propertyGroup, lastBinding, AnimationWindowUtility.GetPropertyGroupName(lastBinding.propertyName), ref curvesCache);
- }
-
- private void FillPropertyGroup(ref EditorCurveBinding?[] propertyGroup, EditorCurveBinding lastBinding, string propertyGroupName, ref List curvesCache)
- {
- var newBinding = lastBinding;
- newBinding.isPhantom = true;
- if (!propertyGroup[0].HasValue)
- {
- newBinding.propertyName = propertyGroupName + ".x";
- AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, newBinding, GetEditorCurveValueType(newBinding));
- curve.selectionBinding = this;
- curvesCache.Add(curve);
- }
-
- if (!propertyGroup[1].HasValue)
- {
- newBinding.propertyName = propertyGroupName + ".y";
- AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, newBinding, GetEditorCurveValueType(newBinding));
- curve.selectionBinding = this;
- curvesCache.Add(curve);
- }
-
- if (!propertyGroup[2].HasValue)
- {
- newBinding.propertyName = propertyGroupName + ".z";
- AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, newBinding, GetEditorCurveValueType(newBinding));
- curve.selectionBinding = this;
- curvesCache.Add(curve);
- }
- }
-
- private void AssignBindingToRightSlot(EditorCurveBinding transformBinding, ref EditorCurveBinding?[] propertyGroup)
- {
- if (transformBinding.propertyName.EndsWith(".x"))
- {
- propertyGroup[0] = transformBinding;
- }
- else if (transformBinding.propertyName.EndsWith(".y"))
- {
- propertyGroup[1] = transformBinding;
- }
- else if (transformBinding.propertyName.EndsWith(".z"))
- {
- propertyGroup[2] = transformBinding;
- }
- }
-
- public static AnimationWindowSelectionItem Create()
- {
- AnimationWindowSelectionItem selectionItem = CreateInstance(typeof(AnimationWindowSelectionItem)) as AnimationWindowSelectionItem;
- return selectionItem;
- }
-
public int GetRefreshHash()
{
return unchecked (id * 19603 ^
@@ -334,11 +202,6 @@ public int GetRefreshHash()
(scriptableObject != null ? scriptableObject.GetHashCode() : 0));
}
- public void ClearCache()
- {
- m_CurvesCache = null;
- }
-
virtual public void Synchronize()
{
// nothing to do.
@@ -351,30 +214,5 @@ public bool Equals(AnimationWindowSelectionItem other)
gameObject == other.gameObject &&
scriptableObject == other.scriptableObject;
}
-
- public Type GetEditorCurveValueType(EditorCurveBinding curveBinding)
- {
- if (rootGameObject != null)
- {
- return AnimationUtility.GetEditorCurveValueType(rootGameObject, curveBinding);
- }
- else if (scriptableObject != null)
- {
- return AnimationUtility.GetEditorCurveValueType(scriptableObject, curveBinding);
- }
- else
- {
- if (curveBinding.isPPtrCurve)
- {
- // Cannot extract type of PPtrCurve.
- return null;
- }
- else
- {
- // Cannot extract type of AnimationCurve. Default to float.
- return typeof(float);
- }
- }
- }
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs
index 8b52dff073..6de5dd2e79 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowState.cs
@@ -3,20 +3,18 @@
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using System;
-using System.Reflection;
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
-using System.Collections;
using UnityEditor.IMGUI.Controls;
using Object = UnityEngine.Object;
-using Random = UnityEngine.Random;
+using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem;
namespace UnityEditorInternal
{
[System.Serializable]
- internal class AnimationWindowState : ScriptableObject, ICurveEditorState
+ class AnimationWindowState : ICurveEditorState
{
public enum RefreshType
{
@@ -29,23 +27,28 @@ public enum SnapMode
{
Disabled = 0,
SnapToFrame = 1,
+ [Obsolete("SnapToClipFrame has been made redundant with SnapToFrame, SnapToFrame will behave the same.")]
SnapToClipFrame = 2
}
- [SerializeField] public AnimationWindowHierarchyState hierarchyState; // Persistent state of treeview on the left side of window
[SerializeField] public AnimEditor animEditor; // Reference to owner of this state. Used to trigger repaints.
+ [SerializeField] public AnimationWindowHierarchyState hierarchyState = new(); // Persistent state of treeview on the left side of window
+ [NonSerialized] public AnimationWindowHierarchyDataSource hierarchyData;
+
+ [SerializeReference] private TimeArea m_TimeArea; // Either curveeditor or dopesheet depending on which is selected
+ [SerializeReference] private AnimationWindowControl m_ControlInterface;
+ [SerializeReference] private IAnimationWindowController m_OverrideControlInterface;
+
+ [SerializeReference] private AnimationWindowSelectionItem m_EmptySelection;
+ [SerializeReference] private AnimationWindowSelectionItem m_Selection; // Internal selection
+ [SerializeField] private AnimationWindowKeySelection m_KeySelection; // What is selected. Hashes persist cache reload, because they are from keyframe time+value
+
[SerializeField] public bool showCurveEditor; // Do we show dopesheet or curves
[SerializeField] public bool linkedWithSequencer; // Toggle Sequencer selection mode.
[SerializeField] private bool m_RippleTime; // Toggle ripple time option for curve editor and dopesheet.
private bool m_RippleTimeClutch; // Toggle ripple time option for curve editor and dopesheet.
- [SerializeField] private TimeArea m_TimeArea; // Either curveeditor or dopesheet depending on which is selected
- [SerializeField] private AnimationWindowSelectionItem m_EmptySelection;
- [SerializeField] private AnimationWindowSelectionItem m_Selection; // Internal selection
- [SerializeField] private AnimationWindowKeySelection m_KeySelection; // What is selected. Hashes persist cache reload, because they are from keyframe time+value
[SerializeField] private int m_ActiveKeyframeHash; // Which keyframe is active (selected key that user previously interacted with)
[SerializeField] private float m_FrameRate = kDefaultFrameRate;
- [SerializeField] private AnimationWindowControl m_ControlInterface;
- [SerializeField] private IAnimationWindowControl m_OverrideControlInterface;
[SerializeField] private int[] m_SelectionFilter;
[NonSerialized] public Action onStartLiveEdit;
@@ -54,10 +57,13 @@ public enum SnapMode
private static List s_KeyframeClipboard; // For copy-pasting keyframes
- [NonSerialized] public AnimationWindowHierarchyDataSource hierarchyData;
+ private bool m_AllCurvesCacheDirty = true;
+ private bool m_FilteredCurvesCacheDirty = true;
+ private bool m_ActiveCurvesCacheDirty = true;
+ private List m_AllCurvesCache = new ();
+ private List m_FilteredCurvesCache = new ();
+ private List m_ActiveCurvesCache = new ();
- private List m_AllCurvesCache;
- private List m_ActiveCurvesCache;
private List m_dopelinesCache;
private List m_SelectedKeysCache;
private Bounds? m_SelectionBoundsCache;
@@ -99,30 +105,14 @@ public AnimationWindowSelectionItem selection
return m_Selection;
if (m_EmptySelection == null)
- {
m_EmptySelection = AnimationClipSelectionItem.Create(null, null);
- m_EmptySelection.hideFlags = HideFlags.HideAndDontSave;
- }
return m_EmptySelection;
}
set
{
- if (m_Selection != null)
- Object.DestroyImmediate(m_Selection);
-
- // Make a copy and take ownership
- if (value != null)
- {
- m_Selection = Object.Instantiate(value);
- m_Selection.hideFlags = HideFlags.HideAndDontSave;
- }
- else
- {
- m_Selection = null;
- }
-
+ m_Selection = value;
OnSelectionChanged();
}
}
@@ -196,34 +186,20 @@ public bool disabled
}
}
- public IAnimationWindowControl controlInterface
- {
- get
- {
- if (m_OverrideControlInterface != null)
- return m_OverrideControlInterface;
-
- return m_ControlInterface;
- }
- }
+ public IAnimationWindowController controlInterface => m_OverrideControlInterface ?? m_ControlInterface;
- public IAnimationWindowControl overrideControlInterface
+ public IAnimationWindowController overrideControlInterface
{
- get
- {
- return m_OverrideControlInterface;
- }
-
+ get => m_OverrideControlInterface;
set
{
if (m_OverrideControlInterface != null)
- Object.DestroyImmediate(m_OverrideControlInterface);
+ m_OverrideControlInterface.OnDestroy();
m_OverrideControlInterface = value;
}
}
-
public bool filterBySelection
{
get
@@ -293,11 +269,11 @@ private void Refresh()
if (refresh == RefreshType.Everything)
{
- selection.ClearCache();
+ m_AllCurvesCacheDirty = true;
+ m_FilteredCurvesCacheDirty = true;
+ m_ActiveCurvesCacheDirty = true;
m_ActiveKeyframeCache = null;
- m_AllCurvesCache = null;
- m_ActiveCurvesCache = null;
m_dopelinesCache = null;
m_SelectedKeysCache = null;
m_SelectionBoundsCache = null;
@@ -355,45 +331,54 @@ public void ForceRefresh()
private void PurgeSelection()
{
- Object.DestroyImmediate(m_Selection);
+ linkedWithSequencer = false;
+ m_OverrideControlInterface = null;
m_Selection = null;
}
public void OnEnable()
{
- hideFlags = HideFlags.HideAndDontSave;
AnimationUtility.onCurveWasModified += CurveWasModified;
- Undo.undoRedoPerformed += UndoRedoPerformed;
+ Undo.undoRedoEvent += UndoRedoPerformed;
AssemblyReloadEvents.beforeAssemblyReload += PurgeSelection;
// NoOps...
onStartLiveEdit += () => {};
onEndLiveEdit += () => {};
- if (m_ControlInterface == null)
- m_ControlInterface = CreateInstance(typeof(AnimationWindowControl)) as AnimationWindowControl;
- m_ControlInterface.state = this;
+ m_ControlInterface = new AnimationWindowControl
+ {
+ state = this
+ };
m_ControlInterface.OnEnable();
+
+ m_AllCurvesCacheDirty = true;
+ m_FilteredCurvesCacheDirty = true;
+ m_ActiveCurvesCacheDirty = true;
}
public void OnDisable()
{
AnimationUtility.onCurveWasModified -= CurveWasModified;
- Undo.undoRedoPerformed -= UndoRedoPerformed;
+ Undo.undoRedoEvent -= UndoRedoPerformed;
AssemblyReloadEvents.beforeAssemblyReload -= PurgeSelection;
m_ControlInterface.OnDisable();
+ previewing = false;
}
public void OnDestroy()
{
m_ControlInterface.OnDestroy();
+ m_ControlInterface = null;
+
+ if (m_OverrideControlInterface != null)
+ {
+ m_OverrideControlInterface.OnDestroy();
+ m_OverrideControlInterface = null;
+ }
- Object.DestroyImmediate(m_EmptySelection);
- Object.DestroyImmediate(m_Selection);
Object.DestroyImmediate(m_KeySelection);
- Object.DestroyImmediate(m_ControlInterface);
- Object.DestroyImmediate(m_OverrideControlInterface);
}
public void OnSelectionChanged()
@@ -432,10 +417,10 @@ public RefreshType refresh
}
}
- public void UndoRedoPerformed()
+ public void UndoRedoPerformed(in UndoRedoInfo info)
{
refresh = RefreshType.Everything;
- controlInterface.ResampleAnimation();
+ ResampleAnimation();
}
// When curve is modified, we never trigger refresh right away. We order a refresh at later time by setting refresh to appropriate value.
@@ -452,10 +437,10 @@ void CurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationU
bool hadPhantom = false;
int hashCode = binding.GetHashCode();
- List curves = selection.curves;
+ var curves = filteredCurves;
for (int j = 0; j < curves.Count; ++j)
{
- AnimationWindowCurve curve = curves[j];
+ var curve = curves[j];
int curveHash = curve.GetBindingHashCode();
if (curveHash == hashCode)
{
@@ -530,7 +515,7 @@ private void SaveSelectedKeys(string undoLabel)
List toBeDeleted = new List();
// If selected keys are dragged over non-selected keyframe at exact same time, then delete the unselected ones underneath
- foreach (AnimationWindowKeyframe other in snapshot.curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe other in snapshot.curve.keyframes)
{
// Keyframe is in selection, skip.
if (snapshot.selectedKeys.Exists(liveEditKey => liveEditKey.key == other))
@@ -545,7 +530,7 @@ private void SaveSelectedKeys(string undoLabel)
foreach (AnimationWindowKeyframe deletedKey in toBeDeleted)
{
- snapshot.curve.m_Keyframes.Remove(deletedKey);
+ snapshot.curve.RemoveKeyframe(deletedKey);
}
}
@@ -565,53 +550,116 @@ public void RemoveCurve(AnimationWindowCurve curve, string undoLabel)
AnimationUtility.SetEditorCurve(curve.clip, curve.binding, null);
}
- public bool previewing { get { return controlInterface.previewing; } }
-
- public bool canPreview { get { return controlInterface.canPreview; } }
-
- public void StartPreview()
+ public bool previewing
{
- controlInterface.StartPreview();
- controlInterface.ResampleAnimation();
- }
+ get => controlInterface.previewing;
+ set
+ {
+ if (controlInterface.previewing == value)
+ return;
- public void StopPreview()
- {
- controlInterface.StopPreview();
+ if (value)
+ {
+ if (canPreview)
+ controlInterface.previewing = true;
+ }
+ else
+ {
+ // Automatically stop recording and playback when stopping preview.
+ controlInterface.playing = false;
+ controlInterface.recording = false;
+ controlInterface.previewing = false;
+ }
+ }
}
- public bool recording { get { return controlInterface.recording; } }
-
- public bool canRecord { get { return controlInterface.canRecord; } }
+ public bool canPreview => controlInterface.canPreview;
- public void StartRecording()
+ public void UpdateCurvesDisplayName()
{
- controlInterface.StartRecording(selection.sourceObject);
- controlInterface.ResampleAnimation();
+ if (hierarchyData != null)
+ hierarchyData.UpdateSerializeReferenceCurvesArrayNiceDisplayName();
}
- public void StopRecording()
+ public bool recording
{
- controlInterface.StopRecording();
- }
+ get => controlInterface.recording;
+ set
+ {
+ if (controlInterface.recording == value)
+ return;
- public bool playing { get { return controlInterface.playing; } }
+ if (value)
+ {
+ if (canRecord)
+ {
+ // Auto-Preview when starting recording
+ controlInterface.previewing = true;
- public void StartPlayback()
- {
- controlInterface.StartPlayback();
+ if (controlInterface.previewing)
+ controlInterface.recording = true;
+ }
+ }
+ else
+ controlInterface.recording = false;
+ }
}
- public void StopPlayback()
+ public bool canRecord => controlInterface.canRecord;
+
+ public bool playing
{
- controlInterface.StopPlayback();
+ get => controlInterface.playing;
+ set
+ {
+ if (controlInterface.playing == value)
+ return;
+
+ if (value)
+ {
+ if (canPlay)
+ {
+ // Auto-Preview when starting playback.
+ controlInterface.previewing = true;
+
+ if (controlInterface.previewing)
+ controlInterface.playing = true;
+ }
+ }
+ else
+ controlInterface.playing = false;
+ }
}
+ public bool canPlay => controlInterface.canPlay;
+
public void ResampleAnimation()
{
+ if (disabled)
+ return;
+
+ if (controlInterface.previewing == false)
+ return;
+ if (controlInterface.canPreview == false)
+ return;
+
controlInterface.ResampleAnimation();
}
+ public bool PlaybackUpdate()
+ {
+ if (disabled)
+ return false;
+
+ if (!controlInterface.playing)
+ return false;
+
+ return controlInterface.PlaybackUpdate();
+ }
+
+ public void ClearCandidates() => controlInterface.ClearCandidates();
+ public void ProcessCandidates() => controlInterface.ProcessCandidates();
+
public bool ShouldShowCurve(AnimationWindowCurve curve)
{
if (filterBySelection && activeRootGameObject != null)
@@ -639,67 +687,211 @@ private void UpdateSelectionFilter()
m_SelectionFilter = (filterBySelection) ? (int[])Selection.instanceIDs.Clone() : null;
}
- public List allCurves
+ void RebuildAllCurvesCacheIfNecessary()
{
- get
+ if (m_AllCurvesCacheDirty == false && m_AllCurvesCache != null)
+ return;
+
+ if (m_AllCurvesCache == null)
+ m_AllCurvesCache = new List();
+ else
+ m_AllCurvesCache.Clear();
+
+ var animationClip = activeAnimationClip;
+ if (animationClip == null || (!selection.animationIsEditable && !showReadOnly))
+ return;
+
+ EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(animationClip);
+ EditorCurveBinding[] objectCurveBindings = AnimationUtility.GetObjectReferenceCurveBindings(animationClip);
+
+ List transformCurves = new List();
+
+ foreach (EditorCurveBinding curveBinding in curveBindings)
{
- if (m_AllCurvesCache == null)
+ if (AnimationWindowUtility.ShouldShowAnimationWindowCurve(curveBinding))
{
- if (!selection.animationIsEditable && !showReadOnly)
- {
- // Empty list.
- m_AllCurvesCache = new List();
- }
- else if (!filterBySelection || activeRootGameObject == null)
- {
- m_AllCurvesCache = selection.curves;
- }
- else
+ AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, curveBinding, controlInterface.GetValueType(curveBinding));
+ curve.selectionBinding = selection;
+
+ m_AllCurvesCache.Add(curve);
+
+ if (AnimationWindowUtility.IsActualTransformCurve(curveBinding))
{
- List allCurvesUnfiltered = selection.curves;
- m_AllCurvesCache = new List();
- for (int i = 0; i < allCurvesUnfiltered.Count; ++i)
- {
- if (ShouldShowCurve(allCurvesUnfiltered[i]))
- m_AllCurvesCache.Add(allCurvesUnfiltered[i]);
- }
+ transformCurves.Add(curve);
}
}
+ }
- return m_AllCurvesCache;
+ foreach (EditorCurveBinding curveBinding in objectCurveBindings)
+ {
+ AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, curveBinding, controlInterface.GetValueType(curveBinding));
+ curve.selectionBinding = selection;
+
+ m_AllCurvesCache.Add(curve);
+ }
+
+ transformCurves.Sort();
+ if (transformCurves.Count > 0)
+ {
+ FillInMissingTransformCurves(animationClip, transformCurves, ref m_AllCurvesCache);
}
+
+ // Curves need to be sorted with path/type/property name so it's possible to construct hierarchy from them
+ // Sorting logic in AnimationWindowCurve.CompareTo()
+ m_AllCurvesCache.Sort();
+
+ m_AllCurvesCacheDirty = false;
}
- public List activeCurves
+ private void RebuildFilteredCurvesCacheIfNecessary()
{
- get
+ if (m_FilteredCurvesCacheDirty == false && m_FilteredCurvesCache != null)
+ return;
+
+ if (m_FilteredCurvesCache == null)
+ m_FilteredCurvesCache = new List();
+ else
+ m_FilteredCurvesCache.Clear();
+
+ for (int i = 0; i < m_AllCurvesCache.Count; ++i)
+ {
+ if (ShouldShowCurve(m_AllCurvesCache[i]))
+ m_FilteredCurvesCache.Add(m_AllCurvesCache[i]);
+ }
+
+ m_FilteredCurvesCacheDirty = false;
+ }
+
+ private void RebuildActiveCurvesCacheIfNecessary()
+ {
+ if (m_ActiveCurvesCacheDirty == false && m_ActiveCurvesCache != null)
+ return;
+
+ if (m_ActiveCurvesCache == null)
+ m_ActiveCurvesCache = new List();
+ else
+ m_ActiveCurvesCache.Clear();
+
+ if (hierarchyState != null && hierarchyData != null)
{
- if (m_ActiveCurvesCache == null)
+ foreach (int id in hierarchyState.selectedIDs)
{
- m_ActiveCurvesCache = new List();
- if (hierarchyState != null && hierarchyData != null)
- {
- foreach (int id in hierarchyState.selectedIDs)
- {
- TreeViewItem node = hierarchyData.FindItem(id);
- AnimationWindowHierarchyNode hierarchyNode = node as AnimationWindowHierarchyNode;
+ TreeViewItem node = hierarchyData.FindItem(id);
+ AnimationWindowHierarchyNode hierarchyNode = node as AnimationWindowHierarchyNode;
- if (hierarchyNode == null)
- continue;
+ if (hierarchyNode == null)
+ continue;
- AnimationWindowCurve[] curves = hierarchyNode.curves;
- if (curves == null)
- continue;
+ AnimationWindowCurve[] curves = hierarchyNode.curves;
+ if (curves == null)
+ continue;
- foreach (AnimationWindowCurve curve in curves)
- if (!m_ActiveCurvesCache.Contains(curve))
- m_ActiveCurvesCache.Add(curve);
- }
+ foreach (AnimationWindowCurve curve in curves)
+ if (!m_ActiveCurvesCache.Contains(curve))
+ m_ActiveCurvesCache.Add(curve);
+ }
- m_ActiveCurvesCache.Sort();
- }
+ m_ActiveCurvesCache.Sort();
+ }
+
+ m_ActiveCurvesCacheDirty = false;
+ }
+
+ private void FillInMissingTransformCurves(AnimationClip animationClip, List transformCurves, ref List curvesCache)
+ {
+ EditorCurveBinding lastBinding = transformCurves[0].binding;
+ var propertyGroup = new EditorCurveBinding ? [3];
+ string propertyGroupName;
+ foreach (var transformCurve in transformCurves)
+ {
+ var transformBinding = transformCurve.binding;
+ //if it's a new property group
+ if (transformBinding.path != lastBinding.path
+ || AnimationWindowUtility.GetPropertyGroupName(transformBinding.propertyName) != AnimationWindowUtility.GetPropertyGroupName(lastBinding.propertyName))
+ {
+ propertyGroupName = AnimationWindowUtility.GetPropertyGroupName(lastBinding.propertyName);
+
+ FillPropertyGroup(animationClip, ref propertyGroup, lastBinding, propertyGroupName, ref curvesCache);
+
+ lastBinding = transformBinding;
+
+ propertyGroup = new EditorCurveBinding ? [3];
}
+ AssignBindingToRightSlot(transformBinding, ref propertyGroup);
+ }
+ FillPropertyGroup(animationClip, ref propertyGroup, lastBinding, AnimationWindowUtility.GetPropertyGroupName(lastBinding.propertyName), ref curvesCache);
+ }
+
+ private void FillPropertyGroup(AnimationClip animationClip, ref EditorCurveBinding?[] propertyGroup, EditorCurveBinding lastBinding, string propertyGroupName, ref List curvesCache)
+ {
+ var newBinding = lastBinding;
+ newBinding.isPhantom = true;
+ if (!propertyGroup[0].HasValue)
+ {
+ newBinding.propertyName = propertyGroupName + ".x";
+ AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, newBinding, controlInterface.GetValueType(newBinding));
+ curve.selectionBinding = selection;
+ curvesCache.Add(curve);
+ }
+
+ if (!propertyGroup[1].HasValue)
+ {
+ newBinding.propertyName = propertyGroupName + ".y";
+ AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, newBinding, controlInterface.GetValueType(newBinding));
+ curve.selectionBinding = selection;
+ curvesCache.Add(curve);
+ }
+
+ if (!propertyGroup[2].HasValue)
+ {
+ newBinding.propertyName = propertyGroupName + ".z";
+ AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, newBinding, controlInterface.GetValueType(newBinding));
+ curve.selectionBinding = selection;
+ curvesCache.Add(curve);
+ }
+ }
+
+ private void AssignBindingToRightSlot(EditorCurveBinding transformBinding, ref EditorCurveBinding?[] propertyGroup)
+ {
+ if (transformBinding.propertyName.EndsWith(".x"))
+ {
+ propertyGroup[0] = transformBinding;
+ }
+ else if (transformBinding.propertyName.EndsWith(".y"))
+ {
+ propertyGroup[1] = transformBinding;
+ }
+ else if (transformBinding.propertyName.EndsWith(".z"))
+ {
+ propertyGroup[2] = transformBinding;
+ }
+ }
+
+ public List allCurves
+ {
+ get
+ {
+ RebuildAllCurvesCacheIfNecessary();
+ return m_AllCurvesCache;
+ }
+ }
+
+ public List filteredCurves
+ {
+ get
+ {
+ RebuildAllCurvesCacheIfNecessary();
+ RebuildFilteredCurvesCacheIfNecessary();
+ return m_FilteredCurvesCache;
+ }
+ }
+
+ public List activeCurves
+ {
+ get
+ {
+ RebuildActiveCurvesCacheIfNecessary();
return m_ActiveCurvesCache;
}
}
@@ -712,14 +904,14 @@ public CurveWrapper[] activeCurveWrappers
{
List activeCurveWrappers = new List();
foreach (AnimationWindowCurve curve in activeCurves)
- if (!curve.isDiscreteCurve)
- activeCurveWrappers.Add(AnimationWindowUtility.GetCurveWrapper(curve, curve.clip));
+ if (AnimationWindowUtility.GetCurveWrapper(curve, curve.clip) is CurveWrapper wrapper)
+ activeCurveWrappers.Add(wrapper);
// If there are no active curves, we would end up with empty curve editor so we just give all curves insteads
if (!activeCurveWrappers.Any())
- foreach (AnimationWindowCurve curve in allCurves)
- if (!curve.isDiscreteCurve)
- activeCurveWrappers.Add(AnimationWindowUtility.GetCurveWrapper(curve, curve.clip));
+ foreach (AnimationWindowCurve curve in filteredCurves)
+ if (AnimationWindowUtility.GetCurveWrapper(curve, curve.clip) is CurveWrapper wrapper)
+ activeCurveWrappers.Add(wrapper);
m_ActiveCurveWrappersCache = activeCurveWrappers.ToArray();
}
@@ -791,9 +983,9 @@ public AnimationWindowKeyframe activeKeyframe
{
if (m_ActiveKeyframeCache == null)
{
- foreach (AnimationWindowCurve curve in allCurves)
+ foreach (AnimationWindowCurve curve in filteredCurves)
{
- foreach (AnimationWindowKeyframe keyframe in curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe keyframe in curve.keyframes)
{
if (keyframe.GetHash() == m_ActiveKeyframeHash)
m_ActiveKeyframeCache = keyframe;
@@ -816,9 +1008,9 @@ public List selectedKeys
if (m_SelectedKeysCache == null)
{
m_SelectedKeysCache = new List();
- foreach (AnimationWindowCurve curve in allCurves)
+ foreach (AnimationWindowCurve curve in filteredCurves)
{
- foreach (AnimationWindowKeyframe keyframe in curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe keyframe in curve.keyframes)
{
if (KeyIsSelected(keyframe))
{
@@ -842,7 +1034,7 @@ public Bounds selectionBounds
{
AnimationWindowKeyframe key = keys[0];
float time = key.time;
- float val = key.isPPtrCurve ? 0.0f : (float)key.value;
+ float val = key.isPPtrCurve || key.isDiscreteCurve ? 0.0f : (float)key.value;
Bounds bounds = new Bounds(new Vector2(time, val), Vector2.zero);
@@ -851,7 +1043,7 @@ public Bounds selectionBounds
key = keys[i];
time = key.time;
- val = key.isPPtrCurve ? 0.0f : (float)key.value;
+ val = key.isPPtrCurve || key.isDiscreteCurve ? 0.0f : (float)key.value;
bounds.Encapsulate(new Vector2(time, val));
}
@@ -874,7 +1066,7 @@ private HashSet selectedKeyHashes
{
if (m_KeySelection == null)
{
- m_KeySelection = CreateInstance();
+ m_KeySelection = ScriptableObject.CreateInstance();
m_KeySelection.hideFlags = HideFlags.HideAndDontSave;
}
@@ -884,7 +1076,7 @@ private HashSet selectedKeyHashes
{
if (m_KeySelection == null)
{
- m_KeySelection = CreateInstance();
+ m_KeySelection = ScriptableObject.CreateInstance();
m_KeySelection.hideFlags = HideFlags.HideAndDontSave;
}
@@ -948,7 +1140,7 @@ public void DeleteKeys(List keys)
curves.Add(keyframe.curve);
UnselectKey(keyframe);
- keyframe.curve.m_Keyframes.Remove(keyframe);
+ keyframe.curve.RemoveKeyframe(keyframe);
}
SaveCurves(activeAnimationClip, curves, kEditCurveUndoLabel);
@@ -971,7 +1163,7 @@ public void StartLiveEdit()
{
LiveEditCurve snapshot = new LiveEditCurve();
snapshot.curve = selectedKey.curve;
- foreach (AnimationWindowKeyframe key in selectedKey.curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe key in selectedKey.curve.keyframes)
{
LiveEditKeyframe liveEditKey = new LiveEditKeyframe();
liveEditKey.keySnapshot = new AnimationWindowKeyframe(key);
@@ -1048,7 +1240,7 @@ public void TransformSelectedKeys(Matrix4x4 matrix, bool flipX, bool flipY, bool
if (snapshot.curve.animationIsEditable)
{
// Transform time value.
- Vector3 v = new Vector3(liveEditKey.keySnapshot.time, liveEditKey.keySnapshot.isPPtrCurve ? 0f : (float)liveEditKey.keySnapshot.value, 0f);
+ Vector3 v = new Vector3(liveEditKey.keySnapshot.time, liveEditKey.keySnapshot.isPPtrCurve || liveEditKey.keySnapshot.isDiscreteCurve ? 0f : (float)liveEditKey.keySnapshot.value, 0f);
v = matrix.MultiplyPoint3x4(v);
liveEditKey.key.time = Mathf.Max((snapToFrame) ? SnapToFrame(v.x, snapshot.curve.clip.frameRate) : v.x, 0f);
@@ -1069,7 +1261,7 @@ public void TransformSelectedKeys(Matrix4x4 matrix, bool flipX, bool flipY, bool
liveEditKey.key.outWeight = liveEditKey.keySnapshot.inWeight;
}
- if (!liveEditKey.key.isPPtrCurve)
+ if (!liveEditKey.key.isPPtrCurve && !liveEditKey.key.isDiscreteCurve)
{
liveEditKey.key.value = v.y;
@@ -1163,6 +1355,16 @@ public void TransformRippleKeys(Matrix4x4 matrix, float t1, float t2, bool flipX
EndLiveEdit();
}
+ internal static bool CanPasteKeys()
+ {
+ return s_KeyframeClipboard != null && s_KeyframeClipboard.Count > 0;
+ }
+
+ internal static void ClearKeyframeClipboard()
+ {
+ s_KeyframeClipboard?.Clear();
+ }
+
public void CopyKeys()
{
if (s_KeyframeClipboard == null)
@@ -1187,13 +1389,19 @@ public void CopyKeys()
{
CopyAllActiveCurves();
}
+
+ // Animation keyframes right now do not go through regular clipboard machinery,
+ // so when copying keyframes, make sure regular clipboard is cleared, or things
+ // get confusing.
+ if (s_KeyframeClipboard.Count > 0)
+ Clipboard.stringValue = string.Empty;
}
public void CopyAllActiveCurves()
{
foreach (AnimationWindowCurve curve in activeCurves)
{
- foreach (AnimationWindowKeyframe keyframe in curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe keyframe in curve.keyframes)
{
s_KeyframeClipboard.Add(new AnimationWindowKeyframe(keyframe));
}
@@ -1269,14 +1477,16 @@ public void PasteKeys()
// Only allow pasting of key frame from numerical curves to numerical curves or from pptr curves to pptr curves.
if ((newKeyframe.time >= 0.0f) && (newKeyframe.curve != null) && (newKeyframe.curve.isPPtrCurve == keyframe.curve.isPPtrCurve))
{
- if (newKeyframe.curve.HasKeyframe(AnimationKeyTime.Time(newKeyframe.time, newKeyframe.curve.clip.frameRate)))
- newKeyframe.curve.RemoveKeyframe(AnimationKeyTime.Time(newKeyframe.time, newKeyframe.curve.clip.frameRate));
+ var keyTime = AnimationKeyTime.Time(newKeyframe.time, newKeyframe.curve.clip.frameRate);
+
+ if (newKeyframe.curve.HasKeyframe(keyTime))
+ newKeyframe.curve.RemoveKeyframe(keyTime);
// When copy-pasting multiple keyframes (curve), its a continous thing. This is why we delete the existing keyframes in the pasted range.
if (lastTargetCurve == newKeyframe.curve)
newKeyframe.curve.RemoveKeysAtRange(lastTime, newKeyframe.time);
- newKeyframe.curve.m_Keyframes.Add(newKeyframe);
+ newKeyframe.curve.AddKeyframe(newKeyframe, keyTime);
SelectKey(newKeyframe);
// TODO: Optimize to only save curve once instead once per keyframe
SaveCurve(newKeyframe.curve.clip, newKeyframe.curve, kEditCurveUndoLabel);
@@ -1362,7 +1572,7 @@ private void ReloadModifiedCurveWrapperCache()
if (m_ModifiedCurves.Contains(curveWrapper.id))
{
- AnimationWindowCurve curve = allCurves.Find(c => c.GetHashCode() == curveWrapper.id);
+ AnimationWindowCurve curve = filteredCurves.Find(c => c.GetHashCode() == curveWrapper.id);
if (curve != null)
{
// Boundaries have changed, invalidate all curves
@@ -1396,9 +1606,9 @@ private void ReloadModifiedCurveWrapperCache()
private void ReloadModifiedAnimationCurveCache()
{
- for (int i = 0; i < allCurves.Count; ++i)
+ for (int i = 0; i < filteredCurves.Count; ++i)
{
- AnimationWindowCurve curve = allCurves[i];
+ AnimationWindowCurve curve = filteredCurves[i];
if (m_ModifiedCurves.Contains(curve.GetHashCode()))
curve.LoadKeyframes(curve.clip);
}
@@ -1436,7 +1646,7 @@ private void OnNewCurveAdded(EditorCurveBinding newCurve)
}
// Values do not change whenever a new curve is added, so we force an inspector update here.
- controlInterface.ResampleAnimation();
+ ResampleAnimation();
m_lastAddedCurveBinding = null;
}
@@ -1629,16 +1839,16 @@ public float clipFrameRate
SaveKeySelection(kEditCurveUndoLabel);
// Reposition all keyframes to match the new sampling rate
- foreach (var curve in selection.curves)
+ foreach (var curve in allCurves)
{
- foreach (var key in curve.m_Keyframes)
+ foreach (var key in curve.keyframes)
{
int frame = AnimationKeyTime.Time(key.time, clipFrameRate).frame;
key.time = AnimationKeyTime.Frame(frame, value).time;
}
}
- SaveCurves(activeAnimationClip, selection.curves, kEditCurveUndoLabel);
+ SaveCurves(activeAnimationClip, allCurves, kEditCurveUndoLabel);
AnimationEvent[] events = AnimationUtility.GetAnimationEvents(activeAnimationClip);
foreach (AnimationEvent ev in events)
@@ -1670,9 +1880,19 @@ public float frameRate
}
}
- public AnimationKeyTime time { get { return controlInterface.time; } }
- public int currentFrame { get { return time.frame; } set { controlInterface.GoToFrame(value); } }
- public float currentTime { get { return time.time; } set { controlInterface.GoToTime(value); } }
+ public AnimationKeyTime time => AnimationKeyTime.Time(controlInterface.time, frameRate);
+
+ public int currentFrame
+ {
+ get => controlInterface.frame;
+ set => controlInterface.frame = value;
+ }
+
+ public float currentTime
+ {
+ get => controlInterface.time;
+ set => controlInterface.time = value;
+ }
public TimeArea.TimeFormat timeFormat { get { return AnimationWindowOptions.timeFormat; } set { AnimationWindowOptions.timeFormat = value; } }
@@ -1802,5 +2022,44 @@ public float PixelDeltaToTime(Rect rect)
{
return visibleTimeSpan / rect.width;
}
+
+ public void GoToPreviousFrame()
+ {
+ controlInterface.frame -= 1;
+ }
+
+ public void GoToNextFrame()
+ {
+ controlInterface.frame += 1;
+ }
+
+ public void GoToPreviousKeyframe()
+ {
+ List curves = (showCurveEditor && activeCurves.Count > 0) ? activeCurves : filteredCurves;
+
+ float newTime = AnimationWindowUtility.GetPreviousKeyframeTime(curves.ToArray(), controlInterface.time, clipFrameRate);
+ controlInterface.time = SnapToFrame(newTime, SnapMode.SnapToFrame);
+ }
+
+ public void GoToNextKeyframe()
+ {
+ List curves = (showCurveEditor && activeCurves.Count > 0) ? activeCurves : filteredCurves;
+
+ float newTime = AnimationWindowUtility.GetNextKeyframeTime(curves.ToArray(), controlInterface.time, clipFrameRate);
+ controlInterface.time = SnapToFrame(newTime, AnimationWindowState.SnapMode.SnapToFrame);
+ }
+
+ public void GoToFirstKeyframe()
+ {
+ if (activeAnimationClip)
+ controlInterface.time = activeAnimationClip.startTime;
+ }
+
+ public void GoToLastKeyframe()
+ {
+ if (activeAnimationClip)
+ controlInterface.time = activeAnimationClip.stopTime;
+ }
+
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/AnimationWindowUtility.cs b/Editor/Mono/Animation/AnimationWindow/AnimationWindowUtility.cs
index 92d731e609..df9a25a1a8 100644
--- a/Editor/Mono/Animation/AnimationWindow/AnimationWindowUtility.cs
+++ b/Editor/Mono/Animation/AnimationWindow/AnimationWindowUtility.cs
@@ -16,7 +16,7 @@
namespace UnityEditorInternal
{
- static internal class AnimationWindowUtility
+ static class AnimationWindowUtility
{
public static void SaveCurve(AnimationClip clip, AnimationWindowCurve curve)
{
@@ -111,11 +111,11 @@ public static void CreateDefaultCurves(AnimationWindowState state, AnimationClip
public static AnimationWindowCurve CreateDefaultCurve(AnimationWindowState state, AnimationClip animationClip, EditorCurveBinding binding)
{
- Type type = state.selection.GetEditorCurveValueType(binding);
+ Type type = state.controlInterface.GetValueType(binding);
AnimationWindowCurve curve = new AnimationWindowCurve(animationClip, binding, type);
- object currentValue = CurveBindingUtility.GetCurrentValue(state.activeRootGameObject, binding);
+ object currentValue = CurveBindingUtility.GetCurrentValue(state, binding);
if (animationClip.length == 0.0F)
{
AddKeyframeToCurve(curve, currentValue, type, AnimationKeyTime.Time(0.0F, animationClip.frameRate));
@@ -138,7 +138,7 @@ public static bool ShouldShowAnimationWindowCurve(EditorCurveBinding curveBindin
return true;
}
- public static bool IsNodeLeftOverCurve(AnimationWindowHierarchyNode node)
+ public static bool IsNodeLeftOverCurve(AnimationWindowState state, AnimationWindowHierarchyNode node)
{
if (node.binding != null)
{
@@ -150,7 +150,7 @@ public static bool IsNodeLeftOverCurve(AnimationWindowHierarchyNode node)
if (selectionBinding.rootGameObject == null && selectionBinding.scriptableObject == null)
return false;
- return selectionBinding.GetEditorCurveValueType((EditorCurveBinding)node.binding) == null;
+ return state.controlInterface.GetValueType((EditorCurveBinding)node.binding) == null;
}
}
}
@@ -159,7 +159,7 @@ public static bool IsNodeLeftOverCurve(AnimationWindowHierarchyNode node)
if (node.hasChildren)
{
foreach (var child in node.children)
- return IsNodeLeftOverCurve(child as AnimationWindowHierarchyNode);
+ return IsNodeLeftOverCurve(state, child as AnimationWindowHierarchyNode);
}
return false;
@@ -200,13 +200,13 @@ public static bool IsNodePhantom(AnimationWindowHierarchyNode node)
public static void AddSelectedKeyframes(AnimationWindowState state, AnimationKeyTime time)
{
- List curves = state.activeCurves.Count > 0 ? state.activeCurves : state.allCurves;
+ List curves = state.activeCurves.Count > 0 ? state.activeCurves : state.filteredCurves;
AddKeyframes(state, curves, time);
}
public static void AddKeyframes(AnimationWindowState state, IList curves, AnimationKeyTime time)
{
- string undoLabel = "Add Key";
+ string undoLabel = L10n.Tr("Add Key");
state.SaveKeySelection(undoLabel);
state.ClearKeySelections();
@@ -230,7 +230,7 @@ public static void AddKeyframes(AnimationWindowState state, IList curves, AnimationKeyTime time)
{
- string undoLabel = "Remove Key";
+ string undoLabel = L10n.Tr("Remove Key");
state.SaveKeySelection(undoLabel);
foreach (AnimationWindowCurve curve in curves)
@@ -266,9 +266,21 @@ public static AnimationWindowKeyframe AddKeyframeToCurve(AnimationWindowCurve cu
keyframe.curve = curve;
curve.AddKeyframe(keyframe, time);
}
+ else if (curve.isDiscreteCurve)
+ {
+ Keyframe tempKey = new Keyframe(time.time, 0f);
+ AnimationUtility.SetKeyLeftTangentMode(ref tempKey, TangentMode.Constant);
+ AnimationUtility.SetKeyRightTangentMode(ref tempKey, TangentMode.Constant);
+ AnimationUtility.SetKeyBroken(ref tempKey, true);
+
+ keyframe = new AnimationWindowKeyframe(curve, tempKey);
+ keyframe.value = Convert.ToInt32(value);
+
+ curve.AddKeyframe(keyframe, time);
+ }
else if (type == typeof(bool) || type == typeof(float) || type == typeof(int))
{
- Keyframe tempKey = new Keyframe(time.time, (float)value);
+ Keyframe tempKey = new Keyframe(time.time, Convert.ToSingle(value));
if (type == typeof(bool))
{
AnimationUtility.SetKeyLeftTangentMode(ref tempKey, TangentMode.Constant);
@@ -280,9 +292,10 @@ public static AnimationWindowKeyframe AddKeyframeToCurve(AnimationWindowCurve cu
{
// Create temporary curve to get proper tangents
AnimationCurve animationCurve = curve.ToAnimationCurve();
+
if (animationCurve.length <= 1)
{
- TangentMode tangentMode = curve.isDiscreteCurve ? TangentMode.Constant : TangentMode.Linear;
+ TangentMode tangentMode = TangentMode.Linear;
AnimationUtility.SetKeyLeftTangentMode(ref tempKey, tangentMode);
AnimationUtility.SetKeyRightTangentMode(ref tempKey, tangentMode);
}
@@ -457,52 +470,40 @@ public static object GetCurrentValue(GameObject rootGameObject, EditorCurveBindi
{
if (curveBinding.isPPtrCurve)
{
- Object value;
- AnimationUtility.GetObjectReferenceValue(rootGameObject, curveBinding, out value);
+ AnimationUtility.GetObjectReferenceValue(rootGameObject, curveBinding, out var value);
+ return value;
+ }
+ else if (curveBinding.isDiscreteCurve)
+ {
+ AnimationUtility.GetDiscreteIntValue(rootGameObject, curveBinding, out var value);
return value;
}
else
{
- float value;
- AnimationUtility.GetFloatValue(rootGameObject, curveBinding, out value);
+ AnimationUtility.GetFloatValue(rootGameObject, curveBinding, out var value);
return value;
}
}
- public static List GetAnimatableProperties(GameObject gameObject, GameObject root, Type valueType)
- {
- EditorCurveBinding[] animatable = AnimationUtility.GetAnimatableBindings(gameObject, root);
-
- List result = new List();
- foreach (EditorCurveBinding binding in animatable)
- if (AnimationUtility.GetEditorCurveValueType(root, binding) == valueType)
- result.Add(binding);
-
- return result;
- }
-
- public static List GetAnimatableProperties(GameObject gameObject, GameObject root, Type objectType, Type valueType)
+ public static EditorCurveBinding[] GetAnimatableBindings(GameObject rootGameObject)
{
- EditorCurveBinding[] animatable = AnimationUtility.GetAnimatableBindings(gameObject, root);
-
- List result = new List();
- foreach (EditorCurveBinding binding in animatable)
- if (binding.type == objectType && AnimationUtility.GetEditorCurveValueType(root, binding) == valueType)
- result.Add(binding);
+ if (rootGameObject != null)
+ {
+ var transforms = rootGameObject.GetComponentsInChildren();
- return result;
- }
+ // At least 10 bindings for Transform (m_LocalPosition, m_LocalRotation, m_LocalScale) and 1 binding for GameObject (m_IsActive)
+ const int kMinNumberOfBindingsPerGameObject = 11;
- public static List GetAnimatableProperties(ScriptableObject scriptableObject, Type valueType)
- {
- EditorCurveBinding[] animatable = AnimationUtility.GetAnimatableBindings(scriptableObject);
+ var bindings = new List(transforms.Length * kMinNumberOfBindingsPerGameObject);
+ for (int i = 0; i < transforms.Length; ++i)
+ {
+ bindings.AddRange(AnimationUtility.GetAnimatableBindings(transforms[i].gameObject, rootGameObject));
+ }
- List result = new List();
- foreach (EditorCurveBinding binding in animatable)
- if (AnimationUtility.GetEditorCurveValueType(scriptableObject, binding) == valueType)
- result.Add(binding);
+ return bindings.ToArray();
+ }
- return result;
+ return Array.Empty();
}
public static bool PropertyIsAnimatable(Object targetObject, string propertyPath, Object rootObject)
@@ -614,7 +615,7 @@ public static PropertyModification[] SerializedPropertyToPropertyModifications(S
var modification = new PropertyModification();
modification.target = targetObjects[j];
- modification.propertyPath = singleProperty.propertyPath;
+ modification.propertyPath = (singleProperty.isReferencingAManagedReferenceField ? singleProperty.managedReferencePropertyPath : singleProperty.propertyPath);
modification.value = value;
modification.objectReference = objectReference;
modifications.Add(modification);
@@ -632,6 +633,8 @@ public static PropertyModification[] SerializedPropertyToPropertyModifications(S
value = propertyIter.floatValue.ToString(CultureInfo.InvariantCulture);
else if (isInt)
value = propertyIter.intValue.ToString();
+ else if (isEnum)
+ value = propertyIter.enumValueIndex.ToString();
else // if (isBool)
value = propertyIter.boolValue ? "1" : "0";
@@ -640,7 +643,7 @@ public static PropertyModification[] SerializedPropertyToPropertyModifications(S
var modification = new PropertyModification();
modification.target = targetObjects[j];
- modification.propertyPath = propertyIter.propertyPath;
+ modification.propertyPath = (propertyIter.isReferencingAManagedReferenceField ? propertyIter.managedReferencePropertyPath : propertyIter.propertyPath);
modification.value = value;
modification.objectReference = objectReference;
modifications.Add(modification);
@@ -729,16 +732,23 @@ public static void RenameCurvePath(AnimationWindowCurve curve, EditorCurveBindin
}
}
+ private static readonly string k_PositionDisplayName = L10n.Tr("Position");
+ private static readonly string k_ScaleDisplayName = L10n.Tr("Scale");
+ private static readonly string k_RotationDisplayName = L10n.Tr("Rotation");
+ private static readonly string k_MaterialReferenceDisplayName = L10n.Tr("Material Reference");
+
// Takes raw animation curve propertyname and makes it pretty
public static string GetPropertyDisplayName(string propertyName)
{
- propertyName = propertyName.Replace("m_LocalPosition", "Position");
- propertyName = propertyName.Replace("m_LocalScale", "Scale");
- propertyName = propertyName.Replace("m_LocalRotation", "Rotation");
- propertyName = propertyName.Replace("localEulerAnglesBaked", "Rotation");
- propertyName = propertyName.Replace("localEulerAnglesRaw", "Rotation");
- propertyName = propertyName.Replace("localEulerAngles", "Rotation");
- propertyName = propertyName.Replace("m_Materials.Array.data", "Material Reference");
+ propertyName = propertyName.Replace("m_LocalPosition", k_PositionDisplayName);
+ propertyName = propertyName.Replace("m_LocalScale", k_ScaleDisplayName);
+ propertyName = propertyName.Replace("m_LocalRotation", k_RotationDisplayName);
+ propertyName = propertyName.Replace("localEulerAnglesBaked", k_RotationDisplayName);
+ propertyName = propertyName.Replace("localEulerAnglesRaw", k_RotationDisplayName);
+ propertyName = propertyName.Replace("localEulerAngles", k_RotationDisplayName);
+ propertyName = propertyName.Replace("m_Materials.Array.data", k_MaterialReferenceDisplayName);
+ if (propertyName.StartsWith("managedReferences["))
+ propertyName = propertyName.Remove(0, propertyName.IndexOf('.')+1);
propertyName = ObjectNames.NicifyVariableName(propertyName);
propertyName = propertyName.Replace("m_", "");
@@ -758,6 +768,29 @@ public static bool ShouldPrefixWithTypeName(Type animatableObjectType, string pr
return true;
}
+ public static string GetNicePropertyDisplayName(EditorCurveBinding curveBinding, SerializedObject so)
+ {
+ if (curveBinding.isSerializeReferenceCurve)
+ {
+ if (so != null)
+ {
+ var displayName = curveBinding.propertyName;
+ var sp = so.FindFirstPropertyFromManagedReferencePath(displayName);
+ if (sp != null)
+ displayName = AnimationWindowUtility.GetPropertyDisplayName(AnimationWindowUtility.GetPropertyGroupName(sp.propertyPath));
+ if (displayName != "")
+ return displayName;
+ }
+ else
+ {
+ return ObjectNames.NicifyVariableName(curveBinding.type.Name) + "." + curveBinding.propertyName;
+ }
+
+ }
+
+ return AnimationWindowUtility.GetNicePropertyDisplayName(curveBinding.type, AnimationWindowUtility.GetPropertyGroupName(curveBinding.propertyName));
+ }
+
public static string GetNicePropertyDisplayName(Type animatableObjectType, string propertyName)
{
if (ShouldPrefixWithTypeName(animatableObjectType, propertyName))
@@ -766,6 +799,28 @@ public static string GetNicePropertyDisplayName(Type animatableObjectType, strin
return GetPropertyDisplayName(propertyName);
}
+ public static string GetNicePropertyGroupDisplayName(EditorCurveBinding curveBinding, SerializedObject so)
+ {
+ if (curveBinding.isSerializeReferenceCurve )
+ {
+ if (so != null)
+ {
+ var displayName = curveBinding.propertyName;
+ var sp = so.FindFirstPropertyFromManagedReferencePath(displayName);
+ if (sp != null)
+ displayName = AnimationWindowUtility.GetPropertyDisplayName(AnimationWindowUtility.GetPropertyGroupName(sp.propertyPath));
+ if (displayName != "")
+ return displayName;
+ }
+ else
+ {
+ return ObjectNames.NicifyVariableName(curveBinding.type.Name) + "." + curveBinding.propertyName;
+ }
+ }
+
+ return NicifyPropertyGroupName(curveBinding.type, AnimationWindowUtility.GetPropertyGroupName(curveBinding.propertyName));
+ }
+
public static string GetNicePropertyGroupDisplayName(Type animatableObjectType, string propertyGroupName)
{
if (ShouldPrefixWithTypeName(animatableObjectType, propertyGroupName))
@@ -780,7 +835,7 @@ public static string NicifyPropertyGroupName(Type animatableObjectType, string p
string result = GetPropertyGroupName(GetPropertyDisplayName(propertyGroupName));
// Workaround for uGUI RectTransform which only animates position.z
- if (animatableObjectType == typeof(RectTransform) & result.Equals("Position"))
+ if (animatableObjectType == typeof(RectTransform) && result.Equals("Position"))
result = "Position (Z)";
return result;
@@ -833,7 +888,7 @@ public static float GetNextKeyframeTime(AnimationWindowCurve[] curves, float cur
foreach (AnimationWindowCurve curve in curves)
{
- foreach (AnimationWindowKeyframe keyframe in curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe keyframe in curve.keyframes)
{
AnimationKeyTime keyTime = AnimationKeyTime.Time(keyframe.time, frameRate);
if (keyTime.frame <= candidateKeyTime.frame && keyTime.frame >= nextTime.frame)
@@ -859,7 +914,7 @@ public static float GetPreviousKeyframeTime(AnimationWindowCurve[] curves, float
foreach (AnimationWindowCurve curve in curves)
{
- foreach (AnimationWindowKeyframe keyframe in curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe keyframe in curve.keyframes)
{
AnimationKeyTime keyTime = AnimationKeyTime.Time(keyframe.time, frameRate);
if (keyTime.frame >= candidateKeyTime.frame && keyTime.frame <= previousTime.frame)
@@ -888,6 +943,7 @@ public static bool InitializeGameobjectForAnimation(GameObject animatedObject)
return false;
animationPlayer = EnsureActiveAnimationPlayer(animatedObject);
+ Undo.RecordObject(animationPlayer, "Add animation clip");
bool success = AddClipToAnimationPlayerComponent(animationPlayer, newClip);
if (!success)
@@ -947,6 +1003,8 @@ public static bool AddClipToAnimatorComponent(Animator animator, AnimationClip n
if (controller == null)
{
controller = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerForClip(newClip, animator.gameObject);
+
+ Undo.RecordObject(animator, "Set Controller");
UnityEditor.Animations.AnimatorController.SetAnimatorController(animator, controller);
if (controller != null)
@@ -984,7 +1042,7 @@ public static bool AddClipToAnimationComponent(Animation animation, AnimationCli
internal static AnimationClip CreateNewClip(string gameObjectName)
{
// Go forward with presenting user a save clip dialog
- string message = string.Format("Create a new animation for the game object '{0}':", gameObjectName);
+ string message = string.Format(L10n.Tr("Create a new animation for the game object '{0}':"), gameObjectName);
string newClipDirectory = ProjectWindowUtil.GetActiveFolderPath();
if (s_LastPathUsedForNewClip != null)
{
@@ -994,7 +1052,7 @@ internal static AnimationClip CreateNewClip(string gameObjectName)
newClipDirectory = directoryPath;
}
}
- string newClipPath = EditorUtility.SaveFilePanelInProject("Create New Animation", "New Animation", "anim", message, newClipDirectory);
+ string newClipPath = EditorUtility.SaveFilePanelInProject(L10n.Tr("Create New Animation"), "New Animation", "anim", message, newClipDirectory);
// If user canceled or save path is invalid, we can't create a clip
if (newClipPath == "")
@@ -1020,6 +1078,7 @@ internal static AnimationClip CreateNewClipAtPath(string clipPath)
if (asset)
{
+ newClip.name = asset.name;
EditorUtility.CopySerialized(newClip, asset);
AssetDatabase.SaveAssets();
Object.DestroyImmediate(newClip);
@@ -1060,13 +1119,23 @@ public static Component GetClosestAnimationPlayerComponentInParents(Transform tr
{
while (true)
{
- var animator = tr.GetComponent();
- if (animator != null)
+ if (tr.TryGetComponent(out Animator animator))
+ {
return animator;
+ }
- var animation = tr.GetComponent();
- if (animation != null)
+ if (tr.TryGetComponent(out Animation animation))
+ {
return animation;
+ }
+
+ if (tr.TryGetComponent(out IAnimationClipSource clipPlayer))
+ {
+ if (clipPlayer is Component clipPlayerComponent)
+ {
+ return clipPlayerComponent;
+ }
+ }
if (tr == tr.root)
break;
@@ -1081,7 +1150,10 @@ public static Animator GetClosestAnimatorInParents(Transform tr)
{
while (true)
{
- if (tr.GetComponent() != null) return tr.GetComponent();
+ if (tr.TryGetComponent(out Animator animator))
+ {
+ return animator;
+ }
if (tr == tr.root) break;
tr = tr.parent;
}
@@ -1093,7 +1165,10 @@ public static Animation GetClosestAnimationInParents(Transform tr)
{
while (true)
{
- if (tr.GetComponent() != null) return tr.GetComponent();
+ if (tr.TryGetComponent(out Animation animation))
+ {
+ return animation;
+ }
if (tr == tr.root) break;
tr = tr.parent;
}
@@ -1204,6 +1279,10 @@ private static CurveWrapper.PreProcessKeyMovement CreateKeyPreprocessorForCurve(
public static CurveWrapper GetCurveWrapper(AnimationWindowCurve curve, AnimationClip clip)
{
+ //Discrete and PPtr curves are not allowed to create curve wrappers.
+ if (curve.isDiscreteCurve || curve.isPPtrCurve)
+ return null;
+
CurveWrapper curveWrapper = new CurveWrapper();
curveWrapper.renderer = CreateRendererForCurve(curve);
curveWrapper.preProcessKeyMovementDelegate = CreateKeyPreprocessorForCurve(curve);
@@ -1224,8 +1303,8 @@ public static AnimationWindowKeyframe CurveSelectionToAnimationWindowKeyframe(Cu
{
int curveID = curve.GetHashCode();
if (curveID == curveSelection.curveID)
- if (curve.m_Keyframes.Count > curveSelection.key)
- return curve.m_Keyframes[curveSelection.key];
+ if (curve.keyframes.Count > curveSelection.key)
+ return curve.keyframes[curveSelection.key];
}
return null;
@@ -1309,7 +1388,7 @@ public static bool ForceGrouping(EditorCurveBinding binding)
if (typeof(Renderer).IsAssignableFrom(binding.type))
{
string group = GetPropertyGroupName(binding.propertyName);
- return group == "material._Color";
+ return group == "material._Color" || group == "material._BaseColor";
}
return false;
}
diff --git a/Editor/Mono/Animation/AnimationWindow/ControlPointRenderer.cs b/Editor/Mono/Animation/AnimationWindow/ControlPointRenderer.cs
index 8ea9b1fb61..63c6a6d689 100644
--- a/Editor/Mono/Animation/AnimationWindow/ControlPointRenderer.cs
+++ b/Editor/Mono/Animation/AnimationWindow/ControlPointRenderer.cs
@@ -97,11 +97,11 @@ public void Render()
if (renderChunk.isDirty)
{
- renderChunk.mesh.vertices = renderChunk.vertices.ToArray();
- renderChunk.mesh.colors32 = renderChunk.colors.ToArray();
- renderChunk.mesh.uv = renderChunk.uvs.ToArray();
+ renderChunk.mesh.SetVertices(renderChunk.vertices);
+ renderChunk.mesh.SetColors(renderChunk.colors);
+ renderChunk.mesh.SetUVs(0, renderChunk.uvs);
- renderChunk.mesh.SetIndices(renderChunk.indices.ToArray(), MeshTopology.Triangles, 0);
+ renderChunk.mesh.SetIndices(renderChunk.indices, MeshTopology.Triangles, 0);
renderChunk.isDirty = false;
}
diff --git a/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs b/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs
index 21ee380a73..6678280c1d 100644
--- a/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs
+++ b/Editor/Mono/Animation/AnimationWindow/CurveBindingUtility.cs
@@ -9,13 +9,32 @@ namespace UnityEditorInternal
{
static internal class CurveBindingUtility
{
+ // Current value of the property that rootGO + curveBinding is pointing to
+ public static object GetCurrentValue(AnimationWindowState state, EditorCurveBinding binding)
+ {
+ if (binding.isPPtrCurve)
+ {
+ return state.controlInterface.GetObjectReferenceValue(binding);
+ }
+ else if (binding.isDiscreteCurve)
+ {
+ return state.controlInterface.GetIntValue(binding);
+ }
+
+ return state.controlInterface.GetFloatValue(binding);
+ }
+
+
// Retrieve current value. If bindings are available and value is animated, use bindings to get value.
// Otherwise, evaluate AnimationWindowCurve at current time.
public static object GetCurrentValue(AnimationWindowState state, AnimationWindowCurve curve)
{
- if (state.previewing && curve.rootGameObject != null)
+ // UUM-66112 - state.linkedWithSequencer - Padding for issue in Timeline where muscle
+ // values are not updated in the editor when previewing in the Animation Window.
+ // Fallback to curve values.
+ if (state.previewing && curve.rootGameObject != null && !state.linkedWithSequencer)
{
- return AnimationWindowUtility.GetCurrentValue(curve.rootGameObject, curve.binding);
+ return GetCurrentValue(state, curve.binding);
}
else
{
@@ -37,6 +56,10 @@ public static object GetCurrentValue(GameObject rootGameObject, EditorCurveBindi
// Cannot extract type of PPtrCurve.
return null;
}
+ else if (curveBinding.isDiscreteCurve)
+ {
+ return 0;
+ }
else
{
// Cannot extract type of AnimationCurve. Default to float.
diff --git a/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs b/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs
index 7f082fe984..650bd7ee7e 100644
--- a/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs
+++ b/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs
@@ -217,6 +217,12 @@ internal class CurveEditor : TimeArea, CurveUpdater
CurveWrapper[] m_AnimationCurves;
static int s_SelectKeyHash = "SelectKeys".GetHashCode();
+ private static readonly string k_DeleteKeys = L10n.Tr("Delete Keys");
+ private static readonly string k_DeleteKey = L10n.Tr("Delete Key");
+ private static readonly string k_EditKeys = L10n.Tr("Edit Keys...");
+ private static readonly string k_EditKey = L10n.Tr("Edit Key...");
+ private static readonly string k_EditCurve = L10n.Tr("Edit Curve");
+ private static readonly string k_AddKey = L10n.Tr("Add Key");
public delegate void CallbackFunction();
@@ -646,13 +652,13 @@ public CurveEditor(Rect rect, CurveWrapper[] curves, bool minimalGUI) : base(min
public void OnEnable()
{
// Only add callback once.
- Undo.undoRedoPerformed -= UndoRedoPerformed;
- Undo.undoRedoPerformed += UndoRedoPerformed;
+ Undo.undoRedoEvent -= UndoRedoPerformed;
+ Undo.undoRedoEvent += UndoRedoPerformed;
}
public void OnDisable()
{
- Undo.undoRedoPerformed -= UndoRedoPerformed;
+ Undo.undoRedoEvent -= UndoRedoPerformed;
if (m_PointRenderer != null)
m_PointRenderer.FlushCache();
@@ -666,7 +672,7 @@ public void OnDestroy()
ScriptableObject.DestroyImmediate(m_Selection);
}
- void UndoRedoPerformed()
+ void UndoRedoPerformed(in UndoRedoInfo info)
{
if (settings.undoRedoSelection)
InvalidateSelectionBounds();
@@ -1105,8 +1111,8 @@ public void CurveGUI()
m_MenuManager = new CurveMenuManager(this);
GenericMenu menu = new GenericMenu();
- string deleteKeyLabel = keyList.Count > 1 ? "Delete Keys" : "Delete Key";
- string editKeyLabel = keyList.Count > 1 ? "Edit Keys..." : "Edit Key...";
+ string deleteKeyLabel = keyList.Count > 1 ? k_DeleteKeys : k_DeleteKey;
+ string editKeyLabel = keyList.Count > 1 ? k_EditKeys : k_EditKey;
if (isEditable)
{
@@ -1158,7 +1164,7 @@ public void CurveGUI()
DrawCurvesTangents();
DrawCurvesOverlay();
- m_RectangleTool.OverlayOnGUI();
+ m_RectangleTool.OverlayOnGUI(rect);
EditSelectedPoints();
}
@@ -1290,7 +1296,7 @@ void DragTangents()
if (m_SelectedTangentPoint != null)
{
- SaveKeySelection("Edit Curve");
+ SaveKeySelection(k_EditCurve);
GUIUtility.hotControl = tangentId;
evt.Use();
@@ -1320,11 +1326,16 @@ void DragTangents()
key.inTangent = tangentDirection.y / tangentDirection.x;
key.inWeight = Mathf.Clamp(Mathf.Abs(tangentDirection.x / dx), 0f, 1f);
}
- else
+ else if (tangentDirection.y > 0)
{
key.inTangent = Mathf.Infinity;
key.inWeight = 0f;
}
+ else
+ {
+ key.inTangent = -Mathf.Infinity;
+ key.inWeight = 0f;
+ }
AnimationUtility.SetKeyLeftTangentMode(ref key, TangentMode.Free);
if (!AnimationUtility.GetKeyBroken(key))
@@ -1344,11 +1355,16 @@ void DragTangents()
key.outTangent = tangentDirection.y / tangentDirection.x;
key.outWeight = Mathf.Clamp(Mathf.Abs(tangentDirection.x / dx), 0f, 1f);
}
- else
+ else if (tangentDirection.y > 0)
{
key.outTangent = Mathf.Infinity;
key.outWeight = 0f;
}
+ else
+ {
+ key.outTangent = -Mathf.Infinity;
+ key.outWeight = 0f;
+ }
AnimationUtility.SetKeyRightTangentMode(ref key, TangentMode.Free);
if (!AnimationUtility.GetKeyBroken(key))
@@ -1390,9 +1406,9 @@ internal void DeleteSelectedKeys()
{
string undoLabel;
if (selectedCurves.Count > 1)
- undoLabel = "Delete Keys";
+ undoLabel = k_DeleteKeys;
else
- undoLabel = "Delete Key";
+ undoLabel = k_DeleteKey;
SaveKeySelection(undoLabel);
@@ -1408,7 +1424,7 @@ internal void DeleteSelectedKeys()
continue;
if (!settings.allowDeleteLastKeyInCurve)
- if (cw.curve.keys.Length == 1)
+ if (cw.curve.length == 1)
continue;
cw.curve.RemoveKey(k.key);
@@ -1427,9 +1443,9 @@ private void DeleteKeys(object obj)
string undoLabel;
if (keyList.Count > 1)
- undoLabel = "Delete Keys";
+ undoLabel = k_DeleteKeys;
else
- undoLabel = "Delete Key";
+ undoLabel = k_DeleteKey;
SaveKeySelection(undoLabel);
@@ -1438,7 +1454,7 @@ private void DeleteKeys(object obj)
for (int i = keyList.Count - 1; i >= 0; i--)
{
if (!settings.allowDeleteLastKeyInCurve)
- if (keyList[i].curve.keys.Length == 1)
+ if (keyList[i].curve.length == 1)
continue;
if (!GetCurveWrapperFromID(keyList[i].curveId).animationIsEditable)
@@ -1788,6 +1804,9 @@ float SnapValue(float v)
new internal static class Styles
{
+ public const float pointIconCenterOffsetX = 7;
+ public const float pointIconCenterOffsetY = 8;
+ public const float pointIconSize = 16;
public static Texture2D pointIcon = EditorGUIUtility.LoadIcon("curvekeyframe");
public static Texture2D pointIconWeighted = EditorGUIUtility.LoadIcon("curvekeyframeweighted");
public static Texture2D pointIconSelected = EditorGUIUtility.LoadIcon("curvekeyframeselected");
@@ -1903,7 +1922,7 @@ int GetCurveAtPosition(Vector2 viewPos, out Vector2 closestPointOnCurve)
void CreateKeyFromClick(object obj)
{
- string undoLabel = "Add Key";
+ string undoLabel = k_AddKey;
SaveKeySelection(undoLabel);
List ids = CreateKeyFromClick((Vector2)obj);
@@ -1924,7 +1943,7 @@ List CreateKeyFromClick(Vector2 viewPos)
CurveWrapper cw = m_AnimationCurves[singleCurveIndex];
Vector2 localPos = ViewToDrawingTransformPoint(viewPos);
float time = localPos.x;
- if (cw.curve.keys.Length == 0 || time < cw.curve.keys[0].time || time > cw.curve.keys[cw.curve.keys.Length - 1].time)
+ if (cw.curve.length == 0 || time < cw.curve[0].time || time > cw.curve[cw.curve.length - 1].time)
{
if (CreateKeyFromClick(singleCurveIndex, localPos))
curveIds.Add(cw.id);
@@ -2142,9 +2161,10 @@ CurveSelection FindNearest()
if (cw.readOnly || cw.hidden)
continue;
- for (int i = 0; i < cw.curve.keys.Length; ++i)
+ Keyframe[] keys = cw.curve.keys;
+ for (int i = 0; i < cw.curve.length; ++i)
{
- Keyframe k = cw.curve.keys[i];
+ Keyframe k = keys[i];
float d = (GetGUIPoint(cw, new Vector2(k.time, k.value)) - mousePos).sqrMagnitude;
// If we have an exact hit we just return that key
if (d <= kExactPickDistSqr)
@@ -2260,7 +2280,7 @@ bool HandleCurveAndRegionMoveToFrontOnMouseDown(ref Vector2 timeValue, ref Curve
if (mouseY >= v1 && mouseY <= v2)
{
timeValue = mousePositionInDrawing;
- curves = new[] {cw, cw2};
+ curves = new[] { cw, cw2 };
MoveCurveToFront(cw.id);
return true;
}
@@ -2320,7 +2340,7 @@ void SelectPoints()
if (curve != null)
{
BeginRangeSelection();
- for (int keyIndex = 0; keyIndex < curve.keys.Length; ++keyIndex)
+ for (int keyIndex = 0; keyIndex < curve.length; ++keyIndex)
{
if (!selectedCurves.Any(x => x.curveID == selectedPoint.curveID && x.key == keyIndex))
{
@@ -2333,7 +2353,7 @@ void SelectPoints()
}
else
{
- SaveKeySelection("Add Key");
+ SaveKeySelection(k_AddKey);
List curveIds = CreateKeyFromClick(Event.current.mousePosition);
if (curveIds.Count > 0)
@@ -3052,7 +3072,7 @@ void ResetDragging()
void MakeCurveBackups()
{
- SaveKeySelection("Edit Curve");
+ SaveKeySelection(k_EditCurve);
m_CurveBackups = new List();
int lastCurveID = -1;
@@ -3102,6 +3122,7 @@ Vector2 GetPosition(CurveSelection selection)
{
Vector2 dir = new Vector2(1.0F, key.inTangent);
if (key.inTangent == Mathf.Infinity) dir = new Vector2(0, -1);
+ else if (key.inTangent == -Mathf.Infinity) dir = new Vector2(0, 1);
Vector2 viewDir = NormalizeInViewSpace(dir);
@@ -3125,6 +3146,7 @@ Vector2 GetPosition(CurveSelection selection)
{
Vector2 dir = new Vector2(1.0F, key.outTangent);
if (key.outTangent == Mathf.Infinity) dir = new Vector2(0, -1);
+ else if (key.outTangent == -Mathf.Infinity) dir = new Vector2(0, 1);
Vector2 viewDir = NormalizeInViewSpace(dir);
@@ -3681,7 +3703,7 @@ void DrawPoint(Vector2 viewPos, CurveWrapper.SelectionMode selected, MouseCursor
{
// Important to take floor of positions of GUI stuff to get pixel correct alignment of
// stuff drawn with both GUI and Handles/GL. Otherwise things are off by one pixel half the time.
- var rect = new Rect(Mathf.Floor(viewPos.x) - 4, Mathf.Floor(viewPos.y) - 4, Styles.pointIcon.width, Styles.pointIcon.height);
+ var rect = new Rect(Mathf.Floor(viewPos.x) - Styles.pointIconCenterOffsetX, Mathf.Floor(viewPos.y) - Styles.pointIconCenterOffsetY, Styles.pointIconSize, Styles.pointIconSize);
if (selected == CurveWrapper.SelectionMode.None)
{
@@ -3707,7 +3729,7 @@ void DrawTangentPoint(Vector2 viewPos, bool weighted)
{
// Important to take floor of positions of GUI stuff to get pixel correct alignment of
// stuff drawn with both GUI and Handles/GL. Otherwise things are off by one pixel half the time.
- var rect = new Rect(Mathf.Floor(viewPos.x) - 4, Mathf.Floor(viewPos.y) - 4, Styles.pointIcon.width, Styles.pointIcon.height);
+ var rect = new Rect(Mathf.Floor(viewPos.x) - Styles.pointIconCenterOffsetX, Mathf.Floor(viewPos.y) - Styles.pointIconCenterOffsetY, Styles.pointIconSize, Styles.pointIconSize);
if (weighted)
{
@@ -3815,7 +3837,6 @@ WrapMode WrapModeIconPopup(Keyframe key, WrapMode oldWrap, float hOffset)
{
r.y = r.y - selectedPopupIndex * 16 - 19;
}
-
EditorGUI.PopupCallbackInfo.instance = new EditorGUI.PopupCallbackInfo(controlID);
EditorUtility.DisplayCustomMenu(r, popupStrings, selectedPopupIndex, EditorGUI.PopupCallbackInfo.instance.SetEnumValueDelegate, null);
GUIUtility.keyboardControl = controlID;
@@ -3829,7 +3850,6 @@ WrapMode WrapModeIconPopup(Keyframe key, WrapMode oldWrap, float hOffset)
{
r.y = r.y - selectedPopupIndex * 16 - 19;
}
-
EditorGUI.PopupCallbackInfo.instance = new EditorGUI.PopupCallbackInfo(controlID);
EditorUtility.DisplayCustomMenu(r, popupStrings, selectedPopupIndex, EditorGUI.PopupCallbackInfo.instance.SetEnumValueDelegate, null);
evt.Use();
@@ -4077,7 +4097,7 @@ public void GridGUI()
float[] ticksPos = (float[])ticks.Clone();
// Calculate how many decimals are needed to show the differences between the labeled ticks
- int decimals = MathUtils.GetNumberOfDecimalsForMinimumDifference(vTicks.GetPeriodOfLevel(labelLevel));
+ int decimals = MathUtils.GetNumberOfDecimalsForMinimumDifference(vTicks.GetPeriodOfLevel(labelLevel));
string format = "n" + decimals;
m_AxisLabelFormat = format;
diff --git a/Editor/Mono/Animation/AnimationWindow/CurveEditorRectangleTool.cs b/Editor/Mono/Animation/AnimationWindow/CurveEditorRectangleTool.cs
index a78a744486..267c9616ee 100644
--- a/Editor/Mono/Animation/AnimationWindow/CurveEditorRectangleTool.cs
+++ b/Editor/Mono/Animation/AnimationWindow/CurveEditorRectangleTool.cs
@@ -554,7 +554,7 @@ public void OnGUI()
GUI.color = oldColor;
}
- public void OverlayOnGUI()
+ public void OverlayOnGUI(Rect bounds)
{
if (!hasSelection)
return;
@@ -578,7 +578,7 @@ public void OverlayOnGUI()
m_VBarTop.OnGUI(m_Layout.vBarTopRect);
}
- DrawLabels();
+ DrawLabels(bounds);
GUI.color = oldColor;
}
@@ -763,7 +763,7 @@ private ToolLayout CalculateLayout()
return layout;
}
- private void DrawLabels()
+ private void DrawLabels(Rect bounds)
{
if (dragMode == DragMode.None)
return;
@@ -793,7 +793,6 @@ private void DrawLabels()
{
GUIContent labelContent = new GUIContent(string.Format("{0}", m_CurveEditor.FormatTime(selectionBounds.center.x, m_CurveEditor.invSnap, m_CurveEditor.timeFormat)));
Vector2 labelSize = styles.dragLabel.CalcSize(labelContent);
-
EditorGUI.DoDropShadowLabel(new Rect(m_Layout.leftLabelAnchor.x, m_Layout.leftLabelAnchor.y, labelSize.x, labelSize.y), labelContent, styles.dragLabel, 0.3f);
}
}
@@ -831,7 +830,14 @@ private void DrawLabels()
GUIContent labelContent = new GUIContent(string.Format("{0}, {1}", m_CurveEditor.FormatTime(localPosition.x, m_CurveEditor.invSnap, m_CurveEditor.timeFormat), m_CurveEditor.FormatValue(localPosition.y)));
Vector2 labelSize = styles.dragLabel.CalcSize(labelContent);
- EditorGUI.DoDropShadowLabel(new Rect(labelPosition.x, labelPosition.y - labelSize.y, labelSize.x, labelSize.y), labelContent, styles.dragLabel, 0.3f);
+ // Clamp popup to remain inside the curve editor window
+ var labelRect = new Rect(labelPosition.x, labelPosition.y - labelSize.y, labelSize.x, labelSize.y);
+ labelRect.x += Mathf.Max(0.0f, bounds.xMin - labelRect.xMin);
+ labelRect.x -= Mathf.Max(0.0f, labelRect.xMax - bounds.xMax);
+ labelRect.y += Mathf.Max(0.0f, bounds.yMin - labelRect.yMin);
+ labelRect.y -= Mathf.Max(0.0f, labelRect.yMax - bounds.yMax);
+
+ EditorGUI.DoDropShadowLabel(labelRect, labelContent, styles.dragLabel, 0.3f);
}
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs b/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs
index 00a8a9099d..0de9352fa1 100644
--- a/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs
+++ b/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs
@@ -30,12 +30,13 @@ public enum NormalizationMode
}
//const int kToolbarHeight = 17;
- const int kPresetsHeight = 46;
+ const int kPresetsHeight = 50;
static CurveEditorWindow s_SharedCurveEditor;
- CurveEditor m_CurveEditor;
+ internal CurveEditor m_CurveEditor;
+ Vector2 m_PresetScrollPosition;
AnimationCurve m_Curve;
Color m_Color;
@@ -43,11 +44,14 @@ public enum NormalizationMode
GUIContent m_GUIContent = new GUIContent();
[SerializeField]
- GUIView delegateView;
+ GUIView m_DelegateView;
public const string CurveChangedCommand = "CurveChanged";
public const string CurveChangeCompletedCommand = "CurveChangeCompleted";
+ // Watch out when accessing this, it will create a new curve editor window if none exists yet.
+ // If you don't display the window (call Show()), it will cause an error when validating the layout
+ // (e.g. when the user maximizes a window).
public static CurveEditorWindow instance
{
get
@@ -99,6 +103,11 @@ public static Color color
}
}
+ internal static GUIView delegateView
+ {
+ get { return visible ? CurveEditorWindow.instance.m_DelegateView : null; }
+ }
+
public static bool visible
{
get { return s_SharedCurveEditor != null; }
@@ -269,7 +278,7 @@ private void RefreshShownCurves()
public void Show(GUIView viewToUpdate, CurveEditorSettings settings)
{
- delegateView = viewToUpdate;
+ m_DelegateView = viewToUpdate;
m_OnCurveChanged = null;
Init(settings);
@@ -281,7 +290,7 @@ public void Show(GUIView viewToUpdate, CurveEditorSettings settings)
public void Show(Action onCurveChanged, CurveEditorSettings settings)
{
m_OnCurveChanged = onCurveChanged;
- delegateView = null;
+ m_DelegateView = null;
Init(settings);
ShowAuxWindow();
@@ -451,7 +460,7 @@ void OnGUI()
{
bool gotMouseUp = (Event.current.type == EventType.MouseUp);
- if (delegateView == null && m_OnCurveChanged == null)
+ if (m_DelegateView == null && m_OnCurveChanged == null)
m_Curve = null;
if (ms_Styles == null)
@@ -468,20 +477,38 @@ void OnGUI()
m_CurveEditor.OnGUI();
// Preset swatch area
- GUI.Box(new Rect(0, position.height - kPresetsHeight, position.width, kPresetsHeight), "", ms_Styles.curveSwatchArea);
+ var presetRect = new Rect(0, position.height - kPresetsHeight, position.width, kPresetsHeight);
+ GUI.Box(presetRect, "", ms_Styles.curveSwatchArea);
+
Color curveColor = m_Color;
curveColor.a *= 0.6f;
- const float margin = 45f;
const float width = 40f;
const float height = 25f;
- float yPos = position.height - kPresetsHeight + (kPresetsHeight - height) * 0.5f;
+ const float spaceBetweenSwatches = 5f;
+ const float presetDropdownSize = 16f;
+ const float horizontalScrollbarHeight = 15f;
+ const float presetDropdownCenteringOffset = 2f;
+ float yPos = (kPresetsHeight - height) * 0.5f;
InitCurvePresets();
CurvePresetLibrary curveLibrary = m_CurvePresets.GetPresetLibraryEditor().GetCurrentLib();
if (curveLibrary != null)
{
- for (int i = 0; i < curveLibrary.Count(); i++)
+ var numPresets = curveLibrary.Count();
+ var presetDropDownRect = new Rect(spaceBetweenSwatches, yPos + presetDropdownCenteringOffset, presetDropdownSize, presetDropdownSize);
+ Rect contentRect = new Rect(0, 0, numPresets * (width + spaceBetweenSwatches) + presetDropDownRect.xMax, presetRect.height - horizontalScrollbarHeight);
+ m_PresetScrollPosition = GUI.BeginScrollView(
+ presetRect, // Rectangle of the visible area
+ m_PresetScrollPosition, // Current scroll position
+ contentRect, // Rectangle containing all content
+ false, // Always show horizontal scrollbar
+ false // Always show vertical scrollbar
+ );
+
+ PresetDropDown(presetDropDownRect);
+
+ Rect swatchRect = new Rect(presetDropDownRect.xMax + spaceBetweenSwatches, yPos, width, height);
+ for (int i = 0; i < numPresets; i++)
{
- Rect swatchRect = new Rect(margin + (width + 5f) * i, yPos, width, height);
m_GUIContent.tooltip = curveLibrary.GetName(i);
if (GUI.Button(swatchRect, m_GUIContent, ms_Styles.curveSwatch))
{
@@ -495,14 +522,11 @@ void OnGUI()
if (Event.current.type == EventType.Repaint)
curveLibrary.Draw(swatchRect, i);
- if (swatchRect.xMax > position.width - 2 * margin)
- break;
+ swatchRect.x += width + spaceBetweenSwatches;
}
+ GUI.EndScrollView();
}
- Rect presetDropDownButtonRect = new Rect(margin - 20f, yPos + 5f, 20, 20);
- PresetDropDown(presetDropDownButtonRect);
-
// For adding default preset curves
//if (EditorGUI.DropdownButton(new Rect (position.width -26, yPos, 20, 20), GUIContent.none, FocusType.Passive, "OL Plus"))
// AddDefaultPresetsToCurrentLib ();
@@ -576,11 +600,11 @@ private void DoUpdateCurve(bool exitGUI)
void SendEvent(string eventName, bool exitGUI)
{
- if (delegateView)
+ if (m_DelegateView)
{
Event e = EditorGUIUtility.CommandEvent(eventName);
Repaint();
- delegateView.SendEvent(e);
+ m_DelegateView.SendEvent(e);
if (exitGUI)
GUIUtility.ExitGUI();
}
diff --git a/Editor/Mono/Animation/AnimationWindow/CurveRenderer/NormalCurveRenderer.cs b/Editor/Mono/Animation/AnimationWindow/CurveRenderer/NormalCurveRenderer.cs
index e18bb8552d..dde6db2ac8 100644
--- a/Editor/Mono/Animation/AnimationWindow/CurveRenderer/NormalCurveRenderer.cs
+++ b/Editor/Mono/Animation/AnimationWindow/CurveRenderer/NormalCurveRenderer.cs
@@ -20,8 +20,8 @@ internal class NormalCurveRenderer : CurveRenderer
private AnimationCurve m_Curve;
private float m_CustomRangeStart = 0;
private float m_CustomRangeEnd = 0;
- private float rangeStart { get { return (m_CustomRangeStart == 0 && m_CustomRangeEnd == 0 && m_Curve.length > 0 ? m_Curve.keys[0].time : m_CustomRangeStart); } }
- private float rangeEnd { get { return (m_CustomRangeStart == 0 && m_CustomRangeEnd == 0 && m_Curve.length > 0 ? m_Curve.keys[m_Curve.length - 1].time : m_CustomRangeEnd); } }
+ private float rangeStart { get { return (m_CustomRangeStart == 0 && m_CustomRangeEnd == 0 && m_Curve.length > 0 ? m_Curve[0].time : m_CustomRangeStart); } }
+ private float rangeEnd { get { return (m_CustomRangeStart == 0 && m_CustomRangeEnd == 0 && m_Curve.length > 0 ? m_Curve[m_Curve.length - 1].time : m_CustomRangeEnd); } }
private WrapMode preWrapMode = WrapMode.Once;
private WrapMode postWrapMode = WrapMode.Once;
@@ -262,11 +262,14 @@ public void DrawCurve(float minTime, float maxTime, Color color, Matrix4x4 trans
{
BuildCurveMesh();
- Keyframe[] keys = m_Curve.keys;
- if (keys.Length > 0)
+ int numKeys = m_Curve.length;
+ int first = 0;
+ int last = Mathf.Max(first, numKeys - 1);
+
+ if (numKeys > 0)
{
- Vector3 firstPoint = new Vector3(rangeStart, keys.First().value);
- Vector3 lastPoint = new Vector3(rangeEnd, keys.Last().value);
+ Vector3 firstPoint = new Vector3(rangeStart, m_Curve[first].value);
+ Vector3 lastPoint = new Vector3(rangeEnd, m_Curve[last].value);
DrawCurveWrapped(minTime, maxTime, rangeStart, rangeEnd, preWrapMode, postWrapMode, m_CurveMesh, firstPoint, lastPoint, transform, color, wrapColor);
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/Deprecated/AnimationEventTimeline.cs b/Editor/Mono/Animation/AnimationWindow/Deprecated/AnimationEventTimeline.cs
index 83ac70c0c1..48b2e83421 100644
--- a/Editor/Mono/Animation/AnimationWindow/Deprecated/AnimationEventTimeline.cs
+++ b/Editor/Mono/Animation/AnimationWindow/Deprecated/AnimationEventTimeline.cs
@@ -27,12 +27,13 @@ internal static class Styles
private AnimationEvent[] m_EventsAtMouseDown;
[System.NonSerialized]
private float[] m_EventTimes;
+ private static readonly Vector2 k_EventMarkerSize = new Vector2(16, 16);
private bool m_DirtyTooltip = false;
private int m_HoverEvent = -1;
- // Rects used for checking mouse-move state changes
private string m_InstantTooltipText = null;
private Vector2 m_InstantTooltipPoint = Vector2.zero;
+ private bool m_HasSelectedEvents;
public AnimationEventTimeLine(EditorWindow owner)
{
@@ -53,7 +54,7 @@ public int Compare(AnimationEvent x, AnimationEvent y)
}
}
- private class EventLineContextMenuObject
+ private struct EventLineContextMenuObject
{
public GameObject m_Animated;
public AnimationClip m_Clip;
@@ -71,6 +72,8 @@ public EventLineContextMenuObject(GameObject animated, AnimationClip clip, float
}
}
+ internal bool HasSelectedEvents => m_HasSelectedEvents;
+
public void AddEvent(float time, GameObject gameObject, AnimationClip animationClip)
{
AnimationWindowEvent awEvent = AnimationWindowEvent.CreateAndEdit(gameObject, animationClip, time);
@@ -141,7 +144,7 @@ void CopyEvents(AnimationClip clip, bool[] selected, int explicitIndex = -1)
AnimationWindowEventsClipboard.CopyEvents(allEvents, selected, explicitIndex);
}
- void PasteEvents(GameObject animated, AnimationClip clip, float time)
+ internal void PasteEvents(GameObject animated, AnimationClip clip, float time)
{
var oldEvents = AnimationUtility.GetAnimationEvents(clip);
var newEvents = AnimationWindowEventsClipboard.AddPastedEvents(oldEvents, time, out var selected);
@@ -199,15 +202,15 @@ public void EventLineGUI(Rect rect, AnimationWindowState state)
int sharedOffset = 0;
if (shared > 1)
{
- float spread = Mathf.Min((shared - 1) * (eventMarker.width - 1), (int)(state.FrameDeltaToPixel(rect) - eventMarker.width * 2));
- sharedOffset = Mathf.FloorToInt(Mathf.Max(0, spread - (eventMarker.width - 1) * (sharedLeft)));
+ float spread = Mathf.Min((shared - 1) * (k_EventMarkerSize.x - 1), (int)(state.FrameDeltaToPixel(rect) - k_EventMarkerSize.x * 2));
+ sharedOffset = Mathf.FloorToInt(Mathf.Max(0, spread - (k_EventMarkerSize.x - 1) * (sharedLeft)));
}
Rect r = new Rect(
- keypos + sharedOffset - eventMarker.width / 2,
+ keypos + sharedOffset - k_EventMarkerSize.x / 2,
(rect.height - 10) * (float)(sharedLeft - shared + 1) / Mathf.Max(1, shared - 1),
- eventMarker.width,
- eventMarker.height);
+ k_EventMarkerSize.x,
+ k_EventMarkerSize.y);
hitRects[i] = r;
drawRects[i] = r;
@@ -225,6 +228,7 @@ public void EventLineGUI(Rect rect, AnimationWindowState state)
}
bool[] selectedEvents = new bool[events.Length];
+ m_HasSelectedEvents = false;
Object[] selectedObjects = Selection.objects;
foreach (Object selectedObject in selectedObjects)
@@ -235,6 +239,7 @@ public void EventLineGUI(Rect rect, AnimationWindowState state)
if (awe.eventIndex >= 0 && awe.eventIndex < selectedEvents.Length)
{
selectedEvents[awe.eventIndex] = true;
+ m_HasSelectedEvents = true;
}
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/DopeLine.cs b/Editor/Mono/Animation/AnimationWindow/DopeLine.cs
index c576b1cf2c..da6b52f5f0 100644
--- a/Editor/Mono/Animation/AnimationWindow/DopeLine.cs
+++ b/Editor/Mono/Animation/AnimationWindow/DopeLine.cs
@@ -98,7 +98,7 @@ public List keys
{
m_Keys = new List();
foreach (AnimationWindowCurve curve in m_Curves)
- foreach (AnimationWindowKeyframe key in curve.m_Keyframes)
+ foreach (AnimationWindowKeyframe key in curve.keyframes)
m_Keys.Add(key);
m_Keys.Sort((a, b) => a.time.CompareTo(b.time));
diff --git a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs
index 4ad6ddec5e..ae4b219977 100644
--- a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs
+++ b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs
@@ -9,13 +9,14 @@
using Event = UnityEngine.Event;
using Object = UnityEngine.Object;
using System.Collections;
+using System.Linq;
namespace UnityEditorInternal
{
[System.Serializable]
- internal class DopeSheetEditor : TimeArea, CurveUpdater
+ class DopeSheetEditor : TimeArea, CurveUpdater
{
- public AnimationWindowState state;
+ [SerializeReference] public AnimationWindowState state;
// How much rendered keyframe left edge is visually offset when compared to the time it represents.
// A diamond shape left edge isn't representing the time, the middle part is.
@@ -23,6 +24,8 @@ internal class DopeSheetEditor : TimeArea, CurveUpdater
// Pptr keyframe preview also needs 1px offset so it sits more tightly in the grid
private const float k_PptrKeyframeOffset = -1;
+ private static readonly Vector2 k_ControlPointSize = new Vector2(16, 16);
+
const int kLabelMarginHorizontal = 8;
const int kLabelMarginVertical = 2;
@@ -148,7 +151,7 @@ public void AddUnselectedKey(DrawElement element)
else
{
Rect rect = element.position;
- rect.size = new Vector2(m_DefaultDopeKeyIcon.width, m_DefaultDopeKeyIcon.height);
+ rect.size = k_ControlPointSize;
m_UnselectedKeysRenderer.AddPoint(rect, element.color);
}
}
@@ -164,7 +167,7 @@ public void AddSelectedKey(DrawElement element)
else
{
Rect rect = element.position;
- rect.size = new Vector2(m_DefaultDopeKeyIcon.width, m_DefaultDopeKeyIcon.height);
+ rect.size = k_ControlPointSize;
m_SelectedKeysRenderer.AddPoint(rect, element.color);
}
}
@@ -180,7 +183,7 @@ public void AddDragDropKey(DrawElement element)
else
{
Rect rect = element.position;
- rect.size = new Vector2(m_DefaultDopeKeyIcon.width, m_DefaultDopeKeyIcon.height);
+ rect.size = k_ControlPointSize;
m_DragDropKeysRenderer.AddPoint(rect, element.color);
}
}
@@ -493,7 +496,7 @@ private void DopeLineRepaint(DopeLine dopeline)
if (DoDragAndDrop(dopeline, dopeline.position, false))
{
- float time = Mathf.Max(state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToClipFrame), 0f);
+ float time = Mathf.Max(state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToFrame), 0f);
Color keyColor = Color.gray.RGBMultiplied(1.2f);
Texture2D texture = null;
@@ -561,15 +564,15 @@ private GenericMenu GenerateMenu(DopeLine dopeline)
hoveringKeys.Add(key);
}
- AnimationKeyTime mouseKeyTime = AnimationKeyTime.Time(state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToClipFrame), state.frameRate);
+ AnimationKeyTime mouseKeyTime = AnimationKeyTime.Time(state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToFrame), state.frameRate);
- string str = "Add Key";
+ string str = L10n.Tr("Add Key");
if (dopeline.isEditable && hoveringKeys.Count == 0)
menu.AddItem(new GUIContent(str), false, AddKeyToDopeline, new AddKeyToDopelineContext {dopeline = dopeline, time = mouseKeyTime});
else
menu.AddDisabledItem(new GUIContent(str));
- str = state.selectedKeys.Count > 1 ? "Delete Keys" : "Delete Key";
+ str = state.selectedKeys.Count > 1 ? L10n.Tr("Delete Keys") : L10n.Tr("Delete Key");
if (dopeline.isEditable && (state.selectedKeys.Count > 0 || hoveringKeys.Count > 0))
menu.AddItem(new GUIContent(str), false, DeleteKeys, state.selectedKeys.Count > 0 ? state.selectedKeys : hoveringKeys);
else
@@ -638,7 +641,7 @@ private void HandleDragging()
foreach (AnimationWindowKeyframe selectedKey in state.selectedKeys)
firstSelectedKeyTime = Mathf.Min(selectedKey.time, firstSelectedKeyTime);
- float currentTime = state.SnapToFrame(state.PixelToTime(Event.current.mousePosition.x), AnimationWindowState.SnapMode.SnapToClipFrame);
+ float currentTime = state.SnapToFrame(state.PixelToTime(Event.current.mousePosition.x), AnimationWindowState.SnapMode.SnapToFrame);
if (m_IsDragging)
{
@@ -773,9 +776,7 @@ private void HandleDragAndDropToEmptyArea()
{
EditorCurveBinding? spriteBinding = CreateNewPptrDopeline(state.selection, typeof(Sprite));
if (spriteBinding != null)
- {
DoSpriteDropAfterGeneratingNewDopeline(state.activeAnimationClip, spriteBinding);
- }
}
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
@@ -792,8 +793,35 @@ private void DoSpriteDropAfterGeneratingNewDopeline(AnimationClip animationClip,
// Create the new curve for our sprites
AnimationWindowCurve newCurve = new AnimationWindowCurve(animationClip, (EditorCurveBinding)spriteBinding, typeof(Sprite));
- // And finally perform the drop onto the curve
+ // Perform the drop onto the curve
PerformDragAndDrop(newCurve, 0f);
+
+ // Assign the Sprite in the first keyframe to the SpriteRenderer's Sprite property
+ AssignSpriteToSpriteRenderer(newCurve);
+ }
+
+ private void AssignSpriteToSpriteRenderer(AnimationWindowCurve curve)
+ {
+ var rootGameObject = state.selection.rootGameObject;
+ if (rootGameObject == null)
+ return;
+
+ var hasValidCurve = curve.keyframes.Count > 0 && curve.binding.type == typeof(SpriteRenderer);
+ if (!hasValidCurve)
+ return;
+
+ var spriteRenderer = AnimationUtility.GetAnimatedObject(rootGameObject, curve.binding) as SpriteRenderer;
+ var hasValidSpriteRenderer = spriteRenderer != null && spriteRenderer.sprite == null;
+ if (!hasValidSpriteRenderer)
+ return;
+
+ var keyframe = curve.keyframes[0];
+ var sprite = keyframe.value as Sprite;
+ if (sprite != null)
+ {
+ Undo.RecordObject(spriteRenderer, "Add Sprite");
+ spriteRenderer.sprite = sprite;
+ }
}
private void HandleRectangleToolEvents()
@@ -803,29 +831,46 @@ private void HandleRectangleToolEvents()
private bool DopelineForValueTypeExists(Type valueType)
{
- return state.allCurves.Exists(curve => curve.valueType == valueType);
+ return state.filteredCurves.Exists(curve => curve.valueType == valueType);
+ }
+
+ public EditorCurveBinding[] GetAnimatableProperties(AnimationWindowSelectionItem selection, Type valueType)
+ {
+ EditorCurveBinding[] allBindings = null;
+ if (selection.gameObject != null)
+ {
+ allBindings = state.controlInterface.GetAnimatableBindings(selection.gameObject);
+ }
+ else if (selection.scriptableObject != null)
+ {
+ allBindings = state.controlInterface.GetAnimatableBindings();
+ }
+
+ return allBindings
+ .Where(binding => state.controlInterface.GetValueType(binding) == valueType)
+ .ToArray();
}
private EditorCurveBinding? CreateNewPptrDopeline(AnimationWindowSelectionItem selectedItem, Type valueType)
{
- List potentialBindings = null;
+ EditorCurveBinding[] potentialBindings = null;
if (selectedItem.rootGameObject != null)
{
- potentialBindings = AnimationWindowUtility.GetAnimatableProperties(selectedItem.rootGameObject, selectedItem.rootGameObject, valueType);
- if (potentialBindings.Count == 0 && valueType == typeof(Sprite)) // No animatable properties for Sprite available. Default as SpriteRenderer.
+ potentialBindings = GetAnimatableProperties(selectedItem, valueType);
+ if (potentialBindings.Length == 0 && valueType == typeof(Sprite)) // No animatable properties for Sprite available. Default as SpriteRenderer.
{
return CreateNewSpriteRendererDopeline(selectedItem.rootGameObject, selectedItem.rootGameObject);
}
}
else if (selectedItem.scriptableObject != null)
{
- potentialBindings = AnimationWindowUtility.GetAnimatableProperties(selectedItem.scriptableObject, valueType);
+ potentialBindings = GetAnimatableProperties(selectedItem, valueType);
}
- if (potentialBindings == null || potentialBindings.Count == 0)
+ if (potentialBindings == null || potentialBindings.Length == 0)
return null;
- if (potentialBindings.Count == 1) // Single property for this valuetype, return it
+ if (potentialBindings.Length == 1) // Single property for this valuetype, return it
{
return potentialBindings[0];
}
@@ -855,20 +900,16 @@ private void SelectTypeForCreatingNewPptrDopeline(object userData, string[] opti
DoSpriteDropAfterGeneratingNewDopeline(animationClip, bindings[selected]);
}
- private EditorCurveBinding? CreateNewSpriteRendererDopeline(GameObject targetGameObject, GameObject rootGameObject)
+ private EditorCurveBinding CreateNewSpriteRendererDopeline(GameObject targetGameObject, GameObject rootGameObject)
{
// Let's make sure there is spriterenderer to animate
if (!targetGameObject.GetComponent())
targetGameObject.AddComponent();
- // Now we should always find an animatable binding for it
- List curveBindings = AnimationWindowUtility.GetAnimatableProperties(targetGameObject, rootGameObject, typeof(SpriteRenderer), typeof(Sprite));
- if (curveBindings.Count == 1)
- return curveBindings[0];
-
- // Something went wrong
- Debug.LogError("Unable to create animatable SpriteRenderer component");
- return null;
+ return EditorCurveBinding.PPtrCurve(
+ AnimationUtility.CalculateTransformPath(targetGameObject.transform, rootGameObject.transform),
+ typeof(SpriteRenderer),
+ "m_Sprite");
}
private void HandleDragAndDrop(DopeLine dopeline)
@@ -1003,7 +1044,7 @@ private void HandleMouseDown(DopeLine dopeline)
private void HandleDopelineDoubleclick(DopeLine dopeline)
{
- float timeAtMousePosition = state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToClipFrame);
+ float timeAtMousePosition = state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToFrame);
AnimationKeyTime mouseKeyTime = AnimationKeyTime.Time(timeAtMousePosition, state.frameRate);
AnimationWindowUtility.AddKeyframes(state, dopeline.curves, mouseKeyTime);
@@ -1027,7 +1068,7 @@ private Rect GetKeyframeRect(DopeLine dopeline, AnimationWindowKeyframe keyframe
if (dopeline.isPptrDopeline && dopeline.tallMode && (keyframe == null || keyframe.value != null))
width = dopeline.position.height;
- return new Rect(state.TimeToPixel(state.SnapToFrame(time, AnimationWindowState.SnapMode.SnapToClipFrame)) + GetKeyframeOffset(dopeline, keyframe), dopeline.position.yMin, width, dopeline.position.height);
+ return new Rect(state.TimeToPixel(state.SnapToFrame(time, AnimationWindowState.SnapMode.SnapToFrame)) + GetKeyframeOffset(dopeline, keyframe), dopeline.position.yMin, width, dopeline.position.height);
}
// This means "how much is the rendered keyframe offset in pixels for x-axis".
@@ -1085,12 +1126,12 @@ public void FrameSelected()
{
foreach (AnimationWindowCurve curve in state.activeCurves)
{
- int keyCount = curve.m_Keyframes.Count;
+ int keyCount = curve.keyframes.Count;
if (keyCount > 1)
{
- Vector2 pt1 = new Vector2(curve.m_Keyframes[0].time, 0.0f);
- Vector2 pt2 = new Vector2(curve.m_Keyframes[keyCount - 1].time, 0.0f);
+ Vector2 pt1 = new Vector2(curve.keyframes[0].time, 0.0f);
+ Vector2 pt2 = new Vector2(curve.keyframes[keyCount - 1].time, 0.0f);
if (firstKey)
{
@@ -1162,7 +1203,7 @@ private bool DoDragAndDrop(DopeLine dopeLine, Rect position, bool perform)
if (perform)
{
- float time = Mathf.Max(state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToClipFrame), 0f);
+ float time = Mathf.Max(state.PixelToTime(Event.current.mousePosition.x, AnimationWindowState.SnapMode.SnapToFrame), 0f);
AnimationWindowCurve targetCurve = GetCurveOfType(dopeLine, targetType);
PerformDragAndDrop(targetCurve, time);
}
@@ -1175,7 +1216,7 @@ private void PerformDragAndDrop(AnimationWindowCurve targetCurve, float time)
if (DragAndDrop.objectReferences.Length == 0 || targetCurve == null)
return;
- string undoLabel = "Drop Key";
+ string undoLabel = L10n.Tr("Drop Key");
state.SaveKeySelection(undoLabel);
state.ClearSelections();
@@ -1421,8 +1462,8 @@ public Rect GetCurrentPixelRect()
{
float height = AnimationWindowHierarchyGUI.k_DopeSheetRowHeight;
Rect r = AnimationWindowUtility.FromToRect(m_SelectStartPoint, m_SelectMousePoint);
- r.xMin = owner.state.TimeToPixel(owner.state.PixelToTime(r.xMin, AnimationWindowState.SnapMode.SnapToClipFrame), AnimationWindowState.SnapMode.SnapToClipFrame);
- r.xMax = owner.state.TimeToPixel(owner.state.PixelToTime(r.xMax, AnimationWindowState.SnapMode.SnapToClipFrame), AnimationWindowState.SnapMode.SnapToClipFrame);
+ r.xMin = owner.state.TimeToPixel(owner.state.PixelToTime(r.xMin, AnimationWindowState.SnapMode.SnapToFrame), AnimationWindowState.SnapMode.SnapToFrame);
+ r.xMax = owner.state.TimeToPixel(owner.state.PixelToTime(r.xMax, AnimationWindowState.SnapMode.SnapToFrame), AnimationWindowState.SnapMode.SnapToFrame);
r.yMin = Mathf.Floor(r.yMin / height) * height;
r.yMax = (Mathf.Floor(r.yMax / height) + 1) * height;
return r;
@@ -1432,8 +1473,8 @@ public Rect GetCurrentTimeRect()
{
float height = AnimationWindowHierarchyGUI.k_DopeSheetRowHeight;
Rect r = AnimationWindowUtility.FromToRect(m_SelectStartPoint, m_SelectMousePoint);
- r.xMin = owner.state.PixelToTime(r.xMin, AnimationWindowState.SnapMode.SnapToClipFrame);
- r.xMax = owner.state.PixelToTime(r.xMax, AnimationWindowState.SnapMode.SnapToClipFrame);
+ r.xMin = owner.state.PixelToTime(r.xMin, AnimationWindowState.SnapMode.SnapToFrame);
+ r.xMax = owner.state.PixelToTime(r.xMax, AnimationWindowState.SnapMode.SnapToFrame);
r.yMin = Mathf.Floor(r.yMin / height) * height;
r.yMax = (Mathf.Floor(r.yMax / height) + 1) * height;
return r;
@@ -1446,7 +1487,7 @@ public void UpdateCurves(List changedCurves, string undoText)
foreach (ChangedCurve changedCurve in changedCurves)
{
- AnimationWindowCurve curve = state.allCurves.Find(c => changedCurve.curveId == c.GetHashCode());
+ AnimationWindowCurve curve = state.filteredCurves.Find(c => changedCurve.curveId == c.GetHashCode());
if (curve != null)
{
AnimationUtility.SetEditorCurve(curve.clip, changedCurve.binding, changedCurve.curve);
diff --git a/Editor/Mono/Animation/AnimationWindow/GameObjectSelectionItem.cs b/Editor/Mono/Animation/AnimationWindow/GameObjectSelectionItem.cs
index f1d1aa5e68..3c40b4b184 100644
--- a/Editor/Mono/Animation/AnimationWindow/GameObjectSelectionItem.cs
+++ b/Editor/Mono/Animation/AnimationWindow/GameObjectSelectionItem.cs
@@ -8,11 +8,12 @@
namespace UnityEditorInternal
{
+ [Serializable]
internal class GameObjectSelectionItem : AnimationWindowSelectionItem
{
public static GameObjectSelectionItem Create(GameObject gameObject)
{
- GameObjectSelectionItem selectionItem = CreateInstance(typeof(GameObjectSelectionItem)) as GameObjectSelectionItem;
+ var selectionItem = new GameObjectSelectionItem();
selectionItem.gameObject = gameObject;
selectionItem.animationClip = null;
diff --git a/Editor/Mono/Animation/AnimationWindow/IAnimationContextualResponder.cs b/Editor/Mono/Animation/AnimationWindow/IAnimationContextualResponder.cs
index 9070b0ecf8..ce1a181faa 100644
--- a/Editor/Mono/Animation/AnimationWindow/IAnimationContextualResponder.cs
+++ b/Editor/Mono/Animation/AnimationWindow/IAnimationContextualResponder.cs
@@ -2,8 +2,6 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
-using System;
-using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;
diff --git a/Editor/Mono/Animation/AnimationWindow/IAnimationWindowControl.cs b/Editor/Mono/Animation/AnimationWindow/IAnimationWindowControl.cs
index 356bc4fb30..fb89e71fb3 100644
--- a/Editor/Mono/Animation/AnimationWindow/IAnimationWindowControl.cs
+++ b/Editor/Mono/Animation/AnimationWindow/IAnimationWindowControl.cs
@@ -3,26 +3,64 @@
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using System;
-using UnityEngine;
using UnityEditor;
+using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditorInternal
{
- internal abstract class IAnimationWindowControl : ScriptableObject
+ // Compatibility implementation of IAnimationWindowController.
+ abstract class IAnimationWindowControl : ScriptableObject, IAnimationWindowController
{
- public virtual void OnEnable() { hideFlags = HideFlags.HideAndDontSave; }
+ [SerializeReference] AnimationWindowState m_State;
+
+ public virtual void OnEnable()
+ {
+ hideFlags = HideFlags.HideAndDontSave;
+ }
+
public abstract void OnSelectionChanged();
+ public void Init(AnimationWindowState state)
+ {
+ m_State = state;
+ }
+
+ void IAnimationWindowController.OnCreate(AnimationWindow animationWindow, UnityEngine.Component component)
+ {
+ }
+
+ void IAnimationWindowController.OnDestroy()
+ {
+ // Animation Window has ownership of `IAnimationWindowControl` in legacy workflow.
+ Object.DestroyImmediate(this);
+ }
+
+ float IAnimationWindowController.time
+ {
+ get => time.time;
+ set => GoToTime(value);
+ }
+
+ int IAnimationWindowController.frame
+ {
+ get => time.frame;
+ set => GoToFrame(value);
+ }
+
public abstract AnimationKeyTime time { get; }
public abstract void GoToTime(float time);
public abstract void GoToFrame(int frame);
+ // Not used anymore. This was not used by either the AnimationWindow nor Timeline.
+ // Replaced by setting IAnimationWindowController.time.
public abstract void StartScrubTime();
public abstract void ScrubTime(float time);
public abstract void EndScrubTime();
+ // Not used anymore. Required internal knowledge of the Animation Window and
+ // default implementation should suffice.
public abstract void GoToPreviousFrame();
public abstract void GoToNextFrame();
public abstract void GoToPreviousKeyframe();
@@ -31,26 +69,152 @@ internal abstract class IAnimationWindowControl : ScriptableObject
public abstract void GoToLastKeyframe();
public abstract bool canPlay { get; }
- public abstract bool playing { get; }
+ bool IAnimationWindowController.playing
+ {
+ get => playing;
+ set
+ {
+ if (value)
+ StartPlayback();
+ else
+ StopPlayback();
+ }
+ }
+
+ public abstract bool playing { get; }
public abstract bool StartPlayback();
public abstract void StopPlayback();
public abstract bool PlaybackUpdate();
public abstract bool canPreview { get; }
- public abstract bool previewing { get; }
+ bool IAnimationWindowController.previewing
+ {
+ get => previewing;
+ set
+ {
+ if (value)
+ StartPreview();
+ else
+ StopPreview();
+ }
+ }
+
+ public abstract bool previewing { get; }
public abstract bool StartPreview();
public abstract void StopPreview();
public abstract bool canRecord { get; }
- public abstract bool recording { get; }
+ bool IAnimationWindowController.recording
+ {
+ get => recording;
+ set
+ {
+ if (value)
+ StartRecording(null);
+ else
+ StopRecording();
+ }
+ }
+
+ public abstract bool recording { get; }
+ // targetObject parameter is not used.
public abstract bool StartRecording(Object targetObject);
public abstract void StopRecording();
+
public abstract void ResampleAnimation();
public abstract void ProcessCandidates();
public abstract void ClearCandidates();
+
+ EditorCurveBinding[] IAnimationWindowController.GetAnimatableBindings()
+ {
+ if (m_State == null)
+ return Array.Empty();
+
+ var rootGameObject = m_State.activeRootGameObject;
+ var scriptableObject = m_State.activeScriptableObject;
+
+ if (rootGameObject != null)
+ {
+ return AnimationWindowUtility.GetAnimatableBindings(rootGameObject);
+ }
+ if (scriptableObject != null)
+ {
+ return AnimationUtility.GetAnimatableBindings(scriptableObject);
+ }
+
+ return Array.Empty();
+ }
+
+ EditorCurveBinding[] IAnimationWindowController.GetAnimatableBindings(GameObject gameObject)
+ {
+ if (m_State == null)
+ return Array.Empty();
+
+ var rootGameObject = m_State.activeRootGameObject;
+ return AnimationUtility.GetAnimatableBindings(gameObject, rootGameObject);
+ }
+
+ System.Type IAnimationWindowController.GetValueType(EditorCurveBinding binding)
+ {
+ if (m_State == null)
+ return default;
+
+ var rootGameObject = m_State.activeRootGameObject;
+ var scriptableObject = m_State.activeScriptableObject;
+
+ if (rootGameObject != null)
+ {
+ return AnimationUtility.GetEditorCurveValueType(rootGameObject, binding);
+ }
+ else if (scriptableObject != null)
+ {
+ return AnimationUtility.GetEditorCurveValueType(scriptableObject, binding);
+ }
+ else
+ {
+ if (binding.isPPtrCurve)
+ {
+ // Cannot extract type of PPtrCurve.
+ return null;
+ }
+ else
+ {
+ // Cannot extract type of AnimationCurve. Default to float.
+ return typeof(float);
+ }
+ }
+ }
+
+ float IAnimationWindowController.GetFloatValue(EditorCurveBinding binding)
+ {
+ if (m_State == null)
+ return default;
+
+ AnimationUtility.GetFloatValue(m_State.activeRootGameObject, binding, out var value);
+ return value;
+ }
+
+ int IAnimationWindowController.GetIntValue(EditorCurveBinding binding)
+ {
+ if (m_State == null)
+ return default;
+
+ AnimationUtility.GetDiscreteIntValue(m_State.activeRootGameObject, binding, out var value);
+ return value;
+ }
+
+ UnityEngine.Object IAnimationWindowController.GetObjectReferenceValue(EditorCurveBinding binding)
+ {
+ if (m_State == null)
+ return default;
+
+ AnimationUtility.GetObjectReferenceValue(m_State.activeRootGameObject, binding, out var value);
+ return value;
+ }
+
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/IAnimationWindowController.cs b/Editor/Mono/Animation/AnimationWindow/IAnimationWindowController.cs
new file mode 100644
index 0000000000..ced9cb6703
--- /dev/null
+++ b/Editor/Mono/Animation/AnimationWindow/IAnimationWindowController.cs
@@ -0,0 +1,42 @@
+// Unity C# reference source
+// Copyright (c) Unity Technologies. For terms of use, see
+// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+
+using UnityEngine;
+
+namespace UnityEditor
+{
+ interface IAnimationWindowController
+ {
+ void OnCreate(AnimationWindow animationWindow, UnityEngine.Component component);
+ void OnDestroy();
+ void OnSelectionChanged();
+
+ float time { get; set; }
+ int frame { get; set; }
+
+ bool canPlay { get; }
+ bool playing { get; set; }
+
+ bool PlaybackUpdate();
+
+ bool canPreview { get; }
+ bool previewing { get; set; }
+
+ bool canRecord { get; }
+ bool recording { get; set; }
+
+ void ResampleAnimation();
+
+ void ProcessCandidates();
+ void ClearCandidates();
+
+ EditorCurveBinding[] GetAnimatableBindings(GameObject gameObject);
+ EditorCurveBinding[] GetAnimatableBindings();
+ System.Type GetValueType(EditorCurveBinding binding);
+ float GetFloatValue(EditorCurveBinding binding);
+ int GetIntValue(EditorCurveBinding binding);
+ UnityEngine.Object GetObjectReferenceValue(EditorCurveBinding binding);
+
+ }
+}
diff --git a/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs b/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs
index 5b44306564..f1c1306127 100644
--- a/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs
+++ b/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs
@@ -3,7 +3,6 @@
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using System;
-using System.Linq;
using UnityEngine;
namespace UnityEditor
@@ -249,11 +248,12 @@ void UpdateRegionDomain()
{
foreach (var animationCurve in new[] { m_MaxCurve, m_MinCurve })
{
- if (animationCurve.length > 0)
+ var keyCount = animationCurve.length;
+ if (keyCount > 0)
{
var keys = animationCurve.keys;
- domain.x = Mathf.Min(domain.x, keys.First().time);
- domain.y = Math.Max(domain.y, keys.Last().time);
+ domain.x = Mathf.Min(domain.x, animationCurve[0].time);
+ domain.y = Math.Max(domain.y, animationCurve[keyCount - 1].time);
}
}
}
diff --git a/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs b/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs
index ede837fd2c..6c017c2958 100644
--- a/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs
+++ b/Editor/Mono/Animation/AnimationWindow/RotationCurveInterpolation.cs
@@ -225,7 +225,7 @@ static public EditorCurveBinding RemapAnimationBindingForRotationCurves(EditorCu
internal static void SetInterpolation(AnimationClip clip, EditorCurveBinding[] curveBindings, Mode newInterpolationMode)
{
- Undo.RegisterCompleteObjectUndo(clip, "Rotation Interpolation");
+ Undo.RegisterCompleteObjectUndo(clip, L10n.Tr("Rotation Interpolation"));
if (clip.legacy && newInterpolationMode == Mode.RawEuler)
{
@@ -269,7 +269,7 @@ internal static void SetInterpolation(AnimationClip clip, EditorCurveBinding[] c
oldCurvesBindings.Add(removeCurve);
}
- Undo.RegisterCompleteObjectUndo(clip, "Rotation Interpolation");
+ Undo.RegisterCompleteObjectUndo(clip, L10n.Tr("Rotation Interpolation"));
foreach (EditorCurveBinding binding in oldCurvesBindings)
AnimationUtility.SetEditorCurve(clip, binding, null);
diff --git a/Editor/Mono/Animation/AnimatorController.cs b/Editor/Mono/Animation/AnimatorController.cs
index 3330ed6235..f5a2c0e500 100644
--- a/Editor/Mono/Animation/AnimatorController.cs
+++ b/Editor/Mono/Animation/AnimatorController.cs
@@ -2,6 +2,7 @@
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
+using System;
using UnityEngine;
using System.IO;
using System.Collections.Generic;
@@ -60,6 +61,8 @@ public void AddLayer(string name)
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(newLayer.stateMachine, AssetDatabase.GetAssetPath(this));
+ undoHandler.DoUndoCreated(newLayer.stateMachine, "Layer added");
+
AddLayer(newLayer);
}
@@ -79,6 +82,16 @@ internal void RemoveLayers(List layerIndexes)
AnimatorControllerLayer[] layerVector = this.layers;
foreach (var layerIndex in layerIndexes)
{
+ for (var i = 0; i < layerVector.Length; ++i)
+ {
+ var syncedLayerIndex = layerVector[i].syncedLayerIndex;
+ if (syncedLayerIndex > layerIndex)
+ {
+ // synced layer is after the layer being removed, so it's going to be shifted upon removal
+ layerVector[i].syncedLayerIndex = syncedLayerIndex - 1;
+ }
+ }
+
RemoveLayerInternal(layerIndex, ref layerVector);
}
this.layers = layerVector;
@@ -195,6 +208,8 @@ public AnimatorState CreateBlendTreeInController(string name, out BlendTree tree
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(tree, AssetDatabase.GetAssetPath(this));
+ undoHandler.DoUndoCreated(tree, "Blend Tree Created");
+
AnimatorState state = layers[layerIndex].stateMachine.AddState(tree.name);
state.motion = tree;
return state;
@@ -244,7 +259,13 @@ internal static AnimatorController CreateAnimatorControllerForClip(AnimationClip
public static AnimatorController CreateAnimatorControllerAtPathWithClip(string path, AnimationClip clip)
{
AnimatorController controller = CreateAnimatorControllerAtPath(path);
- controller.AddMotion(clip);
+
+ AnimatorStateMachine stateMachine = controller.layers[0].stateMachine;
+ stateMachine.pushUndo = false;
+ var state = stateMachine.AddState(clip.name);
+ state.motion = clip;
+ stateMachine.pushUndo = true;
+
return controller;
}
@@ -255,6 +276,15 @@ public void SetStateEffectiveMotion(AnimatorState state, Motion motion)
public void SetStateEffectiveMotion(AnimatorState state, Motion motion, int layerIndex)
{
+ //delete existing nested blend tree asset
+ Motion selectedMotion = GetStateEffectiveMotion(state, layerIndex);
+ BlendTree blendTree = selectedMotion as BlendTree;
+
+ if (blendTree != null && !AssetDatabase.IsMainAsset(blendTree))
+ {
+ MecanimUtilities.DestroyBlendTreeRecursive(blendTree);
+ }
+
if (layers[layerIndex].syncedLayerIndex == -1)
{
undoHandler.DoUndo(state, "Set Motion");
@@ -276,14 +306,10 @@ public Motion GetStateEffectiveMotion(AnimatorState state)
public Motion GetStateEffectiveMotion(AnimatorState state, int layerIndex)
{
- if (layers[layerIndex].syncedLayerIndex == -1)
- {
- return state.motion;
- }
- else
- {
- return layers[layerIndex].GetOverrideMotion(state);
- }
+ if (layerIndex < 0 || layerIndex > layers.Length)
+ return null;
+
+ return layers[layerIndex].syncedLayerIndex == -1 ? state.motion : layers[layerIndex].GetOverrideMotion(state);
}
public void SetStateEffectiveBehaviours(AnimatorState state, int layerIndex, StateMachineBehaviour[] behaviours)
@@ -302,6 +328,9 @@ public void SetStateEffectiveBehaviours(AnimatorState state, int layerIndex, Sta
public StateMachineBehaviour[] GetStateEffectiveBehaviours(AnimatorState state, int layerIndex)
{
+ if (layerIndex < 0 || layerIndex > layers.Length)
+ return Array.Empty();
+
return Internal_GetEffectiveBehaviours(state, layerIndex) as StateMachineBehaviour[];
}
diff --git a/Editor/Mono/Animation/BlendTree.cs b/Editor/Mono/Animation/BlendTree.cs
index 70ba96bbf2..33619e8979 100644
--- a/Editor/Mono/Animation/BlendTree.cs
+++ b/Editor/Mono/Animation/BlendTree.cs
@@ -80,14 +80,16 @@ internal bool HasChild(BlendTree childTree, bool recursive)
internal BlendTree CreateBlendTreeChild(Vector2 position, float threshold)
{
- Undo.RecordObject(this, "Created BlendTree Child");
-
BlendTree tree = new BlendTree();
tree.name = "BlendTree";
tree.hideFlags = HideFlags.HideInHierarchy;
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(tree, AssetDatabase.GetAssetPath(this));
+ Undo.RegisterCreatedObjectUndo(tree, "Blend Tree Created");
+
+ Undo.RecordObject(this, "Created BlendTree Child");
+
AddChild(tree, position, threshold);
return tree;
}
diff --git a/Editor/Mono/Animation/EditorCurveBinding.bindings.cs b/Editor/Mono/Animation/EditorCurveBinding.bindings.cs
index d6ccd3d822..334acb0ff6 100644
--- a/Editor/Mono/Animation/EditorCurveBinding.bindings.cs
+++ b/Editor/Mono/Animation/EditorCurveBinding.bindings.cs
@@ -8,6 +8,8 @@
using UnityEngine.Playables;
using UnityEngine.Scripting.APIUpdating;
using UnityEngine.Internal;
+using UnityEngine;
+using static UnityEditor.AnimationUtility;
namespace UnityEditor
{
@@ -29,15 +31,24 @@ public struct EditorCurveBinding : IEquatable
//is it a discrete curve
private int m_isDiscreteCurve;
+ //is it a serialize reference curve
+ private int m_isSerializeReferenceCurve;
+
//is it placeholder curve
private int m_isPhantom;
+ //is it a unknown curve: mean it needs to be processed further more to find out what is this curve
+ // This is necessary to support old user code using FloatCurve for non float type
+ private int m_isUnknownCurve;
+
// This is only used internally for deleting curves
internal int m_ClassID;
internal int m_ScriptInstanceID;
public bool isPPtrCurve { get { return m_isPPtrCurve != 0; } }
public bool isDiscreteCurve { get { return m_isDiscreteCurve != 0; } }
+
+ public bool isSerializeReferenceCurve { get { return m_isSerializeReferenceCurve != 0; } }
internal bool isPhantom { get { return m_isPhantom != 0; } set { m_isPhantom = value == true ? 1 : 0; } }
public static bool operator==(EditorCurveBinding lhs, EditorCurveBinding rhs)
@@ -49,7 +60,7 @@ public struct EditorCurveBinding : IEquatable
return false;
}
- return lhs.m_isPPtrCurve == rhs.m_isPPtrCurve && lhs.m_isDiscreteCurve == rhs.m_isDiscreteCurve && lhs.path == rhs.path && lhs.type == rhs.type && lhs.propertyName == rhs.propertyName;
+ return lhs.m_isPPtrCurve == rhs.m_isPPtrCurve && lhs.m_isDiscreteCurve == rhs.m_isDiscreteCurve && lhs.m_isSerializeReferenceCurve == rhs.m_isSerializeReferenceCurve && lhs.path == rhs.path && lhs.type == rhs.type && lhs.propertyName == rhs.propertyName;
}
public static bool operator!=(EditorCurveBinding lhs, EditorCurveBinding rhs)
@@ -93,6 +104,8 @@ static public EditorCurveBinding FloatCurve(string inPath, System.Type inType, s
BaseCurve(inPath, inType, inPropertyName, out binding);
binding.m_isPPtrCurve = 0;
binding.m_isDiscreteCurve = 0;
+ binding.m_isSerializeReferenceCurve = 0;
+ binding.m_isUnknownCurve = 1;
return binding;
}
@@ -103,6 +116,8 @@ static public EditorCurveBinding PPtrCurve(string inPath, System.Type inType, st
BaseCurve(inPath, inType, inPropertyName, out binding);
binding.m_isPPtrCurve = 1;
binding.m_isDiscreteCurve = 1;
+ binding.m_isSerializeReferenceCurve = 0;
+ binding.m_isUnknownCurve = 0;
return binding;
}
@@ -112,6 +127,31 @@ static public EditorCurveBinding DiscreteCurve(string inPath, System.Type inType
BaseCurve(inPath, inType, inPropertyName, out binding);
binding.m_isPPtrCurve = 0;
binding.m_isDiscreteCurve = 1;
+ binding.m_isSerializeReferenceCurve = 0;
+ binding.m_isUnknownCurve = 0;
+
+ DiscreteBindingResult result = AnimationUtility.IsDiscreteIntBinding(binding);
+ if (result == DiscreteBindingResult.IncompatibleFieldType || result == DiscreteBindingResult.MissingDiscreteAttribute)
+ {
+ Debug.LogWarning(
+ $"Property [" + inPropertyName + "] is not a supported discrete curve binding. " +
+ "Discrete curves only support [" + typeof(Enum) + "] and [" + typeof(int) + " with the `DiscreteEvaluation` attribute].");
+
+ binding.m_isDiscreteCurve = 0;
+ binding.m_isUnknownCurve = 1;
+ }
+
+ return binding;
+ }
+
+ static public EditorCurveBinding SerializeReferenceCurve(string inPath, System.Type inType, long refID, string inPropertyName, bool isPPtr, bool isDiscrete)
+ {
+ EditorCurveBinding binding;
+ BaseCurve(inPath, inType, $"managedReferences[{refID}].{inPropertyName}", out binding);
+ binding.m_isPPtrCurve = isPPtr ? 1 : 0;
+ binding.m_isDiscreteCurve = isDiscrete || isPPtr ? 1 : 0;
+ binding.m_isSerializeReferenceCurve = 1;
+ binding.m_isUnknownCurve = 0;
return binding;
}
diff --git a/Editor/Mono/Animation/MaterialAnimationUtility.cs b/Editor/Mono/Animation/MaterialAnimationUtility.cs
index d31ce0aacc..27cfc5e01d 100644
--- a/Editor/Mono/Animation/MaterialAnimationUtility.cs
+++ b/Editor/Mono/Animation/MaterialAnimationUtility.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
+using ShaderPropertyType = UnityEngine.Rendering.ShaderPropertyType;
using Object = UnityEngine.Object;
namespace UnityEditorInternal
@@ -63,16 +64,17 @@ static PropertyModification[] MaterialPropertyToPropertyModifications(string nam
return modifications;
}
- static bool ApplyMaterialModificationToAnimationRecording(PropertyModification[] modifications)
+ static bool ApplyMaterialModificationToAnimationRecording(PropertyModification[] previousModifications, PropertyModification[] currentModifications)
{
- UndoPropertyModification[] undoModifications = new UndoPropertyModification[modifications.Length];
+ UndoPropertyModification[] undoModifications = new UndoPropertyModification[previousModifications.Length];
for (int i = 0; i < undoModifications.Length; ++i)
{
- undoModifications[i].previousValue = modifications[i];
+ undoModifications[i].previousValue = previousModifications[i];
+ undoModifications[i].currentValue = currentModifications[i];
}
UndoPropertyModification[] ret = Undo.InvokePostprocessModifications(undoModifications);
- return ret.Length != modifications.Length;
+ return ret.Length != undoModifications.Length;
}
static public bool OverridePropertyColor(MaterialProperty materialProp, Renderer target, out Color color)
@@ -80,20 +82,27 @@ static public bool OverridePropertyColor(MaterialProperty materialProp, Renderer
var propertyPaths = new List();
string basePropertyPath = kMaterialPrefix + materialProp.name;
- if (materialProp.type == MaterialProperty.PropType.Texture)
+ if (materialProp.propertyType == ShaderPropertyType.Texture)
{
propertyPaths.Add(basePropertyPath + "_ST.x");
propertyPaths.Add(basePropertyPath + "_ST.y");
propertyPaths.Add(basePropertyPath + "_ST.z");
propertyPaths.Add(basePropertyPath + "_ST.w");
}
- else if (materialProp.type == MaterialProperty.PropType.Color)
+ else if (materialProp.propertyType == ShaderPropertyType.Color)
{
propertyPaths.Add(basePropertyPath + ".r");
propertyPaths.Add(basePropertyPath + ".g");
propertyPaths.Add(basePropertyPath + ".b");
propertyPaths.Add(basePropertyPath + ".a");
}
+ else if (materialProp.propertyType == ShaderPropertyType.Vector)
+ {
+ propertyPaths.Add(basePropertyPath + ".x");
+ propertyPaths.Add(basePropertyPath + ".y");
+ propertyPaths.Add(basePropertyPath + ".z");
+ propertyPaths.Add(basePropertyPath + ".w");
+ }
else
{
propertyPaths.Add(basePropertyPath);
@@ -130,37 +139,37 @@ static public void TearDownMaterialPropertyBlock(Renderer target)
static public bool ApplyMaterialModificationToAnimationRecording(MaterialProperty materialProp, int changedMask, Renderer target, object oldValue)
{
bool applied = false;
- switch (materialProp.type)
+ switch (materialProp.propertyType)
{
- case MaterialProperty.PropType.Color:
+ case ShaderPropertyType.Color:
SetupMaterialPropertyBlock(materialProp, changedMask, target);
- applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(materialProp, target, (Color)oldValue));
+ applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(materialProp, target, (Color)oldValue), MaterialPropertyToPropertyModifications(materialProp, target, materialProp.colorValue));
if (!applied)
TearDownMaterialPropertyBlock(target);
return applied;
- case MaterialProperty.PropType.Vector:
+ case ShaderPropertyType.Vector:
SetupMaterialPropertyBlock(materialProp, changedMask, target);
- applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(materialProp, target, (Vector4)oldValue));
+ applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(materialProp, target, (Vector4)oldValue), MaterialPropertyToPropertyModifications(materialProp, target, materialProp.vectorValue));
if (!applied)
TearDownMaterialPropertyBlock(target);
return applied;
- case MaterialProperty.PropType.Float:
- case MaterialProperty.PropType.Range:
+ case ShaderPropertyType.Float:
+ case ShaderPropertyType.Range:
SetupMaterialPropertyBlock(materialProp, changedMask, target);
- applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(materialProp, target, (float)oldValue));
+ applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(materialProp, target, (float)oldValue), MaterialPropertyToPropertyModifications(materialProp, target, materialProp.floatValue));
if (!applied)
TearDownMaterialPropertyBlock(target);
return applied;
- case MaterialProperty.PropType.Texture:
+ case ShaderPropertyType.Texture:
{
if (MaterialProperty.IsTextureOffsetAndScaleChangedMask(changedMask))
{
string name = materialProp.name + "_ST";
SetupMaterialPropertyBlock(materialProp, changedMask, target);
- applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(name, target, (Vector4)oldValue));
+ applied = ApplyMaterialModificationToAnimationRecording(MaterialPropertyToPropertyModifications(name, target, (Vector4)oldValue), MaterialPropertyToPropertyModifications(name, target, materialProp.textureScaleAndOffset));
if (!applied)
TearDownMaterialPropertyBlock(target);
return applied;
@@ -175,17 +184,17 @@ static public bool ApplyMaterialModificationToAnimationRecording(MaterialPropert
static public PropertyModification[] MaterialPropertyToPropertyModifications(MaterialProperty materialProp, Renderer target)
{
- switch (materialProp.type)
+ switch (materialProp.propertyType)
{
- case MaterialProperty.PropType.Color:
+ case ShaderPropertyType.Color:
return MaterialPropertyToPropertyModifications(materialProp, target, materialProp.colorValue);
- case MaterialProperty.PropType.Vector:
+ case ShaderPropertyType.Vector:
return MaterialPropertyToPropertyModifications(materialProp, target, materialProp.vectorValue);
- case MaterialProperty.PropType.Float:
- case MaterialProperty.PropType.Range:
+ case ShaderPropertyType.Float:
+ case ShaderPropertyType.Range:
return MaterialPropertyToPropertyModifications(materialProp, target, materialProp.floatValue);
- case MaterialProperty.PropType.Texture:
+ case ShaderPropertyType.Texture:
{
string name = materialProp.name + "_ST";
return MaterialPropertyToPropertyModifications(name, target, materialProp.vectorValue);
diff --git a/Editor/Mono/Animation/StateMachine.cs b/Editor/Mono/Animation/StateMachine.cs
index 6fbe2217fd..7a0a5c021d 100644
--- a/Editor/Mono/Animation/StateMachine.cs
+++ b/Editor/Mono/Animation/StateMachine.cs
@@ -27,6 +27,11 @@ public void DoUndo(Object target, string undoOperation)
impl.DoUndo(target, undoOperation);
}
+ public void DoUndoCreated(Object target, string undoOperation)
+ {
+ impl.DoUndoCreated(target, undoOperation);
+ }
+
PushUndoIfNeededImpl impl
{
get
@@ -54,6 +59,14 @@ public void DoUndo(Object target, string undoOperation)
}
}
+ public void DoUndoCreated(Object target, string undoOperation)
+ {
+ if (m_PushUndo)
+ {
+ Undo.RegisterCreatedObjectUndo(target, undoOperation);
+ }
+ }
+
public bool m_PushUndo;
}
}
@@ -87,11 +100,12 @@ public void RemoveCondition(AnimatorCondition condition)
}
}
-
+ [HelpURL("StateMachineTransitions")]
internal class AnimatorDefaultTransition : ScriptableObject
{
}
+ [HelpURL("class-State")]
public partial class AnimatorState : Object
{
private PushUndoIfNeeded undoHandler = new PushUndoIfNeeded(true);
@@ -128,6 +142,8 @@ private AnimatorStateTransition CreateTransition(bool setDefaultExitTime)
AssetDatabase.AddObjectToAsset(newTransition, AssetDatabase.GetAssetPath(this));
newTransition.hideFlags = HideFlags.HideInHierarchy;
+ undoHandler.DoUndoCreated(newTransition, "Transition Created");
+
if (setDefaultExitTime)
SetDefaultTransitionExitTime(ref newTransition);
@@ -227,6 +243,7 @@ public int uniqueNameHash
}
}
+ [HelpURL("NestedStateMachines")]
public partial class AnimatorStateMachine : Object
{
private PushUndoIfNeeded undoHandler = new PushUndoIfNeeded(true);
@@ -377,6 +394,8 @@ public AnimatorState AddState(string name, Vector3 position)
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(state, AssetDatabase.GetAssetPath(this));
+ undoHandler.DoUndoCreated(state, "State Created");
+
AddState(state, position);
return state;
@@ -392,6 +411,7 @@ public void AddState(AnimatorState state, Vector3 position)
}
undoHandler.DoUndo(this, "State added");
+
ChildAnimatorState newState = new ChildAnimatorState();
newState.state = state;
newState.position = position;
@@ -423,6 +443,8 @@ public AnimatorStateMachine AddStateMachine(string name, Vector3 position)
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(stateMachine, AssetDatabase.GetAssetPath(this));
+ undoHandler.DoUndoCreated(stateMachine, "StateMachine Created");
+
return stateMachine;
}
@@ -453,23 +475,24 @@ public void RemoveStateMachine(AnimatorStateMachine stateMachine)
private AnimatorStateTransition AddAnyStateTransition()
{
- undoHandler.DoUndo(this, "AnyState Transition Added");
-
- AnimatorStateTransition[] transitionsVector = anyStateTransitions;
AnimatorStateTransition newTransition = new AnimatorStateTransition();
newTransition.hasExitTime = false;
newTransition.hasFixedDuration = true;
newTransition.duration = 0.25f;
newTransition.exitTime = 0.75f;
+ newTransition.hideFlags = HideFlags.HideInHierarchy;
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(newTransition, AssetDatabase.GetAssetPath(this));
- newTransition.hideFlags = HideFlags.HideInHierarchy;
+ undoHandler.DoUndoCreated(newTransition, "AnyState Transition Created");
+
+ undoHandler.DoUndo(this, "AnyState Transition Added");
+
+ AnimatorStateTransition[] transitionsVector = anyStateTransitions;
ArrayUtility.Add(ref transitionsVector, newTransition);
anyStateTransitions = transitionsVector;
-
return newTransition;
}
@@ -521,42 +544,48 @@ internal void RemoveAnyStateTransitionRecursive(AnimatorStateTransition transiti
public AnimatorTransition AddStateMachineTransition(AnimatorStateMachine sourceStateMachine)
{
- AnimatorStateMachine sm = null;
- return AddStateMachineTransition(sourceStateMachine, sm);
+ AnimatorTransition newTransition = new AnimatorTransition();
+ AddStateMachineTransition(sourceStateMachine, newTransition);
+ return newTransition;
}
public AnimatorTransition AddStateMachineTransition(AnimatorStateMachine sourceStateMachine, AnimatorStateMachine destinationStateMachine)
{
- undoHandler.DoUndo(this, "StateMachine Transition Added");
-
- AnimatorTransition[] transitionsVector = GetStateMachineTransitions(sourceStateMachine);
- AnimatorTransition newTransition = new AnimatorTransition();
- if (destinationStateMachine)
- {
- newTransition.destinationStateMachine = destinationStateMachine;
- }
-
- if (AssetDatabase.GetAssetPath(this) != "")
- AssetDatabase.AddObjectToAsset(newTransition, AssetDatabase.GetAssetPath(this));
-
- newTransition.hideFlags = HideFlags.HideInHierarchy;
- ArrayUtility.Add(ref transitionsVector, newTransition);
- SetStateMachineTransitions(sourceStateMachine, transitionsVector);
-
+ var newTransition = new AnimatorTransition();
+ newTransition.destinationStateMachine = destinationStateMachine;
+ AddStateMachineTransition(sourceStateMachine, newTransition);
return newTransition;
}
public AnimatorTransition AddStateMachineTransition(AnimatorStateMachine sourceStateMachine, AnimatorState destinationState)
{
- AnimatorTransition newTransition = AddStateMachineTransition(sourceStateMachine);
+ var newTransition = new AnimatorTransition();
newTransition.destinationState = destinationState;
+ AddStateMachineTransition(sourceStateMachine, newTransition);
return newTransition;
}
+ internal void AddStateMachineTransition(AnimatorStateMachine sourceStateMachine, AnimatorTransition transition)
+ {
+ transition.hideFlags = HideFlags.HideInHierarchy;
+
+ if (AssetDatabase.GetAssetPath(this) != "")
+ AssetDatabase.AddObjectToAsset(transition, AssetDatabase.GetAssetPath(this));
+
+ undoHandler.DoUndoCreated(transition, "StateMachine Transition Created");
+
+ undoHandler.DoUndo(this, "StateMachine Transition Added");
+
+ AnimatorTransition[] transitionsVector = GetStateMachineTransitions(sourceStateMachine);
+ ArrayUtility.Add(ref transitionsVector, transition);
+ SetStateMachineTransitions(sourceStateMachine, transitionsVector);
+ }
+
public AnimatorTransition AddStateMachineExitTransition(AnimatorStateMachine sourceStateMachine)
{
- AnimatorTransition newTransition = AddStateMachineTransition(sourceStateMachine);
+ var newTransition = new AnimatorTransition();
newTransition.isExit = true;
+ AddStateMachineTransition(sourceStateMachine, newTransition);
return newTransition;
}
@@ -577,14 +606,16 @@ public bool RemoveStateMachineTransition(AnimatorStateMachine sourceStateMachine
private AnimatorTransition AddEntryTransition()
{
- undoHandler.DoUndo(this, "Entry Transition Added");
- AnimatorTransition[] transitionsVector = entryTransitions;
AnimatorTransition newTransition = new AnimatorTransition();
+ newTransition.hideFlags = HideFlags.HideInHierarchy;
if (AssetDatabase.GetAssetPath(this) != "")
AssetDatabase.AddObjectToAsset(newTransition, AssetDatabase.GetAssetPath(this));
- newTransition.hideFlags = HideFlags.HideInHierarchy;
+ undoHandler.DoUndoCreated(newTransition, "Entry Transition Created");
+
+ undoHandler.DoUndo(this, "Entry Transition Added");
+ AnimatorTransition[] transitionsVector = entryTransitions;
ArrayUtility.Add(ref transitionsVector, newTransition);
entryTransitions = transitionsVector;
diff --git a/Editor/Mono/Animation/TickHandler.cs b/Editor/Mono/Animation/TickHandler.cs
index 270854c65b..e5fa350ab7 100644
--- a/Editor/Mono/Animation/TickHandler.cs
+++ b/Editor/Mono/Animation/TickHandler.cs
@@ -190,7 +190,11 @@ public int GetLevelWithMinSeparation(float pixelSeparation)
public void SetTickStrengths(float tickMinSpacing, float tickMaxSpacing, bool sqrt)
{
- m_TickStrengths = new float[m_TickModulos.Length];
+ if (m_TickStrengths == null || m_TickStrengths.Length != m_TickModulos.Length)
+ {
+ m_TickStrengths = new float[m_TickModulos.Length];
+ }
+
m_SmallestTick = 0;
m_BiggestTick = m_TickModulos.Length - 1;
diff --git a/Editor/Mono/Animation/TimeArea.cs b/Editor/Mono/Animation/TimeArea.cs
index 829a93691c..d64fe78d23 100644
--- a/Editor/Mono/Animation/TimeArea.cs
+++ b/Editor/Mono/Animation/TimeArea.cs
@@ -21,7 +21,7 @@ public TickHandler hTicks
[SerializeField] private TickHandler m_VTicks;
- private List m_TickCache = new List(1000);
+ static readonly List s_TickCache = new List(1000);
public TickHandler vTicks
{
@@ -114,12 +114,12 @@ public void DrawMajorTicks(Rect position, float frameRate)
float strength = hTicks.GetStrengthOfLevel(l) * .9f;
if (strength > kTickRulerFatThreshold)
{
- m_TickCache.Clear();
- hTicks.GetTicksAtLevel(l, true, m_TickCache);
- for (int i = 0; i < m_TickCache.Count; i++)
+ s_TickCache.Clear();
+ hTicks.GetTicksAtLevel(l, true, s_TickCache);
+ for (int i = 0; i < s_TickCache.Count; i++)
{
- if (m_TickCache[i] < 0) continue;
- int frame = Mathf.RoundToInt(m_TickCache[i] * frameRate);
+ if (s_TickCache[i] < 0) continue;
+ int frame = Mathf.RoundToInt(s_TickCache[i] * frameRate);
float x = FrameToPixel(frame, frameRate, position, theShowArea);
// Draw line
DrawVerticalLineFast(x, 0.0f, position.height, tickColor);
@@ -166,13 +166,13 @@ public void TimeRuler(Rect position, float frameRate, bool labels, bool useEntir
for (int l = 0; l < hTicks.tickLevels; l++)
{
float strength = hTicks.GetStrengthOfLevel(l) * .9f;
- m_TickCache.Clear();
- hTicks.GetTicksAtLevel(l, true, m_TickCache);
- for (int i = 0; i < m_TickCache.Count; i++)
+ s_TickCache.Clear();
+ hTicks.GetTicksAtLevel(l, true, s_TickCache);
+ for (int i = 0; i < s_TickCache.Count; i++)
{
- if (m_TickCache[i] < hRangeMin || m_TickCache[i] > hRangeMax)
+ if (s_TickCache[i] < hRangeMin || s_TickCache[i] > hRangeMax)
continue;
- int frame = Mathf.RoundToInt(m_TickCache[i] * frameRate);
+ int frame = Mathf.RoundToInt(s_TickCache[i] * frameRate);
float height = useEntireHeight
? position.height
@@ -192,19 +192,19 @@ public void TimeRuler(Rect position, float frameRate, bool labels, bool useEntir
{
// Draw tick labels
int labelLevel = hTicks.GetLevelWithMinSeparation(kTickRulerDistLabel);
- m_TickCache.Clear();
- hTicks.GetTicksAtLevel(labelLevel, false, m_TickCache);
- for (int i = 0; i < m_TickCache.Count; i++)
+ s_TickCache.Clear();
+ hTicks.GetTicksAtLevel(labelLevel, false, s_TickCache);
+ for (int i = 0; i < s_TickCache.Count; i++)
{
- if (m_TickCache[i] < hRangeMin || m_TickCache[i] > hRangeMax)
+ if (s_TickCache[i] < hRangeMin || s_TickCache[i] > hRangeMax)
continue;
- int frame = Mathf.RoundToInt(m_TickCache[i] * frameRate);
+ int frame = Mathf.RoundToInt(s_TickCache[i] * frameRate);
// Important to take floor of positions of GUI stuff to get pixel correct alignment of
// stuff drawn with both GUI and Handles/GL. Otherwise things are off by one pixel half the time.
float labelpos = Mathf.Floor(FrameToPixel(frame, frameRate, position));
- string label = FormatTickTime(m_TickCache[i], frameRate, timeFormat);
+ string label = FormatTickTime(s_TickCache[i], frameRate, timeFormat);
GUI.Label(new Rect(labelpos + 3, -1, 40, 20), label, timeAreaStyles.timelineTick);
}
}
diff --git a/Editor/Mono/Animation/TransitionPreview.cs b/Editor/Mono/Animation/TransitionPreview.cs
index da4a2629d2..6b26f509e6 100644
--- a/Editor/Mono/Animation/TransitionPreview.cs
+++ b/Editor/Mono/Animation/TransitionPreview.cs
@@ -36,6 +36,7 @@ internal class TransitionPreview
private bool m_MustResample = true;
private bool m_MustSampleMotions = false;
+ private bool m_MustResetParameterInfoList = false;
public bool mustResample { set { m_MustResample = value; } get { return m_MustResample; } }
private float m_LastEvalTime = -1.0f;
private bool m_IsResampling = false;
@@ -268,7 +269,7 @@ private void ResampleTransition(AnimatorStateTransition transition, AvatarMask l
AnimatorStateInfo currentState = m_AvatarPreview.Animator.GetCurrentAnimatorStateInfo(m_LayerIndex);
m_LeftStateWeightA = currentState.normalizedTime;
m_LeftStateTimeA = currentTime;
- while (!hasFinished && currentTime < maxDuration)
+ while (!hasFinished)
{
m_AvatarPreview.Animator.Update(stepTime);
@@ -302,7 +303,7 @@ private void ResampleTransition(AnimatorStateTransition transition, AvatarMask l
m_LeftStateTimeB = currentTime;
}
- if (hasTransitioned)
+ if (hasTransitioned || hasFinished)
{
m_RightStateWeightB = currentState.normalizedTime;
m_RightStateTimeB = currentTime;
@@ -328,6 +329,11 @@ private void ResampleTransition(AnimatorStateTransition transition, AvatarMask l
float leftDuration = (m_LeftStateTimeB - m_LeftStateTimeA) / (m_LeftStateWeightB - m_LeftStateWeightA);
float rightDuration = (m_RightStateTimeB - m_RightStateTimeA) / (m_RightStateWeightB - m_RightStateWeightA);
+ // Ensure step times make sense based on these timings
+ // If step time is too small, the samping will take too long
+ currentStateStepTime = Mathf.Max(currentStateStepTime, leftDuration / 600.0f);
+ nextStateStepTime = Mathf.Max(nextStateStepTime, rightDuration / 600.0f);
+
if (m_MustSampleMotions)
{
// Do this as infrequently as possible
@@ -398,6 +404,8 @@ private void ResampleTransition(AnimatorStateTransition transition, AvatarMask l
public void SetTransition(AnimatorStateTransition transition, AnimatorState sourceState, AnimatorState destinationState, AnimatorControllerLayer srcLayer, Animator previewObject)
{
m_RefSrcState = sourceState;
+ m_MustResetParameterInfoList = m_RefDstState != destinationState;
+
m_RefDstState = destinationState;
TransitionInfo info = new TransitionInfo();
info.Set(transition, sourceState, destinationState);
@@ -589,10 +597,12 @@ private void Init(Animator scenePreviewObject, Motion motion)
CreateController();
- if (m_ParameterInfoList == null)
+ if(m_ParameterInfoList == null || m_MustResetParameterInfoList)
{
+ m_MustResetParameterInfoList = false;
CreateParameterInfoList();
}
+
}
public void DoTransitionPreview()
@@ -600,9 +610,6 @@ public void DoTransitionPreview()
if (m_Controller == null)
return;
- if (Event.current.type == EventType.Repaint)
- m_AvatarPreview.timeControl.Update();
-
DoTimeline();
// Draw the blend values
@@ -721,7 +728,12 @@ public void OnInteractivePreviewGUI(Rect r, GUIStyle background)
{
if (m_AvatarPreview != null && m_Controller != null)
{
- if (m_LastEvalTime != m_AvatarPreview.timeControl.currentTime && Event.current.type == EventType.Repaint)
+ bool isRepaint = (Event.current.type == EventType.Repaint);
+
+ if (isRepaint)
+ m_AvatarPreview.timeControl.Update();
+
+ if (m_LastEvalTime != m_AvatarPreview.timeControl.currentTime && isRepaint)
{
m_AvatarPreview.Animator.playbackTime = m_AvatarPreview.timeControl.currentTime;
m_AvatarPreview.Animator.Update(0);
diff --git a/Editor/Mono/Animation/ZoomableArea.cs b/Editor/Mono/Animation/ZoomableArea.cs
index 4685bc4e13..b93187d184 100644
--- a/Editor/Mono/Animation/ZoomableArea.cs
+++ b/Editor/Mono/Animation/ZoomableArea.cs
@@ -85,9 +85,27 @@ private void SetAllowExceed(ref float rangeEnd, ref bool allowExceed, float valu
private float m_VScaleMin = kMinScale;
private float m_VScaleMax = kMaxScale;
- private const float kMinWidth = 0.05f;
+ private float m_MinWidth = 0.05f;
private const float kMinHeight = 0.05f;
+ private const float k_ScrollStepSize = 10f; // mirrors GUI scrollstepsize as there is no global const for this.
+
+ public float minWidth
+ {
+ get { return m_MinWidth; }
+ set
+ {
+ if (value > 0)
+ m_MinWidth = value;
+ else
+ {
+ Debug.LogWarning("Zoomable area width cannot have a value of " +
+ "or below 0. Reverting back to a default value of 0.05f");
+ m_MinWidth = 0.05f;
+ }
+ }
+ }
+
public float hScaleMin
{
get { return m_HScaleMin; }
@@ -352,10 +370,10 @@ public Rect rect
public void SetShownHRangeInsideMargins(float min, float max)
{
float widthInsideMargins = drawRect.width - leftmargin - rightmargin;
- if (widthInsideMargins < kMinWidth) widthInsideMargins = kMinWidth;
+ if (widthInsideMargins < m_MinWidth) widthInsideMargins = m_MinWidth;
float denum = max - min;
- if (denum < kMinWidth) denum = kMinWidth;
+ if (denum < m_MinWidth) denum = m_MinWidth;
m_Scale.x = widthInsideMargins / denum;
@@ -366,7 +384,7 @@ public void SetShownHRangeInsideMargins(float min, float max)
public void SetShownHRange(float min, float max)
{
float denum = max - min;
- if (denum < kMinWidth) denum = kMinWidth;
+ if (denum < m_MinWidth) denum = m_MinWidth;
m_Scale.x = drawRect.width / denum;
@@ -418,7 +436,7 @@ public Rect shownArea
{
set
{
- float width = (value.width < kMinWidth) ? kMinWidth : value.width;
+ float width = (value.width < m_MinWidth) ? m_MinWidth : value.width;
float height = (value.height < kMinHeight) ? kMinHeight : value.height;
if (m_UpDirection == YDirection.Positive)
@@ -477,11 +495,11 @@ private Rect shownAreaInsideMarginsInternal
{
set
{
- float width = (value.width < kMinWidth) ? kMinWidth : value.width;
+ float width = (value.width < m_MinWidth) ? m_MinWidth : value.width;
float height = (value.height < kMinHeight) ? kMinHeight : value.height;
float widthInsideMargins = drawRect.width - leftmargin - rightmargin;
- if (widthInsideMargins < kMinWidth) widthInsideMargins = kMinWidth;
+ if (widthInsideMargins < m_MinWidth) widthInsideMargins = m_MinWidth;
float heightInsideMargins = drawRect.height - topmargin - bottommargin;
if (heightInsideMargins < kMinHeight) heightInsideMargins = kMinHeight;
@@ -519,9 +537,9 @@ private Rect shownAreaInsideMarginsInternal
float GetWidthInsideMargins(float widthWithMargins, bool substractSliderWidth = false)
{
- float width = (widthWithMargins < kMinWidth) ? kMinWidth : widthWithMargins;
+ float width = (widthWithMargins < m_MinWidth) ? m_MinWidth : widthWithMargins;
float widthInsideMargins = width - leftmargin - rightmargin - (substractSliderWidth ? (m_VSlider ? styles.visualSliderWidth : 0) : 0);
- return Mathf.Max(widthInsideMargins, kMinWidth);
+ return Mathf.Max(widthInsideMargins, m_MinWidth);
}
float GetHeightInsideMargins(float heightWithMargins, bool substractSliderHeight = false)
@@ -696,7 +714,11 @@ public void HandleZoomAndPanEvents(Rect area)
break;
case EventType.ScrollWheel:
if (!area.Contains(Event.current.mousePosition))
+ {
+ HandleScrolling(area);
break;
+ }
+
if (m_IgnoreScrollWheelUntilClicked && GUIUtility.keyboardControl != id)
break;
@@ -709,6 +731,24 @@ public void HandleZoomAndPanEvents(Rect area)
GUILayout.EndArea();
}
+ void HandleScrolling(Rect area)
+ {
+ if (m_MinimalGUI)
+ return;
+ if (m_VSlider && new Rect(area.x + area.width, area.y + GUI.skin.verticalScrollbarUpButton.fixedHeight, vSliderWidth, area.height - (GUI.skin.verticalScrollbarDownButton.fixedHeight + hSliderHeight)).Contains(Event.current.mousePosition))
+ {
+ SetTransform(new Vector2(m_Translation.x, m_Translation.y - (Event.current.delta.y * k_ScrollStepSize)), m_Scale);
+ Event.current.Use();
+ return;
+ }
+
+ if (m_HSlider && new Rect(area.x + GUI.skin.horizontalScrollbarLeftButton.fixedWidth, area.y + area.height, area.width - (GUI.skin.horizontalScrollbarRightButton.fixedWidth + vSliderWidth), hSliderHeight).Contains(Event.current.mousePosition))
+ {
+ SetTransform(new Vector2(m_Translation.x + (Event.current.delta.y * k_ScrollStepSize), m_Translation.y), m_Scale);
+ Event.current.Use();
+ }
+ }
+
public void EndViewGUI()
{
if (m_MinimalGUI && Event.current.type == EventType.Repaint)
@@ -867,7 +907,7 @@ private void HandleZoomEvent(Vector2 zoomAround, bool scrollwhell)
// Cap scale when at min width to not "glide" away when zooming closer
float width = shownAreaInsideMargins.width;
- if (width / scale <= kMinWidth)
+ if (width / scale <= m_MinWidth)
return;
SetScaleFocused(zoomAround, scale * m_Scale, Event.current.shift, EditorGUI.actionKey);
@@ -947,7 +987,7 @@ public void EnforceScaleAndRange()
{
// range only has an influence if it is enforced, i.e. not infinity
float denum = hRangeMax - hRangeMin;
- if (denum < kMinWidth) denum = kMinWidth;
+ if (denum < m_MinWidth) denum = m_MinWidth;
constrainedWidth = Mathf.Min(constrainedWidth, denum);
}
diff --git a/Editor/Mono/AnimatorController.bindings.cs b/Editor/Mono/AnimatorController.bindings.cs
index 46d865b2ac..49b5dce79c 100644
--- a/Editor/Mono/AnimatorController.bindings.cs
+++ b/Editor/Mono/AnimatorController.bindings.cs
@@ -33,6 +33,7 @@ extern public AnimatorControllerLayer[] layers
[FreeFunction(Name = "AnimatorControllerBindings::GetLayers", HasExplicitThis = true)]
get;
[FreeFunction(Name = "AnimatorControllerBindings::SetLayers", HasExplicitThis = true, ThrowsException = true)]
+ [param: Unmarshalled]
set;
}
@@ -41,6 +42,7 @@ extern public AnimatorControllerParameter[] parameters
[FreeFunction(Name = "AnimatorControllerBindings::GetParameters", HasExplicitThis = true)]
get;
[FreeFunction(Name = "AnimatorControllerBindings::SetParameters", HasExplicitThis = true, ThrowsException = true)]
+ [param: Unmarshalled]
set;
}
@@ -87,7 +89,7 @@ static public StateMachineBehaviourContext[] FindStateMachineBehaviourContext(St
extern internal MonoScript GetBehaviourMonoScript(AnimatorState state, int layerIndex, int behaviourIndex);
[FreeFunction]
- extern private static ScriptableObject ScriptingAddStateMachineBehaviourWithType(Type stateMachineBehaviourType, AnimatorController controller, AnimatorState state, int layerIndex);
+ extern private static ScriptableObject ScriptingAddStateMachineBehaviourWithType(Type stateMachineBehaviourType, [NotNull] AnimatorController controller, [NotNull] AnimatorState state, int layerIndex);
[TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)]
@@ -133,6 +135,6 @@ internal extern bool isAssetBundled
extern internal ScriptableObject[] Internal_GetEffectiveBehaviours([NotNull] AnimatorState state, int layerIndex);
[FreeFunction(Name = "AnimatorControllerBindings::Internal_SetEffectiveBehaviours", HasExplicitThis = true)]
- extern internal void Internal_SetEffectiveBehaviours([NotNull] AnimatorState state, int layerIndex, ScriptableObject[] behaviours);
+ extern internal void Internal_SetEffectiveBehaviours([NotNull] AnimatorState state, int layerIndex, [Unmarshalled] ScriptableObject[] behaviours);
}
}
diff --git a/Editor/Mono/Annotation/AnnotationUtility.bindings.cs b/Editor/Mono/Annotation/AnnotationUtility.bindings.cs
index adf769c77a..1efe191cbc 100644
--- a/Editor/Mono/Annotation/AnnotationUtility.bindings.cs
+++ b/Editor/Mono/Annotation/AnnotationUtility.bindings.cs
@@ -3,13 +3,12 @@
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using System;
-using System.Runtime.InteropServices;
using UnityEngine.Bindings;
namespace UnityEditor
{
[NativeType(CodegenOptions.Custom, "AnnotationBindings")]
- internal partial struct Annotation
+ struct Annotation
{
public int iconEnabled;
public int gizmoEnabled;
@@ -19,13 +18,23 @@ internal partial struct Annotation
}
[NativeHeader("Editor/Mono/Annotation/AnnotationUtility.bindings.h")]
- [NativeHeader("Editor/Src/AnnotationManager.h")]
- internal sealed partial class AnnotationUtility
+ [NativeHeader("Editor/Src/Gizmos/AnnotationManager.h")]
+ static class AnnotationUtility
{
+ // Similar values as in Annotation (in AnnotationManager.h)
+ public enum Flags
+ {
+ kHasIcon = 1 << 0,
+ kHasGizmo = 1 << 1,
+ kIsDisabled = 1 << 2
+ };
+
extern internal static Annotation[] GetAnnotations();
extern internal static Annotation[] GetRecentlyChangedAnnotations();
+ extern internal static Annotation GetAnnotation(int classID, string scriptClass);
+
[StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)]
extern internal static string GetNameOfCurrentSetup();
@@ -69,5 +78,14 @@ internal sealed partial class AnnotationUtility
[StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)]
internal extern static float iconSize { get; set; }
+
+ [StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)]
+ internal extern static float fadeGizmoSize { get; set; }
+
+ [StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)]
+ internal extern static bool fadeGizmos { get; set; }
+
+ [StaticAccessor("GetAnnotationManager()", StaticAccessorType.Dot)]
+ internal extern static bool useInspectorExpandedState { get; set; }
}
}
diff --git a/Editor/Mono/Annotation/AnnotationWindow.cs b/Editor/Mono/Annotation/AnnotationWindow.cs
index ed885a0b41..8442759474 100644
--- a/Editor/Mono/Annotation/AnnotationWindow.cs
+++ b/Editor/Mono/Annotation/AnnotationWindow.cs
@@ -4,16 +4,24 @@
using UnityEngine;
using System.Collections.Generic;
-using System.Globalization;
+using UnityEditor.ShortcutManagement;
namespace UnityEditor
{
internal class AnnotationWindow : EditorWindow
{
+ private static SavedBool s_ShowTerrainDebugWarnings = new SavedBool("Terrain.ShowDebugWarnings", true);
+
+ public static bool ShowTerrainDebugWarnings
+ {
+ get => s_ShowTerrainDebugWarnings.value;
+ set => s_ShowTerrainDebugWarnings.value = value;
+ }
+
class Styles
{
public GUIStyle toggle = "Toggle";
- public GUIStyle toggleMixed = "ToggleMixed";
+ public GUIStyle toggleMixed = EditorStyles.toggleMixed;
public GUIStyle listEvenBg = "ObjectPickerResultsOdd";//"ObjectPickerResultsEven";//
public GUIStyle listOddBg = "ObjectPickerResultsEven";//"ObjectPickerResultsEven";//
public GUIStyle background = "grey_border";
@@ -21,7 +29,6 @@ class Styles
public GUIStyle iconDropDown = "IN dropdown";
public GUIStyle listTextStyle;
public GUIStyle listHeaderStyle;
- public GUIStyle texelWorldSizeStyle;
public GUIStyle columnHeaderStyle;
public const float k_ToggleSize = 17f;
@@ -34,12 +41,6 @@ public Styles()
listHeaderStyle = new GUIStyle(EditorStyles.boldLabel);
listHeaderStyle.padding.left = 5;
- texelWorldSizeStyle = new GUIStyle(EditorStyles.label);
- texelWorldSizeStyle.alignment = TextAnchor.UpperRight;
- texelWorldSizeStyle.font = EditorStyles.miniLabel.font;
- texelWorldSizeStyle.fontSize = EditorStyles.miniLabel.fontSize;
- texelWorldSizeStyle.padding.right = 0;
-
columnHeaderStyle = EditorStyles.miniLabel;
}
}
@@ -52,41 +53,50 @@ private enum EnabledState
Mixed = 2
}
- const float kWindowWidth = 270;
- const float scrollBarWidth = 14;
- const float listElementHeight = 18;
+ const float k_WindowWidth = 270;
+ const float k_ScrollBarWidth = 14;
+ const float k_ListElementHeight = 18;
+ const float k_FrameWidth = 1f;
float iconSize = 16;
float gizmoRightAlign;
float gizmoTextRightAlign;
float iconRightAlign;
float iconTextRightAlign;
- const float frameWidth = 1f;
- static bool s_Debug = false;
static AnnotationWindow s_AnnotationWindow = null;
static long s_LastClosedTime;
+ const long k_JustClosedPeriod = 400;
+
static Styles m_Styles;
- List m_RecentAnnotations;
- List m_BuiltinAnnotations;
- List m_ScriptAnnotations;
+ List m_RecentAnnotations;
+ List