Esempio n. 1
0
        /// <summary>
        /// Opens a dialog to allows the user to select a location where to save the current scene. If scene was previously
        /// saved it is instead automatically saved at the last location.
        /// </summary>
        public static void SaveScene(Action onSuccess = null, Action onFailure = null)
        {
            if (!Scene.ActiveSceneUUID.IsEmpty())
            {
                string scenePath = ProjectLibrary.GetPath(Scene.ActiveSceneUUID);
                if (!string.IsNullOrEmpty(scenePath))
                {
                    if (Scene.IsGenericPrefab)
                    {
                        SaveGenericPrefab(onSuccess, onFailure);
                    }
                    else
                    {
                        SaveScene(scenePath);

                        if (onSuccess != null)
                        {
                            onSuccess();
                        }
                    }
                }
                else
                {
                    SaveSceneAs(onSuccess, onFailure);
                }
            }
            else
            {
                SaveSceneAs(onSuccess, onFailure);
            }
        }
Esempio n. 2
0
        public static void SaveProject()
        {
            OnProjectSave?.Invoke();

            // Apply changes to any animation clips edited using the animation editor
            foreach (var KVP in persistentData.dirtyAnimClips)
            {
                KVP.Value.SaveToClip();
            }

            // Save all dirty resources to disk
            foreach (var KVP in persistentData.dirtyResources)
            {
                UUID   resourceUUID = KVP.Key;
                string path         = ProjectLibrary.GetPath(resourceUUID);
                if (!IsNative(path))
                {
                    continue; // Imported resources can't be changed
                }
                Resource resource = ProjectLibrary.Load <Resource>(path);

                if (resource != null)
                {
                    ProjectLibrary.Save(resource);
                }
            }

            persistentData.dirtyAnimClips.Clear();
            persistentData.dirtyResources.Clear();
            SetStatusProject(false);

            Internal_SaveProject();
        }
Esempio n. 3
0
        /// <summary>
        /// Reimports the script code resource according to the currently set import options.
        /// </summary>
        private void TriggerReimport()
        {
            ScriptCode scriptCode   = (ScriptCode)InspectedObject;
            string     resourcePath = ProjectLibrary.GetPath(scriptCode);

            ProjectLibrary.Reimport(resourcePath, importOptions, true);
        }
        /// <summary>
        /// Retrieves import options for the resource we're currently inspecting.
        /// </summary>
        /// <returns>Script code import options object.</returns>
        private ScriptCodeImportOptions GetImportOptions()
        {
            ScriptCode scriptCode          = InspectedObject as ScriptCode;
            ScriptCodeImportOptions output = null;

            if (scriptCode != null)
            {
                LibraryEntry libEntry = ProjectLibrary.GetEntry(ProjectLibrary.GetPath(scriptCode));
                if (libEntry != null && libEntry.Type == LibraryEntryType.File)
                {
                    FileEntry fileEntry = (FileEntry)libEntry;
                    output = fileEntry.Options as ScriptCodeImportOptions;
                }
            }

            if (output == null)
            {
                if (importOptions == null)
                {
                    output = new ScriptCodeImportOptions();
                }
                else
                {
                    output = importOptions;
                }
            }

            return(output);
        }
Esempio n. 5
0
        /// <summary>
        /// Reimports the texture resource according to the currently set import options.
        /// </summary>
        private void TriggerReimport()
        {
            Texture texture      = (Texture)InspectedObject;
            string  resourcePath = ProjectLibrary.GetPath(texture);

            ProjectLibrary.Reimport(resourcePath, importOptions, true);
        }
        /// <summary>
        /// Saves the animation curves and events stored in this object, into the associated animation clip resource.
        /// Relevant animation clip resource must already be created and exist in the project library.
        /// </summary>
        public void SaveToClip()
        {
            if (!isImported)
            {
                EditorAnimClipData editorAnimClipData;
                Apply(out editorAnimClipData);

                string resourcePath = ProjectLibrary.GetPath(clip);
                ProjectLibrary.Save(clip);

                ProjectLibrary.SetEditorData(resourcePath, editorAnimClipData);
            }
            else
            {
                string       resourcePath = ProjectLibrary.GetPath(clip);
                LibraryEntry entry        = ProjectLibrary.GetEntry(resourcePath);

                if (entry != null && entry.Type == LibraryEntryType.File)
                {
                    FileEntry         fileEntry         = (FileEntry)entry;
                    MeshImportOptions meshImportOptions = (MeshImportOptions)fileEntry.Options;

                    string clipName = PathEx.GetTail(resourcePath);

                    List <ImportedAnimationEvents> newEvents = new List <ImportedAnimationEvents>();
                    newEvents.AddRange(meshImportOptions.AnimationEvents);

                    bool isExisting = false;
                    for (int i = 0; i < newEvents.Count; i++)
                    {
                        if (newEvents[i].Name == clipName)
                        {
                            newEvents[i].Events = events;
                            isExisting          = true;
                            break;
                        }
                    }

                    if (!isExisting)
                    {
                        ImportedAnimationEvents newEntry = new ImportedAnimationEvents();
                        newEntry.Name   = clipName;
                        newEntry.Events = events;

                        newEvents.Add(newEntry);
                    }

                    meshImportOptions.AnimationEvents = newEvents.ToArray();

                    ProjectLibrary.Reimport(resourcePath, meshImportOptions, true);
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Creates a new material parameter GUI.
        /// </summary>
        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of texture type.</param>
        /// <param name="material">Material the parameter is a part of.</param>
        /// <param name="layout">Layout to append the GUI elements to.</param>
        internal MaterialParamTextureGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
            : base(shaderParam)
        {
            LocString title = new LocEdString(shaderParam.name);

            GUITextureFieldType type = shaderParam.type == ShaderParameterType.Texture2D ?
                                       GUITextureFieldType.TextureOrSpriteTexture :
                                       GUITextureFieldType.Texture;

            guiElem = new GUITextureField(type, title);

            switch (shaderParam.type)
            {
            case ShaderParameterType.Texture2D:
            case ShaderParameterType.Texture3D:
            case ShaderParameterType.TextureCube:
                guiElem.OnChanged += (x) =>
                {
                    string path = ProjectLibrary.GetPath(x.UUID);
                    if (!string.IsNullOrEmpty(path))
                    {
                        if (ProjectLibrary.GetEntry(path) is FileEntry fileEntry)
                        {
                            if (fileEntry.ResourceMetas.Length > 0)
                            {
                                ResourceMeta meta = fileEntry.ResourceMetas[0];
                                if (meta.ResType == ResourceType.SpriteTexture)
                                {
                                    material.SetSpriteTexture(shaderParam.name, x.As <SpriteTexture>());
                                }
                                else if (meta.ResType == ResourceType.Texture)
                                {
                                    material.SetTexture(shaderParam.name, x.As <Texture>());
                                }
                            }
                        }
                    }
                    else
                    {
                        material.SetTexture(shaderParam.name, null);
                    }

                    EditorApplication.SetDirty(material);
                };
                break;
            }

            layout.AddElement(guiElem);
        }
        /// <summary>
        /// Updates the contents of the prefab with the contents of the provided prefab instance. If the provided object
        /// is not a prefab instance nothing happens.
        /// </summary>
        /// <param name="obj">Prefab instance whose prefab to update.</param>
        /// <param name="refreshScene">If true, all prefab instances in the current scene will be updated so they consistent
        ///                            with the newly saved data.</param>
        public static void ApplyPrefab(SceneObject obj, bool refreshScene = true)
        {
            if (obj == null)
            {
                return;
            }

            SceneObject prefabInstanceRoot = GetPrefabParent(obj);

            if (prefabInstanceRoot == null)
            {
                return;
            }

            if (refreshScene)
            {
                SceneObject root = Scene.Root;
                if (root != null)
                {
                    Internal_RecordPrefabDiff(root.GetCachedPtr());
                }
            }

            UUID   prefabUUID = GetPrefabUUID(prefabInstanceRoot);
            string prefabPath = ProjectLibrary.GetPath(prefabUUID);
            Prefab prefab     = ProjectLibrary.Load <Prefab>(prefabPath);

            if (prefab != null)
            {
                IntPtr soPtr     = prefabInstanceRoot.GetCachedPtr();
                IntPtr prefabPtr = prefab.GetCachedPtr();

                Internal_ApplyPrefab(soPtr, prefabPtr);
                ProjectLibrary.Save(prefab);
            }

            if (refreshScene)
            {
                SceneObject root = Scene.Root;
                if (root != null)
                {
                    Internal_UpdateFromPrefab(root.GetCachedPtr());
                }
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Pings the resource, highlighting it in its respective editors.
        /// </summary>
        /// <param name="resource">Resource to highlight.</param>
        public static void Ping(Resource resource)
        {
            string path = ProjectLibrary.GetPath(resource);

            Internal_PingResource(path);
        }
        /// <summary>
        /// Checks is the specified animation clip is imported from an external file, or created within the editor.
        /// </summary>
        /// <param name="clip">Clip to check.</param>
        /// <returns>True if the clip is imported from an external file (e.g. FBX file), or false if the clip is a native
        ///          resource created within the editor.</returns>
        public static bool IsClipImported(AnimationClip clip)
        {
            string resourcePath = ProjectLibrary.GetPath(clip);

            return(ProjectLibrary.IsSubresource(resourcePath));
        }
        /// <summary>
        /// Loads curve and event information from the provided clip, and creates a new instance of this object containing
        /// the required data for editing the source clip in the animation editor.
        /// </summary>
        /// <param name="clip">Clip to load.</param>
        /// <returns>Editor specific editable information about an animation clip.</returns>
        public static EditorAnimClipInfo Create(AnimationClip clip)
        {
            EditorAnimClipInfo clipInfo = new EditorAnimClipInfo();

            clipInfo.clip       = clip;
            clipInfo.isImported = IsClipImported(clip);
            clipInfo.sampleRate = (int)clip.SampleRate;

            AnimationCurves    clipCurves     = clip.Curves;
            EditorAnimClipData editorClipData = null;

            EditorAnimClipData lGetAnimClipData(ResourceMeta meta)
            {
                object             editorData = meta.EditorData;
                EditorAnimClipData output     = editorData as EditorAnimClipData;

                if (output == null)
                {
                    // Old editor data stores tangents only
                    if (editorData is EditorAnimClipTangents tangents)
                    {
                        output          = new EditorAnimClipData();
                        output.tangents = tangents;
                    }
                }

                return(output);
            }

            string resourcePath = ProjectLibrary.GetPath(clip);

            if (!string.IsNullOrEmpty(resourcePath))
            {
                LibraryEntry entry    = ProjectLibrary.GetEntry(resourcePath);
                string       clipName = PathEx.GetTail(resourcePath);

                if (entry != null && entry.Type == LibraryEntryType.File)
                {
                    FileEntry      fileEntry = (FileEntry)entry;
                    ResourceMeta[] metas     = fileEntry.ResourceMetas;

                    if (clipInfo.isImported)
                    {
                        for (int i = 0; i < metas.Length; i++)
                        {
                            if (clipName == metas[i].SubresourceName)
                            {
                                editorClipData = lGetAnimClipData(metas[i]);
                                break;
                            }
                        }
                    }
                    else
                    {
                        if (metas.Length > 0)
                        {
                            editorClipData = lGetAnimClipData(metas[0]);
                        }
                    }
                }
            }

            if (editorClipData == null)
            {
                editorClipData          = new EditorAnimClipData();
                editorClipData.tangents = new EditorAnimClipTangents();
            }

            int globalCurveIdx = 0;

            void lLoadVector3Curve(NamedVector3Curve[] curves, EditorVector3CurveTangents[] tangents, string subPath)
            {
                foreach (var curveEntry in curves)
                {
                    TangentMode[] tangentsX = null;
                    TangentMode[] tangentsY = null;
                    TangentMode[] tangentsZ = null;

                    if (tangents != null)
                    {
                        foreach (var tangentEntry in tangents)
                        {
                            if (tangentEntry.name == curveEntry.name)
                            {
                                tangentsX = tangentEntry.tangentsX;
                                tangentsY = tangentEntry.tangentsY;
                                tangentsZ = tangentEntry.tangentsZ;
                                break;
                            }
                        }
                    }

                    // Convert compound curve to three per-component curves
                    AnimationCurve[] componentCurves = AnimationUtility.SplitCurve3D(curveEntry.curve);

                    FieldAnimCurves fieldCurves = new FieldAnimCurves();
                    fieldCurves.type            = SerializableProperty.FieldType.Vector3;
                    fieldCurves.curveInfos      = new EdCurveDrawInfo[3];
                    fieldCurves.isPropertyCurve = !clipInfo.isImported;

                    fieldCurves.curveInfos[0]       = new EdCurveDrawInfo();
                    fieldCurves.curveInfos[0].curve = new EdAnimationCurve(componentCurves[0], tangentsX);
                    fieldCurves.curveInfos[0].color = GetUniqueColor(globalCurveIdx++);

                    fieldCurves.curveInfos[1]       = new EdCurveDrawInfo();
                    fieldCurves.curveInfos[1].curve = new EdAnimationCurve(componentCurves[1], tangentsY);
                    fieldCurves.curveInfos[1].color = GetUniqueColor(globalCurveIdx++);

                    fieldCurves.curveInfos[2]       = new EdCurveDrawInfo();
                    fieldCurves.curveInfos[2].curve = new EdAnimationCurve(componentCurves[2], tangentsZ);
                    fieldCurves.curveInfos[2].color = GetUniqueColor(globalCurveIdx++);

                    string curvePath = curveEntry.name.TrimEnd('/') + subPath;
                    clipInfo.curves[curvePath] = fieldCurves;
                }
            };

            NamedQuaternionCurve[] rotationCurves      = clipCurves.Rotation;
            NamedVector3Curve[]    eulerRotationCurves = new NamedVector3Curve[rotationCurves.Length];
            if (editorClipData.eulerCurves == null || editorClipData.eulerCurves.Length != rotationCurves.Length)
            {
                // Convert rotation from quaternion to euler if we don't have original euler animation data stored.
                for (int i = 0; i < rotationCurves.Length; i++)
                {
                    NamedQuaternionCurve quatCurve  = rotationCurves[i];
                    Vector3Curve         eulerCurve = AnimationUtility.QuaternionToEulerCurve(quatCurve.curve);

                    eulerRotationCurves[i] = new NamedVector3Curve(quatCurve.name, quatCurve.flags, eulerCurve);
                }
            }
            else
            {
                for (int i = 0; i < editorClipData.eulerCurves.Length; i++)
                {
                    EditorNamedVector3Curve edCurve = editorClipData.eulerCurves[i];

                    eulerRotationCurves[i] = new NamedVector3Curve(
                        edCurve.name, edCurve.flags, new Vector3Curve(edCurve.keyFrames));
                }
            }

            lLoadVector3Curve(clipCurves.Position, editorClipData.tangents.positionCurves, "/Position");
            lLoadVector3Curve(eulerRotationCurves, editorClipData.tangents.rotationCurves, "/Rotation");
            lLoadVector3Curve(clipCurves.Scale, editorClipData.tangents.scaleCurves, "/Scale");

            // Find which individual float curves belong to the same field
            Dictionary <string, Tuple <int, int, bool>[]> floatCurveMapping = new Dictionary <string, Tuple <int, int, bool>[]>();

            {
                int curveIdx = 0;
                foreach (var curveEntry in clipCurves.Generic)
                {
                    string path         = curveEntry.name;
                    string pathNoSuffix = null;

                    string pathSuffix;
                    if (path.Length >= 2)
                    {
                        pathSuffix   = path.Substring(path.Length - 2, 2);
                        pathNoSuffix = path.Substring(0, path.Length - 2);
                    }
                    else
                    {
                        pathSuffix = "";
                    }

                    int tangentIdx        = -1;
                    int currentTangentIdx = 0;
                    foreach (var tangentEntry in editorClipData.tangents.floatCurves)
                    {
                        if (tangentEntry.name == curveEntry.name)
                        {
                            tangentIdx = currentTangentIdx;
                            break;
                        }

                        currentTangentIdx++;
                    }

                    Animation.PropertySuffixInfo suffixInfo;
                    if (Animation.PropertySuffixInfos.TryGetValue(pathSuffix, out suffixInfo))
                    {
                        Tuple <int, int, bool>[] curveInfo;
                        if (!floatCurveMapping.TryGetValue(pathNoSuffix, out curveInfo))
                        {
                            curveInfo = new Tuple <int, int, bool> [4];
                        }

                        curveInfo[suffixInfo.elementIdx] = Tuple.Create(curveIdx, tangentIdx, suffixInfo.isVector);
                        floatCurveMapping[pathNoSuffix]  = curveInfo;
                    }
                    else
                    {
                        Tuple <int, int, bool>[] curveInfo = new Tuple <int, int, bool> [4];
                        curveInfo[0] = Tuple.Create(curveIdx, tangentIdx, suffixInfo.isVector);

                        floatCurveMapping[path] = curveInfo;
                    }

                    curveIdx++;
                }
            }

            foreach (var KVP in floatCurveMapping)
            {
                int numCurves = 0;
                for (int i = 0; i < 4; i++)
                {
                    if (KVP.Value[i] == null)
                    {
                        continue;
                    }

                    numCurves++;
                }

                if (numCurves == 0)
                {
                    continue; // Invalid curve
                }
                FieldAnimCurves fieldCurves = new FieldAnimCurves();

                // Deduce type (note that all single value types are assumed to be float even if their source type is int or bool)
                if (numCurves == 1)
                {
                    fieldCurves.type = SerializableProperty.FieldType.Float;
                }
                else if (numCurves == 2)
                {
                    fieldCurves.type = SerializableProperty.FieldType.Vector2;
                }
                else if (numCurves == 3)
                {
                    fieldCurves.type = SerializableProperty.FieldType.Vector3;
                }
                else // 4 curves
                {
                    bool isVector = KVP.Value[0].Item3;
                    if (isVector)
                    {
                        fieldCurves.type = SerializableProperty.FieldType.Vector4;
                    }
                    else
                    {
                        fieldCurves.type = SerializableProperty.FieldType.Color;
                    }
                }

                bool   isMorphCurve = false;
                string curvePath    = KVP.Key;

                fieldCurves.curveInfos = new EdCurveDrawInfo[numCurves];
                for (int i = 0; i < numCurves; i++)
                {
                    int curveIdx   = KVP.Value[i].Item1;
                    int tangentIdx = KVP.Value[i].Item2;

                    TangentMode[] tangents = null;
                    if (tangentIdx != -1)
                    {
                        tangents = editorClipData.tangents.floatCurves[tangentIdx].tangents;
                    }

                    fieldCurves.curveInfos[i]       = new EdCurveDrawInfo();
                    fieldCurves.curveInfos[i].curve = new EdAnimationCurve(clipCurves.Generic[curveIdx].curve, tangents);
                    fieldCurves.curveInfos[i].color = GetUniqueColor(globalCurveIdx++);

                    if (clipCurves.Generic[curveIdx].flags.HasFlag(AnimationCurveFlags.MorphFrame))
                    {
                        curvePath    = "MorphShapes/Frames/" + KVP.Key;
                        isMorphCurve = true;
                    }
                    else if (clipCurves.Generic[curveIdx].flags.HasFlag(AnimationCurveFlags.MorphWeight))
                    {
                        curvePath    = "MorphShapes/Weight/" + KVP.Key;
                        isMorphCurve = true;
                    }
                }

                fieldCurves.isPropertyCurve = !clipInfo.isImported && !isMorphCurve;

                clipInfo.curves[curvePath] = fieldCurves;
            }

            // Add events
            clipInfo.events = clip.Events;
            return(clipInfo);
        }