/// <summary> /// Retrieves import options for the texture we're currently inspecting. /// </summary> /// <returns>Texture import options object.</returns> private TextureImportOptions GetImportOptions() { TextureImportOptions output = null; LibraryEntry texEntry = ProjectLibrary.GetEntry(InspectedResourcePath); if (texEntry != null && texEntry.Type == LibraryEntryType.File) { FileEntry texFileEntry = (FileEntry)texEntry; output = texFileEntry.Options as TextureImportOptions; } if (output == null) { if (importOptions == null) { output = new TextureImportOptions(); } else { output = importOptions; } } return(output); }
/// <summary> /// Triggered when a resource is (re)imported in the project library. /// </summary> /// <param name="path">Path of the imported resource, relative to the project's resource folder.</param> private void OnEntryImported(string path) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry == null || entry.Type != LibraryEntryType.File) { return; } FileEntry fileEntry = (FileEntry)entry; if (fileEntry.ResType != ResourceType.ScriptCode) { return; } ScriptCode codeFile = ProjectLibrary.Load <ScriptCode>(path); if (codeFile == null) { return; } if (codeFile.EditorScript) { isEditorAssemblyDirty = true; } else { isGameAssemblyDirty = true; } }
/// <summary> /// Triggered when the user double-clicked on the entry. /// </summary> /// <param name="path">Project library path of the double-clicked entry.</param> private void OnEntryDoubleClicked(string path) { delayedSelect = false; LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry != null) { if (entry.Type == LibraryEntryType.Directory) { owner.Window.EnterDirectory(path); } else { ResourceMeta meta = ProjectLibrary.GetMeta(path); FileEntry fileEntry = (FileEntry)entry; if (meta.ResType == ResourceType.Prefab) { EditorApplication.LoadScene(fileEntry.Path); } else if (meta.ResType == ResourceType.ScriptCode) { ProgressBar.Show("Opening external code editor...", 1.0f); delayedOpenCodeEditorFrame = Time.FrameIdx + 1; } } } }
/// <summary> /// Retrieves import options for the audio clip we're currently inspecting. /// </summary> /// <returns>Audio clip import options object.</returns> private AudioClipImportOptions GetImportOptions() { AudioClip audioClip = InspectedObject as AudioClip; AudioClipImportOptions output = null; if (audioClip != null) { LibraryEntry meshEntry = ProjectLibrary.GetEntry(ProjectLibrary.GetPath(audioClip)); if (meshEntry != null && meshEntry.Type == LibraryEntryType.File) { FileEntry meshFileEntry = (FileEntry)meshEntry; output = meshFileEntry.Options as AudioClipImportOptions; } } if (output == null) { if (importOptions == null) { output = new AudioClipImportOptions(); } else { output = importOptions; } } return(output); }
/// <summary> /// Retrieves import options for the mesh we're currently inspecting. /// </summary> /// <returns>Mesh import options object.</returns> private MeshImportOptions GetImportOptions() { Mesh mesh = InspectedObject as Mesh; MeshImportOptions output = null; if (mesh != null) { LibraryEntry meshEntry = ProjectLibrary.GetEntry(ProjectLibrary.GetPath(mesh)); if (meshEntry != null && meshEntry.Type == LibraryEntryType.File) { FileEntry meshFileEntry = (FileEntry)meshEntry; output = meshFileEntry.Options as MeshImportOptions; } } if (output == null) { if (importOptions == null) { output = new MeshImportOptions(); } else { output = importOptions; } } return(output); }
/// <summary> /// Checks is the resource at the provided path a file relevant to the code editor. /// </summary> /// <param name="path">Path to the resource, absolute or relative to the project's resources folder.</param> /// <returns>True if the file is relevant to the code editor, false otherwise.</returns> private bool IsCodeEditorFile(string path) { if (Path.GetExtension(path) == ".dll") { return(true); //Include assemblies. TODO: Make platform-agnostic. } LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry != null && entry.Type == LibraryEntryType.File) { FileEntry fileEntry = (FileEntry)entry; ResourceMeta[] resourceMetas = fileEntry.ResourceMetas; foreach (var codeType in CodeEditor.CodeTypes) { foreach (var meta in resourceMetas) { if (meta.ResType == codeType) { return(true); } } } } return(false); }
/// <summary> /// Retrieves import options for the texture we're currently inspecting. /// </summary> /// <returns>Font import options object.</returns> private FontImportOptions GetImportOptions() { Font font = InspectedObject as Font; FontImportOptions output = null; if (font != null) { LibraryEntry texEntry = ProjectLibrary.GetEntry(ProjectLibrary.GetPath(font)); if (texEntry != null && texEntry.Type == LibraryEntryType.File) { FileEntry texFileEntry = (FileEntry)texEntry; output = texFileEntry.Options as FontImportOptions; } } if (output == null) { if (importOptions == null) { output = new FontImportOptions(); } else { output = importOptions; } } return(output); }
/// <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); }
/// <summary> /// Retrieves import options for the mesh we're currently inspecting. /// </summary> /// <returns>Mesh import options object.</returns> private MeshImportOptions GetImportOptions() { MeshImportOptions output = null; LibraryEntry meshEntry = ProjectLibrary.GetEntry(InspectedResourcePath); if (meshEntry != null && meshEntry.Type == LibraryEntryType.File) { FileEntry meshFileEntry = (FileEntry)meshEntry; output = meshFileEntry.Options as MeshImportOptions; } if (output == null) { if (importOptions == null) { output = new MeshImportOptions(); } else { output = importOptions; } } return(output); }
/// <summary> /// Retrieves import options for the texture we're currently inspecting. /// </summary> /// <returns>Texture import options object.</returns> private TextureImportOptions GetImportOptions() { Texture2D texture = InspectedObject as Texture2D; TextureImportOptions output = null; if (texture != null) { LibraryEntry texEntry = ProjectLibrary.GetEntry(ProjectLibrary.GetPath(texture)); if (texEntry != null && texEntry.Type == LibraryEntryType.File) { FileEntry texFileEntry = (FileEntry)texEntry; output = texFileEntry.Options as TextureImportOptions; } } if (output == null) { if (importOptions == null) { output = new TextureImportOptions(); } else { output = importOptions; } } return(output); }
/// <summary> /// Returns an icon that can be used for displaying a resource of the specified type. /// </summary> /// <param name="path">Path to the project library entry to display data for.</param> /// <param name="size">Size of the icon to retrieve, in pixels.</param> /// <returns>Icon to display for the specified entry.</returns> private static SpriteTexture GetIcon(string path, int size) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry.Type == LibraryEntryType.Directory) { return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Folder, size)); } else { ResourceMeta meta = ProjectLibrary.GetMeta(path); switch (meta.ResType) { case ResourceType.Font: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Font, size)); case ResourceType.Mesh: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Mesh, size)); case ResourceType.Texture: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Texture, size)); case ResourceType.PlainText: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.PlainText, size)); case ResourceType.ScriptCode: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.ScriptCode, size)); case ResourceType.SpriteTexture: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.SpriteTexture, size)); case ResourceType.Shader: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Shader, size)); case ResourceType.ShaderInclude: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Shader, size)); case ResourceType.Material: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Material, size)); case ResourceType.Prefab: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Prefab, size)); case ResourceType.GUISkin: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.GUISkin, size)); case ResourceType.PhysicsMaterial: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.PhysicsMaterial, size)); case ResourceType.PhysicsMesh: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.PhysicsMesh, size)); case ResourceType.AudioClip: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.AudioClip, size)); } } return(null); }
/// <summary> /// Triggered by the runtime when a resource is dropped on the scene tree view. /// </summary> private void Internal_DoOnResourceDropped(SceneObject parent, string[] resourcePaths) { if (resourcePaths == null) { return; } List <SceneObject> addedObjects = new List <SceneObject>(); for (int i = 0; i < resourcePaths.Length; i++) { LibraryEntry entry = ProjectLibrary.GetEntry(resourcePaths[i]); if (entry != null && entry.Type == LibraryEntryType.File) { FileEntry fileEntry = (FileEntry)entry; if (fileEntry.ResType == ResourceType.Mesh) { if (!string.IsNullOrEmpty(resourcePaths[i])) { string meshName = Path.GetFileNameWithoutExtension(resourcePaths[i]); Mesh mesh = ProjectLibrary.Load <Mesh>(resourcePaths[i]); if (mesh == null) { continue; } SceneObject so = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\""); so.Parent = parent; Renderable renderable = so.AddComponent <Renderable>(); renderable.Mesh = mesh; addedObjects.Add(so); } } else if (fileEntry.ResType == ResourceType.Prefab) { if (!string.IsNullOrEmpty(resourcePaths[i])) { Prefab prefab = ProjectLibrary.Load <Prefab>(resourcePaths[i]); SceneObject so = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name); so.Parent = parent; addedObjects.Add(so); } } } } if (addedObjects.Count > 0) { EditorApplication.SetSceneDirty(); } Selection.SceneObjects = addedObjects.ToArray(); }
/// <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) { EditorAnimClipTangents tangents; Apply(out tangents); string resourcePath = ProjectLibrary.GetPath(clip); ProjectLibrary.Save(clip); ProjectLibrary.SetEditorData(resourcePath, tangents); } 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); } } }
/// <summary> /// Triggered when a resource is (re)imported in the project library. /// </summary> /// <param name="path">Path of the imported resource, relative to the project's resource folder.</param> private void OnEntryImported(string path) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry == null || entry.Type != LibraryEntryType.File) { return; } FileEntry fileEntry = (FileEntry)entry; ResourceMeta[] resourceMetas = fileEntry.ResourceMetas; bool found = false; foreach (var meta in resourceMetas) { if (meta.ResType == ResourceType.ScriptCode) { found = true; break; } } if (!found) { return; } ScriptCode codeFile = ProjectLibrary.Load <ScriptCode>(path); if (codeFile == null) { return; } if (codeFile.EditorScript) { isEditorAssemblyDirty = true; } else { isGameAssemblyDirty = true; } }
/// <summary> /// Triggered when the user clicks on the entry. /// </summary> /// <param name="path">Project library path of the clicked entry.</param> private void OnEntryClicked(string path) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry != null && entry.Type == LibraryEntryType.Directory) { // If entry is a directory delay selection as it might be a double-click, in which case we want to keep // whatever selection is active currently so that user can perform drag and drop with its inspector // from the folder he is browsing to. delayedSelect = true; delayedSelectTime = Time.RealElapsed + 0.5f; } else { owner.Window.Select(path); } }
/// <summary> /// Checks is the resource at the provided path a file relevant to the code editor. /// </summary> /// <param name="path">Path to the resource, absolute or relative to the project's resources folder.</param> /// <returns>True if the file is relevant to the code editor, false otherwise.</returns> private bool IsCodeEditorFile(string path) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry != null && entry.Type == LibraryEntryType.File) { FileEntry fileEntry = (FileEntry)entry; foreach (var codeType in CodeEditor.CodeTypes) { if (fileEntry.ResType == codeType) { return(true); } } } return(false); }
/// <summary> /// Called every frame. /// </summary> public void Update() { if (delayedSelect && Time.RealElapsed > delayedSelectTime) { owner.Window.Select(path); delayedSelect = false; } if (delayedOpenCodeEditorFrame == Time.FrameIdx) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry != null && entry.Type == LibraryEntryType.File) { FileEntry resEntry = (FileEntry)entry; CodeEditor.OpenFile(resEntry.Path, 0); } ProgressBar.Hide(); } }
private void OnEditorUpdate() { if (currentType == InspectorType.SceneObject) { Component[] allComponents = activeSO.GetComponents(); bool requiresRebuild = allComponents.Length != inspectorComponents.Count; if (!requiresRebuild) { for (int i = 0; i < inspectorComponents.Count; i++) { if (inspectorComponents[i].instanceId != allComponents[i].InstanceId) { requiresRebuild = true; break; } } } if (requiresRebuild) { SceneObject so = activeSO; Clear(); SetObjectToInspect(so); } else { RefreshSceneObjectFields(false); InspectableState componentModifyState = InspectableState.NotModified; for (int i = 0; i < inspectorComponents.Count; i++) { componentModifyState |= inspectorComponents[i].inspector.Refresh(); } if (componentModifyState.HasFlag(InspectableState.ModifyInProgress)) { EditorApplication.SetSceneDirty(); } modifyState |= componentModifyState; } } else if (currentType == InspectorType.Resource) { inspectorResource.inspector.Refresh(); } // Detect drag and drop bool isValidDrag = false; if (activeSO != null) { if ((DragDrop.DragInProgress || DragDrop.DropInProgress) && DragDrop.Type == DragDropType.Resource) { Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition); Vector2I scrollPos = windowPos; Rect2I contentBounds = inspectorLayout.Bounds; scrollPos.x -= contentBounds.x; scrollPos.y -= contentBounds.y; bool isInBounds = false; Rect2I dropArea = new Rect2I(); foreach (var bounds in dropAreas) { if (bounds.Contains(scrollPos)) { isInBounds = true; dropArea = bounds; break; } } Type draggedComponentType = null; if (isInBounds) { ResourceDragDropData dragData = DragDrop.Data as ResourceDragDropData; if (dragData != null) { foreach (var resPath in dragData.Paths) { LibraryEntry entry = ProjectLibrary.GetEntry(resPath); FileEntry fileEntry = entry as FileEntry; if (fileEntry != null) { if (fileEntry.ResType == ResourceType.ScriptCode) { ScriptCode scriptFile = ProjectLibrary.Load <ScriptCode>(resPath); if (scriptFile != null) { Type[] scriptTypes = scriptFile.Types; foreach (var type in scriptTypes) { if (type.IsSubclassOf(typeof(Component))) { draggedComponentType = type; isValidDrag = true; break; } } if (draggedComponentType != null) { break; } } } } } } } if (isValidDrag) { scrollAreaHighlight.Bounds = dropArea; if (DragDrop.DropInProgress) { activeSO.AddComponent(draggedComponentType); modifyState = InspectableState.Modified; EditorApplication.SetSceneDirty(); } } } } if (scrollAreaHighlight != null) { scrollAreaHighlight.Active = isValidDrag; } }
/// <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; EditorAnimClipTangents editorCurveData = null; 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) { editorCurveData = metas[i].EditorData as EditorAnimClipTangents; break; } } } else { if (metas.Length > 0) { editorCurveData = metas[0].EditorData as EditorAnimClipTangents; } } } } if (editorCurveData == null) { editorCurveData = new EditorAnimClipTangents(); } int globalCurveIdx = 0; Action <NamedVector3Curve[], EditorVector3CurveTangents[], string> loadVector3Curve = (curves, tangents, 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.SplitCurve(curveEntry.curve); FieldAnimCurves fieldCurves = new FieldAnimCurves(); fieldCurves.type = SerializableProperty.FieldType.Vector3; fieldCurves.curveInfos = new CurveDrawInfo[3]; fieldCurves.isPropertyCurve = !clipInfo.isImported; fieldCurves.curveInfos[0] = new CurveDrawInfo(); fieldCurves.curveInfos[0].curve = new EdAnimationCurve(componentCurves[0], tangentsX); fieldCurves.curveInfos[0].color = GUICurveDrawing.GetUniqueColor(globalCurveIdx++); fieldCurves.curveInfos[1] = new CurveDrawInfo(); fieldCurves.curveInfos[1].curve = new EdAnimationCurve(componentCurves[1], tangentsY); fieldCurves.curveInfos[1].color = GUICurveDrawing.GetUniqueColor(globalCurveIdx++); fieldCurves.curveInfos[2] = new CurveDrawInfo(); fieldCurves.curveInfos[2].curve = new EdAnimationCurve(componentCurves[2], tangentsZ); fieldCurves.curveInfos[2].color = GUICurveDrawing.GetUniqueColor(globalCurveIdx++); string curvePath = curveEntry.name.TrimEnd('/') + subPath; clipInfo.curves[curvePath] = fieldCurves; } }; // Convert rotation from quaternion to euler NamedQuaternionCurve[] rotationCurves = clipCurves.Rotation; NamedVector3Curve[] eulerRotationCurves = new NamedVector3Curve[rotationCurves.Length]; for (int i = 0; i < rotationCurves.Length; i++) { eulerRotationCurves[i] = new NamedVector3Curve(); eulerRotationCurves[i].name = rotationCurves[i].name; eulerRotationCurves[i].flags = rotationCurves[i].flags; eulerRotationCurves[i].curve = AnimationUtility.QuaternionToEulerCurve(rotationCurves[i].curve); } loadVector3Curve(clipCurves.Position, editorCurveData.positionCurves, "/Position"); loadVector3Curve(eulerRotationCurves, editorCurveData.rotationCurves, "/Rotation"); loadVector3Curve(clipCurves.Scale, editorCurveData.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 editorCurveData.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 CurveDrawInfo[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 = editorCurveData.floatCurves[tangentIdx].tangents; } fieldCurves.curveInfos[i] = new CurveDrawInfo(); fieldCurves.curveInfos[i].curve = new EdAnimationCurve(clipCurves.Generic[curveIdx].curve, tangents); fieldCurves.curveInfos[i].color = GUICurveDrawing.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); }
private void OnEditorUpdate() { if (HasFocus) { if (!Input.IsPointerButtonHeld(PointerButton.Right)) { if (VirtualInput.IsButtonDown(toggleProfilerOverlayKey)) EditorSettings.SetBool(ProfilerOverlayActiveKey, !EditorSettings.GetBool(ProfilerOverlayActiveKey)); if (VirtualInput.IsButtonDown(viewToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.View; if (VirtualInput.IsButtonDown(moveToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.Move; if (VirtualInput.IsButtonDown(rotateToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.Rotate; if (VirtualInput.IsButtonDown(scaleToolKey)) EditorApplication.ActiveSceneTool = SceneViewTool.Scale; if (VirtualInput.IsButtonDown(duplicateKey)) { SceneObject[] selectedObjects = Selection.SceneObjects; CleanDuplicates(ref selectedObjects); if (selectedObjects.Length > 0) { String message; if (selectedObjects.Length == 1) message = "Duplicated " + selectedObjects[0].Name; else message = "Duplicated " + selectedObjects.Length + " elements"; UndoRedo.CloneSO(selectedObjects, message); EditorApplication.SetSceneDirty(); } } if (VirtualInput.IsButtonDown(deleteKey)) { SceneObject[] selectedObjects = Selection.SceneObjects; CleanDuplicates(ref selectedObjects); if (selectedObjects.Length > 0) { foreach (var so in selectedObjects) { string message = "Deleted " + so.Name; UndoRedo.DeleteSO(so, message); } EditorApplication.SetSceneDirty(); } } } } // Refresh GUI buttons if needed (in case someones changes the values from script) if (editorSettingsHash != EditorSettings.Hash) { UpdateButtonStates(); UpdateProfilerOverlay(); editorSettingsHash = EditorSettings.Hash; } // Update scene view handles and selection sceneGizmos.Draw(); sceneGrid.Draw(); bool handleActive = false; if (Input.IsPointerButtonUp(PointerButton.Left)) { if (sceneHandles.IsActive()) { sceneHandles.ClearSelection(); handleActive = true; } if (sceneAxesGUI.IsActive()) { sceneAxesGUI.ClearSelection(); handleActive = true; } } Vector2I scenePos; bool inBounds = ScreenToScenePos(Input.PointerPosition, out scenePos); bool draggedOver = DragDrop.DragInProgress || DragDrop.DropInProgress; draggedOver &= IsPointerHovering && inBounds && DragDrop.Type == DragDropType.Resource; if (draggedOver) { if (DragDrop.DropInProgress) { dragActive = false; if (draggedSO != null) { Selection.SceneObject = draggedSO; EditorApplication.SetSceneDirty(); } draggedSO = null; } else { if (!dragActive) { dragActive = true; ResourceDragDropData dragData = (ResourceDragDropData)DragDrop.Data; string[] draggedPaths = dragData.Paths; for (int i = 0; i < draggedPaths.Length; i++) { LibraryEntry entry = ProjectLibrary.GetEntry(draggedPaths[i]); if (entry != null && entry.Type == LibraryEntryType.File) { FileEntry fileEntry = (FileEntry) entry; if (fileEntry.ResType == ResourceType.Mesh) { if (!string.IsNullOrEmpty(draggedPaths[i])) { string meshName = Path.GetFileNameWithoutExtension(draggedPaths[i]); draggedSO = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\""); Mesh mesh = ProjectLibrary.Load<Mesh>(draggedPaths[i]); Renderable renderable = draggedSO.AddComponent<Renderable>(); renderable.Mesh = mesh; } break; } else if (fileEntry.ResType == ResourceType.Prefab) { if (!string.IsNullOrEmpty(draggedPaths[i])) { Prefab prefab = ProjectLibrary.Load<Prefab>(draggedPaths[i]); draggedSO = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name); } break; } } } } if (draggedSO != null) { Ray worldRay = camera.ScreenToWorldRay(scenePos); draggedSO.Position = worldRay*DefaultPlacementDepth; } } return; } else { if (dragActive) { dragActive = false; if (draggedSO != null) { draggedSO.Destroy(); draggedSO = null; } } } if (HasFocus) { cameraController.EnableInput(true); if (inBounds) { if (Input.IsPointerButtonDown(PointerButton.Left)) { Rect2I sceneAxesGUIBounds = new Rect2I(Width - HandleAxesGUISize - HandleAxesGUIPaddingX, HandleAxesGUIPaddingY, HandleAxesGUISize, HandleAxesGUISize); if (sceneAxesGUIBounds.Contains(scenePos)) sceneAxesGUI.TrySelect(scenePos); else sceneHandles.TrySelect(scenePos); } else if (Input.IsPointerButtonUp(PointerButton.Left)) { if (!handleActive) { bool ctrlHeld = Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl); sceneSelection.PickObject(scenePos, ctrlHeld); } } } } else cameraController.EnableInput(false); SceneHandles.BeginInput(); sceneHandles.UpdateInput(scenePos, Input.PointerDelta); sceneHandles.Draw(); sceneAxesGUI.UpdateInput(scenePos); sceneAxesGUI.Draw(); SceneHandles.EndInput(); sceneSelection.Draw(); UpdateGridMode(); if (VirtualInput.IsButtonDown(frameKey)) cameraController.FrameSelected(); }
/// <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) { List <NamedVector3Curve> positionCurves = new List <NamedVector3Curve>(); List <NamedVector3Curve> rotationCurves = new List <NamedVector3Curve>(); List <NamedVector3Curve> scaleCurves = new List <NamedVector3Curve>(); List <NamedFloatCurve> floatCurves = new List <NamedFloatCurve>(); List <EditorVector3CurveTangents> positionTangents = new List <EditorVector3CurveTangents>(); List <EditorVector3CurveTangents> rotationTangents = new List <EditorVector3CurveTangents>(); List <EditorVector3CurveTangents> scaleTangents = new List <EditorVector3CurveTangents>(); List <EditorFloatCurveTangents> floatTangents = new List <EditorFloatCurveTangents>(); foreach (var kvp in curves) { string[] pathEntries = kvp.Key.Split('/'); if (pathEntries.Length == 0) { continue; } string lastEntry = pathEntries[pathEntries.Length - 1]; if (lastEntry == "Position" || lastEntry == "Rotation" || lastEntry == "Scale") { StringBuilder sb = new StringBuilder(); for (int i = 0; i < pathEntries.Length - 2; i++) { sb.Append(pathEntries[i] + "/"); } if (pathEntries.Length > 1) { sb.Append(pathEntries[pathEntries.Length - 2]); } string curvePath = sb.ToString(); NamedVector3Curve curve = new NamedVector3Curve(curvePath, new AnimationCurve(kvp.Value.curveInfos[0].curve.KeyFrames), new AnimationCurve(kvp.Value.curveInfos[1].curve.KeyFrames), new AnimationCurve(kvp.Value.curveInfos[2].curve.KeyFrames)); EditorVector3CurveTangents tangents = new EditorVector3CurveTangents(); tangents.name = curvePath; tangents.tangentsX = kvp.Value.curveInfos[0].curve.TangentModes; tangents.tangentsY = kvp.Value.curveInfos[1].curve.TangentModes; tangents.tangentsZ = kvp.Value.curveInfos[2].curve.TangentModes; if (lastEntry == "Position") { positionCurves.Add(curve); positionTangents.Add(tangents); } else if (lastEntry == "Rotation") { rotationCurves.Add(curve); rotationTangents.Add(tangents); } else if (lastEntry == "Scale") { scaleCurves.Add(curve); scaleTangents.Add(tangents); } } else { Action <int, string> addCurve = (idx, subPath) => { string path = kvp.Key + subPath; NamedFloatCurve curve = new NamedFloatCurve(path, new AnimationCurve(kvp.Value.curveInfos[idx].curve.KeyFrames)); EditorFloatCurveTangents tangents = new EditorFloatCurveTangents(); tangents.name = path; tangents.tangents = kvp.Value.curveInfos[idx].curve.TangentModes; floatCurves.Add(curve); floatTangents.Add(tangents); }; switch (kvp.Value.type) { case SerializableProperty.FieldType.Vector2: addCurve(0, ".x"); addCurve(1, ".y"); break; case SerializableProperty.FieldType.Vector3: addCurve(0, ".x"); addCurve(1, ".y"); addCurve(2, ".z"); break; case SerializableProperty.FieldType.Vector4: addCurve(0, ".x"); addCurve(1, ".y"); addCurve(2, ".z"); addCurve(3, ".w"); break; case SerializableProperty.FieldType.Color: addCurve(0, ".r"); addCurve(1, ".g"); addCurve(2, ".b"); addCurve(3, ".a"); break; case SerializableProperty.FieldType.Bool: case SerializableProperty.FieldType.Int: case SerializableProperty.FieldType.Float: addCurve(0, ""); break; } } } AnimationCurves newClipCurves = new AnimationCurves(); newClipCurves.PositionCurves = positionCurves.ToArray(); newClipCurves.RotationCurves = rotationCurves.ToArray(); newClipCurves.ScaleCurves = scaleCurves.ToArray(); newClipCurves.FloatCurves = floatCurves.ToArray(); clip.Curves = newClipCurves; clip.Events = events; clip.SampleRate = sampleRate; string resourcePath = ProjectLibrary.GetPath(clip); ProjectLibrary.Save(clip); // Save tangents for editor only use EditorAnimClipTangents newCurveData = new EditorAnimClipTangents(); newCurveData.positionCurves = positionTangents.ToArray(); newCurveData.rotationCurves = rotationTangents.ToArray(); newCurveData.scaleCurves = scaleTangents.ToArray(); newCurveData.floatCurves = floatTangents.ToArray(); ProjectLibrary.SetEditorData(resourcePath, newCurveData); } 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); } } }
/// <summary> /// Returns an icon that can be used for displaying a resource of the specified type. /// </summary> /// <param name="path">Path to the project library entry to display data for.</param> /// <param name="size">Size of the icon to retrieve, in pixels.</param> /// <returns>Icon to display for the specified entry.</returns> private static SpriteTexture GetIcon(string path, int size) { LibraryEntry entry = ProjectLibrary.GetEntry(path); if (entry.Type == LibraryEntryType.Directory) { return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Folder, size)); } else { ResourceMeta meta = ProjectLibrary.GetMeta(path); ProjectResourceIcons icons = meta.Icons; Texture icon; if (size <= 16) { icon = icons.icon16; } else if (size <= 32) { icon = icons.icon32; } else if (size <= 48) { icon = icons.icon48; } else { icon = icons.icon64; } if (icon != null) { return(new SpriteTexture(icon)); } switch (meta.ResType) { case ResourceType.Font: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Font, size)); case ResourceType.Mesh: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Mesh, size)); case ResourceType.Texture: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Texture, size)); case ResourceType.PlainText: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.PlainText, size)); case ResourceType.ScriptCode: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.ScriptCode, size)); case ResourceType.SpriteTexture: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.SpriteTexture, size)); case ResourceType.Shader: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Shader, size)); case ResourceType.ShaderInclude: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Shader, size)); case ResourceType.Material: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Material, size)); case ResourceType.Prefab: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Prefab, size)); case ResourceType.GUISkin: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.GUISkin, size)); case ResourceType.PhysicsMaterial: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.PhysicsMaterial, size)); case ResourceType.PhysicsMesh: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.PhysicsMesh, size)); case ResourceType.AudioClip: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.AudioClip, size)); case ResourceType.AnimationClip: return(EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.AnimationClip, size)); } } return(null); }