// ------------------------------------------------------------------ /// \param _animClip the animation clip /// \param _fi the frame info in the animation clip /// add frame info by animation clip and frame info to sprite animation clip db // ------------------------------------------------------------------ public static void AddFrameInfo( exSpriteAnimClip _animClip, exSpriteAnimClip.FrameInfo _fi ) { Init(); string animClipGUID = exEditorHelper.AssetToGUID(_animClip); AddFrameInfo ( animClipGUID, _fi.textureGUID ); }
// ------------------------------------------------------------------ /// \param _animClip the sprite animation clip wants to add /// \return the instantiate animation state of the added _animClip /// Add a sprite animation clip, create a new animation state and saves /// it to the lookup table by the name of the clip /// /// \note if the animation already in the exSpriteAnimation.animations, /// it will do nothing // ------------------------------------------------------------------ public exSpriteAnimState AddAnimation( exSpriteAnimClip _animClip ) { // if we already have the animation, just return the animation state if ( animations.IndexOf(_animClip) != -1 ) { return nameToState[_animClip.name]; } // animations.Add (_animClip); exSpriteAnimState state = new exSpriteAnimState(_animClip); nameToState[state.name] = state; return state; }
[System.NonSerialized] public List<float> frameTimes; ///< the list of the start time in seconds of each frame in the exSpriteAnimClip // ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void Init ( string _name, exSpriteAnimClip _animClip ) { clip = _animClip; name = _name; wrapMode = _animClip.wrapMode; stopAction = _animClip.stopAction; length = _animClip.length; speed = _animClip.speed; frameTimes = new List<float>(_animClip.frameInfos.Count); float tmp = 0.0f; foreach ( exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos ) { tmp += fi.length; frameTimes.Add(tmp); } }
// ------------------------------------------------------------------ /// \param _animClip the sprite animatoin clip /// build the sprite animation clip // ------------------------------------------------------------------ public static void Build(this exSpriteAnimClip _animClip) { try { EditorUtility.DisplayProgressBar("Building Sprite Animation Clip " + _animClip.name, "Building Frames...", 0.1f); bool hasError = false; foreach (exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos) { exAtlasDB.ElementInfo elInfo = exAtlasDB.GetElementInfo(fi.textureGUID); if (elInfo != null) { fi.atlas = exEditorHelper.LoadAssetFromGUID <exAtlas>(elInfo.guidAtlas); fi.index = elInfo.indexInAtlas; } else { string texturePath = AssetDatabase.GUIDToAssetPath(fi.textureGUID); Texture2D tex2D = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); Debug.LogError("Failed to build sprite animation clip: " + _animClip.name + ", can't find texture " + ((tex2D != null) ? tex2D.name : "null") + " in exAtlasInfo."); fi.atlas = null; fi.index = -1; hasError = true; } } EditorUtility.ClearProgressBar(); _animClip.editorNeedRebuild = hasError; EditorUtility.SetDirty(_animClip); } catch (System.Exception) { EditorUtility.ClearProgressBar(); throw; } }
// ------------------------------------------------------------------ /// \param _animClip the sprite animatoin clip /// \param _tex the texture /// add texture to sprite animation clip as new frame // ------------------------------------------------------------------ public static void AddFrame(this exSpriteAnimClip _animClip, Texture2D _tex) { exSpriteAnimClip.FrameInfo frameInfo = new exSpriteAnimClip.FrameInfo(); frameInfo.length = 10.0f / 60.0f; frameInfo.textureGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_tex)); exAtlasDB.ElementInfo elInfo = exAtlasDB.GetElementInfo(frameInfo.textureGUID); if (elInfo != null) { frameInfo.atlas = exEditorHelper.LoadAssetFromGUID <exAtlas>(elInfo.guidAtlas); frameInfo.index = elInfo.indexInAtlas; } else { frameInfo.atlas = null; frameInfo.index = -1; } _animClip.frameInfos.Add(frameInfo); _animClip.length += frameInfo.length; exSpriteAnimationDB.AddFrameInfo(_animClip, frameInfo); _animClip.editorNeedRebuild = true; EditorUtility.SetDirty(_animClip); }
// ------------------------------------------------------------------ /// \param _name the name of animation state you want to add /// \param _animClip the sprite animation clip wants to add /// \return the instantiate animation state of the added _animClip /// Add a sprite animation clip, create a new animation state and saves /// it to the lookup table by the name of the clip /// /// \note if the animation already in the exSpriteAnimation.animations, /// it will override the old clip and return a new animation state. // ------------------------------------------------------------------ public exSpriteAnimState AddAnimation(string _name, exSpriteAnimClip _animClip) { Init(); exSpriteAnimState state = null; // if we already have the animation, just return the animation state if (animations.IndexOf(_animClip) != -1) { state = nameToState[_name]; if (state.clip != _animClip) { state = new exSpriteAnimState(_name, _animClip); nameToState[_name] = state; } return(state); } // animations.Add(_animClip); state = new exSpriteAnimState(_name, _animClip); nameToState[_name] = state; return(state); }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ static void SyncDirectory(string _path) { // Process the list of files found in the directory. string [] files = Directory.GetFiles(_path, "*.asset"); foreach (string fileName in files) { exSpriteAnimClip spAnimClip = (exSpriteAnimClip)AssetDatabase.LoadAssetAtPath(fileName, typeof(exSpriteAnimClip)); if (spAnimClip) { AddSpriteAnimClip(spAnimClip); spAnimClip = null; EditorUtility.UnloadUnusedAssetsIgnoreManagedReferences(); System.GC.Collect(); } } // Recurse into subdirectories of this directory. string [] dirs = Directory.GetDirectories(_path); foreach (string dirName in dirs) { SyncDirectory(dirName); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void SpriteAnimClipField( Rect _rect, int _topHeight, int _botHeight, int _scalarHeight, exSpriteAnimClip _animClip ) { // ======================================================== // init varaible // ======================================================== float boxWidth = _rect.width; float boxHeight = _rect.height - _topHeight - _botHeight; // NOTE: a protection to prevent while dead loop _animClip.editorScale = Mathf.Clamp( _animClip.editorScale, 0.01f, 10.0f ); // constant float widthToShowLabel = 60.0f; float minWidth = 10.0f; float maxWidth = 80.0f; float minUnitSecond = 1.0f/_animClip.sampleRate; // variable // int[] lodScales = new int[] { 5, 2, 3, 2 }; List<int> lodScales = new List<int>(); int tmpSampleRate = (int)_animClip.sampleRate; while ( true ) { int div = 0; if ( tmpSampleRate == 30 ) { div = 3; } else if ( tmpSampleRate % 2 == 0 ) { div = 2; } else if ( tmpSampleRate % 5 == 0 ) { div = 5; } else if ( tmpSampleRate % 3 == 0 ) { div = 3; } else { break; } tmpSampleRate /= div; lodScales.Insert(0,div); } int curIdx = lodScales.Count; lodScales.AddRange( new int[] { 5, 2, 3, 2, 5, 2, 3, 2, } ); // float unitWidth = 1000.0f; // width for 1 second float curUnitSecond = 1.0f; float curCellWidth = unitWidth * _animClip.editorScale; // get curUnitSecond and curIdx if ( curCellWidth < minWidth ) { while ( curCellWidth < minWidth ) { curUnitSecond = curUnitSecond * lodScales[curIdx]; curCellWidth = curCellWidth * lodScales[curIdx]; curIdx += 1; if ( curIdx >= lodScales.Count ) { curIdx = lodScales.Count - 1; break; } } } else if ( curCellWidth > maxWidth ) { while ( (curCellWidth > maxWidth) && (curUnitSecond > minUnitSecond) ) { curIdx -= 1; if ( curIdx < 0 ) { curIdx = 0; break; } curUnitSecond = curUnitSecond / lodScales[curIdx]; curCellWidth = curCellWidth / lodScales[curIdx]; } } // check if prev width is good to show if ( curUnitSecond > minUnitSecond ) { int prev = curIdx - 1; if ( prev < 0 ) prev = 0; float prevCellWidth = curCellWidth / lodScales[prev]; float prevUnitSecond = curUnitSecond / lodScales[prev]; if ( prevCellWidth >= minWidth ) { curIdx = prev; curUnitSecond = prevUnitSecond; curCellWidth = prevCellWidth; } } // init total width and cell-count totalWidth = _animClip.editorScale * _animClip.length * unitWidth; if ( totalWidth > boxWidth/2.0f ) { _animClip.editorOffset = Mathf.Clamp( _animClip.editorOffset, boxWidth - totalWidth - boxWidth/2.0f, 0 ); } else { _animClip.editorOffset = 0; } // get lod interval list int[] lodIntervalList = new int[lodScales.Count+1]; lodIntervalList[curIdx] = 1; for ( int i = curIdx-1; i >= 0; --i ) { lodIntervalList[i] = lodIntervalList[i+1] / lodScales[i]; } for ( int i = curIdx+1; i < lodScales.Count+1; ++i ) { lodIntervalList[i] = lodIntervalList[i-1] * lodScales[i-1]; } // get lod width list float[] lodWidthList = new float[lodScales.Count+1]; lodWidthList[curIdx] = curCellWidth; for ( int i = curIdx-1; i >= 0; --i ) { lodWidthList[i] = lodWidthList[i+1] / lodScales[i]; } for ( int i = curIdx+1; i < lodScales.Count+1; ++i ) { lodWidthList[i] = lodWidthList[i-1] * lodScales[i-1]; } // get idx from int idxFrom = curIdx; for ( int i = 0; i < lodScales.Count+1; ++i ) { if ( lodWidthList[i] > maxWidth ) { idxFrom = i; break; } } // ======================================================== // draw the scalar GUI.BeginGroup( _rect ); // ======================================================== // float xStart = 0.0f; float yStart = _topHeight; // NOTE: +50 here can avoid us clip text so early int iStartFrom = Mathf.CeilToInt( -(_animClip.editorOffset + 50.0f)/curCellWidth ); int cellCount = Mathf.CeilToInt( (boxWidth - _animClip.editorOffset)/curCellWidth ); for ( int i = iStartFrom; i < cellCount; ++i ) { float x = xStart + _animClip.editorOffset + i * curCellWidth + 1; int idx = idxFrom; while ( idx >= 0 ) { if ( i % lodIntervalList[idx] == 0 ) { float heightRatio = lodWidthList[idx] / maxWidth; // draw scalar if ( heightRatio >= 1.0f ) { exEditorHelper.DrawLine ( new Vector2(x, yStart ), new Vector2(x, yStart - _scalarHeight), Color.gray, 1.0f ); exEditorHelper.DrawLine ( new Vector2(x, yStart ), new Vector2(x+1, yStart - _scalarHeight), Color.gray, 1.0f ); } else if ( heightRatio >= 0.5f ) { exEditorHelper.DrawLine ( new Vector2(x, yStart ), new Vector2(x, yStart - _scalarHeight * heightRatio ), Color.gray, 1.0f ); } else { exEditorHelper.DrawLine ( new Vector2(x, yStart ), new Vector2(x, yStart - _scalarHeight * heightRatio ), Color.gray, 1.0f ); } // draw lable if ( lodWidthList[idx] >= widthToShowLabel ) { GUI.Label ( new Rect( x + 4.0f, yStart - 22, 50, 20 ), exTimeHelper.ToString_Frames(i*curUnitSecond,_animClip.sampleRate) ); } // break; } --idx; } } // ======================================================== // draw background // ======================================================== Color old = GUI.color; GUI.color = Color.gray; GUI.DrawTexture( new Rect ( 0, yStart, boxWidth, boxHeight ), exEditorHelper.WhiteTexture() ); GUI.color = old; // ======================================================== // draw event info view background (before in-box scalar) // ======================================================== int eventViewHeight = 25; eventInfoViewRect = new Rect( _animClip.editorOffset, yStart, totalWidth, eventViewHeight ); old = GUI.color; GUI.color = new Color ( 0.65f, 0.65f, 0.65f, 1.0f ); GUI.DrawTexture( eventInfoViewRect, exEditorHelper.WhiteTexture() ); GUI.color = old; // ======================================================== // draw in-box scalar // ======================================================== for ( int i = iStartFrom; i < cellCount; ++i ) { float x = _animClip.editorOffset + i * curCellWidth + 1; int idx = idxFrom; while ( idx >= 0) { if ( i % lodIntervalList[idx] == 0 ) { float ratio = lodWidthList[idx] / maxWidth; exEditorHelper.DrawLine ( new Vector2(x, yStart), new Vector2(x, yStart + boxHeight), new Color( 0.4f, 0.4f, 0.4f, ratio - 0.3f ), 1.0f ); break; } --idx; } } // ======================================================== // draw unused block // ======================================================== exEditorHelper.DrawLine ( new Vector2( 0, yStart + eventViewHeight ), new Vector2( boxWidth, yStart + eventViewHeight ), new Color( 0.8f, 0.8f, 0.8f, 1.0f ), 1.0f ); Color oldBGColor; if ( boxWidth > _animClip.editorOffset + totalWidth ) { Rect unusedBlockRect = new Rect ( _animClip.editorOffset + totalWidth + 1, yStart + 1.0f, boxWidth - (_animClip.editorOffset + totalWidth + 2), boxHeight - 2.0f ); exEditorHelper.DrawRect( unusedBlockRect, new Color( 0.7f, 0.7f, 0.7f, 1.0f ), new Color(0.8f, 0.8f, 0.8f, 1.0f) ); } // ======================================================== // draw frame info view // ======================================================== frameInfoViewRect = new Rect( _animClip.editorOffset, yStart + eventViewHeight, totalWidth, boxHeight - eventViewHeight ); FrameInfoViewField ( frameInfoViewRect, _animClip ); // ======================================================== // draw border // ======================================================== oldBGColor = GUI.backgroundColor; GUI.backgroundColor = Color.black; GUI.Box ( new Rect( 0, yStart, boxWidth, boxHeight ), GUIContent.none, exEditorHelper.RectBorderStyle() ); GUI.backgroundColor = oldBGColor; // ======================================================== // DEBUG { // Color tmpclr = GUI.backgroundColor; // GUI.backgroundColor = Color.red; // GUI.Box ( new Rect( 0, 0, _rect.width, _rect.height ), // GUIContent.none, // exEditorHelper.RectBorderStyle() ); // GUI.backgroundColor = tmpclr; // } DEBUG end GUI.EndGroup(); // draw needle // ======================================================== // GUILayoutUtility.GetRect ( _rect.width, _rect.height + _scalarHeight ); // DEBUG { // GUILayout.BeginHorizontal(); // GUILayout.Space(30); // GUILayout.BeginVertical(); // GUILayout.Label ( "curIdx: " + curIdx ); // GUILayout.Label ( "idxFrom: " + idxFrom ); // GUILayout.Label ( "curCellWidth: " + curCellWidth ); // GUILayout.Label ( "curUnitSecond: " + curUnitSecond ); // GUILayout.Label ( "totalWidth: " + totalWidth ); // for ( int i = 0; i < lodScales.Count; ++i ) { // GUILayout.BeginHorizontal( GUILayout.MaxWidth(800) ); // GUILayout.Label ( "lod scales " + i + " = " + lodScales[i] ); // GUILayout.Label ( "lod width " + i + " = " + lodWidthList[i] ); // GUILayout.Label ( "lod interval " + i + " = " + lodIntervalList[i] ); // GUILayout.EndHorizontal(); // } // GUILayout.EndVertical(); // GUILayout.EndHorizontal(); // } DEBUG end // ======================================================== Event e = Event.current; // ======================================================== if ( _rect.Contains(e.mousePosition) ) { if ( e.type == EventType.ScrollWheel ) { float s = 1000.0f; while ( (_animClip.editorScale/s) < 1.0f || (_animClip.editorScale/s) > 10.0f ) { s /= 10.0f; } _animClip.editorScale -= e.delta.y * s * 0.05f; _animClip.editorScale = Mathf.Clamp( _animClip.editorScale, 0.001f, 100.0f ); Repaint(); e.Use(); } else if ( e.type == EventType.MouseDrag ) { if ( e.button == 1 ) { _animClip.editorOffset += e.delta.x; Repaint(); e.Use(); } } else if ( e.type == EventType.DragUpdated ) { // Show a copy icon on the drag foreach ( Object o in DragAndDrop.objectReferences ) { if ( o is Texture2D || exEditorHelper.IsDirectory(o) ) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; break; } } e.Use(); } else if ( e.type == EventType.DragPerform ) { DragAndDrop.AcceptDrag(); // store old selection state List<Object> oldSelObjects = new List<Object>(); foreach ( Object o in Selection.objects ) { oldSelObjects.Add(o); } Object oldSelActiveObject = Selection.activeObject; // try { EditorUtility.DisplayProgressBar( "Adding Textures...", "Start adding ", 0.5f ); // sort List<Object> objList = new List<Object>(DragAndDrop.objectReferences.Length); foreach ( Object o in DragAndDrop.objectReferences ) { if ( exEditorHelper.IsDirectory(o) ) { Selection.activeObject = o; Object[] objs = Selection.GetFiltered( typeof(Texture2D), SelectionMode.DeepAssets); objList.AddRange(objs); } else if ( o is Texture2D ) { objList.Add(o); } } objList.Sort(exEditorHelper.CompareObjectByName); // DELME { // // sort // Object[] objList = Selection.GetFiltered( typeof(Texture2D), SelectionMode.DeepAssets); // System.Array.Sort( objList, exEditorHelper.CompareObjectByName ); // } DELME end // add objects as frames _animClip.AddFrames( objList.ToArray() ); EditorUtility.ClearProgressBar(); } catch ( System.Exception ) { EditorUtility.ClearProgressBar(); throw; } // CalculatePreviewScale(); Repaint(); // recover selections Selection.activeObject = oldSelActiveObject; Selection.objects = oldSelObjects.ToArray(); e.Use(); } } }
// ------------------------------------------------------------------ /// \param _name the name of the animation state /// \param _animClip the referenced animation clip /// Constructor of exSpriteAnimState, it will copy the settings from _animClip. // ------------------------------------------------------------------ public exSpriteAnimState(string _name, exSpriteAnimClip _animClip) { Init(_name, _animClip); }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void InsertField( Rect _rect, exSpriteAnimClip _animClip ) { if ( insertAt != -1 ) { Rect rect = _rect; if ( insertAt == _animClip.frameInfos.Count ) { rect.x = rect.x + totalWidth - rect.width/2.0f; } else { float curX = 0.0f; for ( int i = 0; i < insertAt; ++i ) { exSpriteAnimClip.FrameInfo fi = _animClip.frameInfos[i]; float width = (fi.length / _animClip.length) * totalWidth; curX += width; } rect.x = rect.x + curX - rect.width/2.0f; } // Color old = GUI.color; GUI.color = new Color( 1.0f, 1.0f, 0.0f, 1.0f ); GUI.DrawTexture( rect, exEditorHelper.WhiteTexture() ); GUI.color = old; Color oldBGColor = GUI.backgroundColor; GUI.backgroundColor = new Color ( 0.0f, 0.0f, 0.0f, 1.0f ); GUI.Box ( rect, GUIContent.none, exEditorHelper.RectBorderStyle() ); GUI.backgroundColor = oldBGColor; } }
// ------------------------------------------------------------------ /// \param _animClip the sprite animatoin clip /// \param _fi frame info /// remove frame info from sprite animation clip // ------------------------------------------------------------------ public static void RemoveFrame( this exSpriteAnimClip _animClip, exSpriteAnimClip.FrameInfo _fi ) { _animClip.frameInfos.Remove(_fi); _animClip.length -= _fi.length; exSpriteAnimationDB.RemoveFrameInfo ( _animClip, _fi ); _animClip.editorNeedRebuild = true; EditorUtility.SetDirty(_animClip); }
// ------------------------------------------------------------------ /// \param _animClip the referenced animation clip /// Constructor of exSpriteAnimState, it will copy the settings from _animClip. // ------------------------------------------------------------------ public exSpriteAnimState ( exSpriteAnimClip _animClip ) { Init ( _animClip.name, _animClip ); }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void FrameInfoField( Rect _rect, exSpriteAnimClip.FrameInfo _fi ) { bool selected = selectedFrameInfos.IndexOf(_fi) != -1; exAtlasDB.ElementInfo elInfo = exAtlasDB.GetElementInfo (_fi.textureGUID); // ======================================================== // draw background // ======================================================== Color old = GUI.color; if ( selected ) { GUI.color = new Color( 0.2f, 0.85f, 0.0f, 0.2f ); } else if ( elInfo == null ) { GUI.color = new Color( 1.0f, 0.0f, 0.0f, 0.2f ); } else { GUI.color = new Color( 1.0f, 0.0f, 0.85f, 0.2f ); } GUI.DrawTexture( _rect, exEditorHelper.WhiteTexture() ); GUI.color = old; // ======================================================== // draw texture // ======================================================== if ( elInfo != null ) { exAtlasInfo atlasInfo = exEditorHelper.LoadAssetFromGUID<exAtlasInfo>(elInfo.guidAtlasInfo); exAtlasInfo.Element el = atlasInfo.elements[elInfo.indexInAtlasInfo]; if ( el.texture != null ) { float width = el.texture.width; float height = el.texture.height; // get the scale float scale = 1.0f; if ( width > _rect.width && height > _rect.height ) { scale = Mathf.Min( _rect.width / width, _rect.height / height ); } else if ( width > _rect.width ) { scale = _rect.width / width; } else if ( height > _rect.height ) { scale = _rect.height / height; } // draw Rect size = new Rect( -el.trimRect.x * scale, -el.trimRect.y * scale, width * scale, height * scale ); GUI.BeginGroup( _rect ); GUI.BeginGroup( new Rect( (_rect.width - el.trimRect.width * scale) * 0.5f, (_rect.height - el.trimRect.height * scale) * 0.5f, el.trimRect.width * scale, el.trimRect.height * scale ) ); GUI.DrawTexture( size, el.texture ); GUI.EndGroup(); GUI.EndGroup(); } } else { Texture2D tex2D = exEditorHelper.LoadAssetFromGUID<Texture2D>(_fi.textureGUID); if ( tex2D != null ) { float width = tex2D.width; float height = tex2D.height; // get the scale float scale = 1.0f; if ( width > _rect.width && height > _rect.height ) { scale = Mathf.Min( _rect.width / width, _rect.height / height ); } else if ( width > _rect.width ) { scale = _rect.width / width; } else if ( height > _rect.height ) { scale = _rect.height / height; } // Rect size = new Rect( 0.0f, 0.0f, width * scale, height * scale ); Rect rect2 = new Rect ( (_rect.width - size.width) * 0.5f, (_rect.height - size.height) * 0.5f, size.width, size.height ); // GUI.BeginGroup( _rect ); GUI.BeginGroup( rect2 ); GUI.DrawTexture( size, tex2D ); GUI.EndGroup(); GUI.EndGroup(); } } // ======================================================== // draw border // ======================================================== Color oldBGColor = GUI.backgroundColor; GUI.backgroundColor = Color.black; GUI.Box ( _rect, GUIContent.none, exEditorHelper.RectBorderStyle() ); GUI.backgroundColor = oldBGColor; }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ static void OnWillSaveAssets(string[] _paths) { ex.onSavingAssets = true; List <exAtlasInfo> rebuildAtlasInfos = new List <exAtlasInfo>(); List <exSpriteAnimClip> rebuildSpriteAnimClips = new List <exSpriteAnimClip>(); List <exGUIBorder> rebuildGuiBorders = new List <exGUIBorder>(); // foreach (string path in _paths) { // check if we are .ex2D_AtlasDB or .ex2D_SpriteAnimationDB if (string.Equals(path, exAtlasDB.dbPath, System.StringComparison.CurrentCultureIgnoreCase) || string.Equals(path, exSpriteAnimationDB.dbPath, System.StringComparison.CurrentCultureIgnoreCase)) { continue; } // check if we are asset if (Path.GetExtension(path) != ".asset") { continue; } Object obj = (Object)AssetDatabase.LoadAssetAtPath(path, typeof(Object)); if (obj == null) { continue; } // ======================================================== // build exAtlasInfo // ======================================================== if (obj is exAtlasInfo) { exAtlasInfo atlasInfo = obj as exAtlasInfo; if (atlasInfo.needRebuild && rebuildAtlasInfos.IndexOf(atlasInfo) == -1) { rebuildAtlasInfos.Add(atlasInfo); } } // ======================================================== // build exSpriteAnimClip // ======================================================== if (obj is exSpriteAnimClip) { exSpriteAnimClip spAnimClip = obj as exSpriteAnimClip; if (spAnimClip.editorNeedRebuild) { rebuildSpriteAnimClips.Add(spAnimClip); } } // TODO { // // ======================================================== // // build exBitmapFont // // ======================================================== // if ( obj is exBitmapFont ) { // exBitmapFont bitmapFont = obj as exBitmapFont; // if ( bitmapFont.editorNeedRebuild ) // Object fontInfo = exEditorHelper.LoadAssetFromGUID(bitmapFont.fontinfoGUID); // bitmapFont.Build( fontInfo ); // } // } TODO end // ======================================================== // build exGUIBorder // ======================================================== if (obj is exGUIBorder) { exGUIBorder guiBorder = obj as exGUIBorder; if (guiBorder.editorNeedRebuild && rebuildGuiBorders.IndexOf(guiBorder) == -1) { guiBorder.editorNeedRebuild = false; EditorUtility.SetDirty(guiBorder); rebuildGuiBorders.Add(guiBorder); } } } // NOTE: we need to make sure exAtlasInfo build before exSpriteAnimClip, // because during build, exAtlasDB will update ElementInfo, and exSpriteAnimClip need this for checking error. // ======================================================== // build exAtlasInfo first // ======================================================== foreach (exAtlasInfo atlasInfo in rebuildAtlasInfos) { exAtlasInfoUtility.Build(atlasInfo); // build sprite animclip that used this atlasInfo exAtlasInfoUtility.BuildSpAnimClipsFromRebuildList(atlasInfo); } // ======================================================== // build exSpriteAnimClip // ======================================================== foreach (exSpriteAnimClip spAnimClip in rebuildSpriteAnimClips) { // NOTE: it could be built in BuildSpAnimClipsFromRebuildList above if (spAnimClip.editorNeedRebuild) { spAnimClip.Build(); } } // ======================================================== // post build // ======================================================== // update scene sprites with rebuild atlasInfo list List <string> rebuildAtlasInfoGUIDs = new List <string>(); foreach (exAtlasInfo atlasInfo in rebuildAtlasInfos) { rebuildAtlasInfoGUIDs.Add(exEditorHelper.AssetToGUID(atlasInfo)); } exSceneHelper.UpdateSprites(rebuildAtlasInfoGUIDs); // update scene sprites with rebuild guiBorder list exSceneHelper.UpdateSpriteBorders(rebuildGuiBorders); // NOTE: without this you will got leaks message // EditorUtility.UnloadUnusedAssets(); ex.onSavingAssets = false; }
// ------------------------------------------------------------------ /// \param _name the name of animation state you want to add /// \param _animClip the sprite animation clip wants to add /// \return the instantiate animation state of the added _animClip /// Add a sprite animation clip, create a new animation state and saves /// it to the lookup table by the name of the clip /// /// \note if the animation already in the exSpriteAnimation.animations, /// it will override the old clip and return a new animation state. // ------------------------------------------------------------------ public exSpriteAnimState AddAnimation ( string _name, exSpriteAnimClip _animClip ) { exSpriteAnimState state = null; // if we already have the animation, just return the animation state if ( animations.IndexOf(_animClip) != -1 ) { state = nameToState[_name]; if ( state.clip != _animClip ) { state = new exSpriteAnimState( _name, _animClip ); nameToState[_name] = state; } return state; } // animations.Add (_animClip); state = new exSpriteAnimState( _name, _animClip ); nameToState[_name] = state; return state; }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void ResizeField(exSpriteAnimClip _animClip) { float frameInfoHeight = frameInfoViewRect.height - 2.0f * yFrameInfoOffset; // add indices List <int> indices = new List <int>(); foreach (exSpriteAnimClip.FrameInfo fi in selectedFrameInfos) { int idx = _animClip.frameInfos.IndexOf(fi); if (idx != -1) { indices.Add(idx); } } indices.Sort(); // check if resizable int lastIdx = -1; // NOTE: it is possible when we play the game, turn back, the selectedFrameInfos.Count > 0 but nothing inside it is correct. bool canResize = indices.Count > 0; foreach (int idx in indices) { if (lastIdx != -1 && idx - lastIdx != 1) { canResize = false; break; } lastIdx = idx; } // if (canResize) { float borderWidth = 0.0f; float curX = 0.0f; for (int i = 0; i < indices[0]; ++i) { exSpriteAnimClip.FrameInfo fi = _animClip.frameInfos[i]; float width = (fi.length / _animClip.length) * totalWidth; curX += width; } foreach (exSpriteAnimClip.FrameInfo fi in selectedFrameInfos) { float width = (fi.length / _animClip.length) * totalWidth; borderWidth += width; } float xStart = curX; float yStart = yFrameInfoOffset; Color oldBGColor = GUI.backgroundColor; GUI.backgroundColor = Color.white; Rect rect = new Rect(xStart, yStart, borderWidth, frameInfoHeight); GUI.Box(rect, GUIContent.none, exEditorHelper.RectBorderStyle()); GUI.backgroundColor = oldBGColor; // if (selectedFrameInfos.Count > 1) { playingSelects = true; playingStart = (xStart + 0.1f) / totalWidth * _animClip.length; playingEnd = (xStart + borderWidth) / totalWidth * _animClip.length; } // draw resize handle ResizeHandleField(new Rect(xStart + borderWidth - 5.0f, yStart, 10.0f, frameInfoHeight)); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void Init( string _name, exSpriteAnimClip _animClip ) { clip = _animClip; name = _name; wrapMode = _animClip.wrapMode; stopAction = _animClip.stopAction; length = _animClip.length; speed = _animClip.speed; frameTimes = new List<float>(_animClip.frameInfos.Count); float tmp = 0.0f; for ( int i = 0; i < _animClip.frameInfos.Count; ++i ) { tmp += _animClip.frameInfos[i].length; frameTimes.Add(tmp); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ exSpriteAnimClip.EventInfo EventInfoField( Rect _rect, exSpriteAnimClip.EventInfo _eventInfo ) { bool selected = selectedEventInfos.IndexOf(_eventInfo) != -1; // if ( selected ) { exEditorHelper.DrawRect ( _rect, new Color ( 0.0f, 0.3f, 1.0f, 1.0f ), new Color ( 1.0f, 1.0f, 1.0f, 1.0f ) ); } else if ( _eventInfo.methodName == "" ) { exEditorHelper.DrawRect ( _rect, new Color ( 1.0f, 0.0f, 0.0f, 0.5f ), new Color ( 0.2f, 0.2f, 0.2f, 1.0f ) ); } else { exEditorHelper.DrawRect ( _rect, new Color ( 0.0f, 1.0f, 0.0f, 1.0f ), new Color ( 0.2f, 0.2f, 0.2f, 1.0f ) ); } // float at = _rect.x + Mathf.Round(_rect.width/2.0f); Vector2 start = new Vector2( at, _rect.yMax ); Vector2 end = new Vector2( at, _rect.y + eventInfoViewRect.height ); exEditorHelper.DrawLine ( start, end, Color.black, 1.0f ); // ======================================================== Event e = Event.current; // ======================================================== if ( e.isMouse ) { if ( e.type == EventType.MouseDown && e.button == 0 ) { if ( _rect.Contains(e.mousePosition) ) { GUIUtility.keyboardControl = -1; // remove any keyboard control selectedFrameInfos.Clear(); return _eventInfo; } } } return null; }
// ------------------------------------------------------------------ /// \param _animClip the referenced animation clip /// Constructor of exSpriteAnimState, it will copy the settings from _animClip. // ------------------------------------------------------------------ public exSpriteAnimState(exSpriteAnimClip _animClip) { Init(_animClip.name, _animClip); }
/////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////// // ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ static void OnPostprocessAllAssets(string[] _importedAssets, string[] _deletedAssets, string[] _movedAssets, string[] _movedFromAssetPaths) { List <exAtlasInfo> updateAtlasInfos = new List <exAtlasInfo>(); List <string> atlasInfoGUIDs = new List <string>(); // ======================================================== // import assets // ======================================================== foreach (string path in _importedAssets) { // check if we are .ex2D_AtlasDB or .ex2D_SpriteAnimationDB if (string.Equals(path, exAtlasDB.dbPath, System.StringComparison.CurrentCultureIgnoreCase) || string.Equals(path, exSpriteAnimationDB.dbPath, System.StringComparison.CurrentCultureIgnoreCase)) { continue; } // check if we are asset string ext = Path.GetExtension(path); if (ext != ".asset" && ext != ".png" && ext != ".jpg" && ext != ".tga") { continue; } // Object obj = (Object)AssetDatabase.LoadAssetAtPath(path, typeof(Object)); if (obj == null) { continue; } // ======================================================== // Texture2D // NOTE: if we are OnWillSaveAssets, it is possible we reimport // textures if they are not valid for atlas. and when import it will // trigger things here which will lead to infinite cycle. // ======================================================== if (ex.onSavingAssets == false && obj is Texture2D) { Texture2D tex2d = obj as Texture2D; exAtlasDB.ElementInfo ei = exAtlasDB.GetElementInfo(tex2d); if (ei != null) { exAtlasInfo atlasInfo = exEditorHelper.LoadAssetFromGUID <exAtlasInfo>(ei.guidAtlasInfo); atlasInfo.UpdateElement(tex2d, true, true); if (atlasInfo && updateAtlasInfos.IndexOf(atlasInfo) == -1) { atlasInfo.needLayout = true; updateAtlasInfos.Add(atlasInfo); } } continue; } // ======================================================== // exAtlasInfo // ======================================================== if (obj is exAtlasInfo) { exAtlasInfo atlasInfo = obj as exAtlasInfo; exAtlasDB.AddAtlasInfo(atlasInfo); // Debug.Log( "add atlas " + path ); // DEBUG } // ======================================================== // exSpriteAnimClip // ======================================================== if (obj is exSpriteAnimClip) { exSpriteAnimClip spAnimClip = obj as exSpriteAnimClip; exSpriteAnimationDB.AddSpriteAnimClip(spAnimClip); // Debug.Log( "add sprite anim clip " + path ); // DEBUG } } // build exAtlasInfo first foreach (exAtlasInfo atlasInfo in updateAtlasInfos) { // NOTE: Build atlas without import texture, without this, we will crash when changing import settings of a texture and rebuild it. exAtlasInfoUtility.Build(atlasInfo, true); // NOTE: no need to update scene sprite and sprite animation clip, because we didn't change index atlasInfoGUIDs.Add(exEditorHelper.AssetToGUID(atlasInfo)); } // ======================================================== // deleted assets // ======================================================== foreach (string path in _deletedAssets) { // check if we are .ex2D_AtlasDB or .ex2D_SpriteAnimationDB if (string.Equals(path, exAtlasDB.dbPath, System.StringComparison.CurrentCultureIgnoreCase) || string.Equals(path, exSpriteAnimationDB.dbPath, System.StringComparison.CurrentCultureIgnoreCase)) { continue; } // check if we are asset if (Path.GetExtension(path) != ".asset") { continue; } // string guid = AssetDatabase.AssetPathToGUID(path); // check if we have the guid in the exAtlasInfo if (exAtlasDB.HasAtlasInfoGUID(guid)) { exAtlasDB.RemoveAtlasInfo(guid); atlasInfoGUIDs.Add(guid); // Debug.Log( "remove atlas " + path ); // DEBUG } // check if we have the guid in the exSpriteAnimClip else if (exSpriteAnimationDB.HasSpriteAnimClipGUID(guid)) { exSpriteAnimationDB.RemoveSpriteAnimClip(guid); // Debug.Log( "remove sprite anim clip " + path ); // DEBUG } } exSceneHelper.UpdateSprites(atlasInfoGUIDs); // DISABLE { // for ( int i = 0; i < _movedAssets.Length; ++i ) // Debug.Log("Moved Asset: " + _movedAssets[i] + " from: " + _movedFromAssetPaths[i]); // } DISABLE end }
// ------------------------------------------------------------------ /// \param _animClip the sprite animation clip wants to add /// \return the instantiate animation state of the added _animClip /// Add a sprite animation clip, create a new animation state and saves /// it to the lookup table by the name of the clip /// /// \note if the animation already in the exSpriteAnimation.animations, /// it will override the old clip and return a new animation state. // ------------------------------------------------------------------ public exSpriteAnimState AddAnimation(exSpriteAnimClip _animClip) { return(AddAnimation(_animClip.name, _animClip)); }
// ------------------------------------------------------------------ /// \param _animClip the sprite animation clip /// \param _frames the frames /// \return the seconds // ------------------------------------------------------------------ public static float FrameToSeconds(this exSpriteAnimClip _animClip, int _frames) { return(_frames / _animClip.sampleRate); }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void EventInfoViewField( Rect _rect, exSpriteAnimClip _animClip ) { float maxHeight = _rect.height-3; Rect lastRect = new Rect( -100, _rect.y, 7, maxHeight ); Rect curRect = new Rect( -100, _rect.y, 7, maxHeight ); exSpriteAnimClip.EventInfo lastClicked = null; // NOTE: when editor.playing, the selectedFrameInfos will become invalid, don't know why :( bool selectedAreInvalid = true; foreach ( exSpriteAnimClip.EventInfo eventInfo in _animClip.eventInfos ) { if ( selectedEventInfos.IndexOf(eventInfo) != -1 ) selectedAreInvalid = false; float at = _rect.x + (eventInfo.time / _animClip.length) * totalWidth; lastRect = curRect; curRect = new Rect( at - 4, _rect.y, 7, maxHeight ); if ( exIntersection2D.RectRect( lastRect, curRect ) ) { curRect.height = Mathf.Max( lastRect.height - 5.0f, 10.0f ); } exSpriteAnimClip.EventInfo clicked_ei = null; if ( at >= spriteAnimClipRect.x && at <= spriteAnimClipRect.xMax ) clicked_ei = EventInfoField ( curRect, eventInfo ); if ( clicked_ei != null ) lastClicked = clicked_ei; } if ( selectedAreInvalid ) selectedEventInfos.Clear(); // ======================================================== Event e = Event.current; // ======================================================== if ( lastClicked != null ) { if ( e.command || e.control ) { ToggleSelected(lastClicked); } else { inDraggingEventInfoState = true; activeEventInfo = lastClicked; bool selected = selectedEventInfos.IndexOf(lastClicked) != -1; if ( selected == false ) { if ( e.command == false && e.control == false ) { selectedEventInfos.Clear(); AddSelected(lastClicked); } } } e.Use(); Repaint(); } // ======================================================== // // ======================================================== if ( e.isMouse ) { if ( _rect.Contains(e.mousePosition) ) { // mouse down if ( e.type == EventType.MouseDown && e.button == 0 && e.clickCount == 1 ) { GUIUtility.keyboardControl = -1; // remove any keyboard control selectedFrameInfos.Clear(); mouseDownPos = e.mousePosition; inRectSelectEventState = true; UpdateSelectRect (mouseDownPos); ConfirmRectSelectEventInfo(); Repaint(); e.Use(); } // double click mouse down if ( e.type == EventType.MouseDown && e.clickCount == 2 && e.command == false ) { // Undo.RegisterUndo(curEdit, "AddEventInfo"); // DISABLE exSpriteAnimClip.EventInfo eventInfo = new exSpriteAnimClip.EventInfo(); eventInfo.time = curEdit.SnapToSeconds( ((e.mousePosition.x - _rect.x) * _animClip.length) / totalWidth ); _animClip.AddEvent(eventInfo); EditorUtility.SetDirty(_animClip); e.Use(); } } } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void ToggleSelected( exSpriteAnimClip.FrameInfo _fi ) { if ( selectedFrameInfos.IndexOf(_fi) == -1 ) { selectedFrameInfos.Add(_fi); } else { selectedFrameInfos.Remove(_fi); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void FrameInfoViewField(Rect _rect, exSpriteAnimClip _animClip) { float curX = 0.0f; int oldDepth = GUI.depth; GUI.BeginGroup(_rect); // ======================================================== // draw none selected object first // ======================================================== List <exSpriteAnimClip.FrameInfo> invalidFrames = new List <exSpriteAnimClip.FrameInfo>(); foreach (exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos) { float width = (fi.length / _animClip.length) * totalWidth; Texture2D tex2D = exEditorHelper.LoadAssetFromGUID <Texture2D>(fi.textureGUID); if (tex2D == null) { invalidFrames.Add(fi); continue; } FrameInfoField(new Rect(curX, yFrameInfoOffset, width, _rect.height - 2 * yFrameInfoOffset), fi); curX += width; } foreach (exSpriteAnimClip.FrameInfo fi in invalidFrames) { curEdit.RemoveFrame(fi); selectedFrameInfos.Remove(fi); // unselect it if we have } // ======================================================== // draw resize field // ======================================================== playingSelects = false; if (selectedFrameInfos.Count > 0) { ResizeField(_animClip); } // ======================================================== // process mouse event Event e = Event.current; curX = 0.0f; // ======================================================== foreach (exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos) { bool selected = selectedFrameInfos.IndexOf(fi) != -1; float width = (fi.length / _animClip.length) * totalWidth; Rect rect = new Rect(curX, yFrameInfoOffset, width, _rect.height - 2 * yFrameInfoOffset); if (e.type == EventType.MouseDown && e.button == 0) { if (rect.Contains(e.mousePosition)) { curSeconds = (curX + 0.1f) / totalWidth * _animClip.length; GUIUtility.keyboardControl = -1; // remove any keyboard control selectedEventInfos.Clear(); // unselect all events if (e.command || e.control) { ToggleSelected(fi); } else { inDraggingFrameInfoState = true; if (selected == false) { if (e.command == false && e.control == false) { selectedFrameInfos.Clear(); AddSelected(fi); } } } e.Use(); Repaint(); } } curX += width; } GUI.EndGroup(); GUI.depth = oldDepth; }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void ToggleSelected( exSpriteAnimClip.EventInfo _ei ) { if ( selectedEventInfos.IndexOf(_ei) == -1 ) { selectedEventInfos.Add(_ei); } else { selectedEventInfos.Remove(_ei); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ public override void OnInspectorGUI() { exSprite sprite = editSpAnim.GetComponent <exSprite>(); bool checkDefaultSprite = (sprite != null) && string.IsNullOrEmpty(sprite.textureGUID); EditorGUIUtility.LookLikeInspector(); EditorGUILayout.Space(); EditorGUI.indentLevel = 1; // ======================================================== // Play Automatically // ======================================================== editSpAnim.playAutomatically = EditorGUILayout.Toggle("Play Automatically", editSpAnim.playAutomatically); // ======================================================== // Default Animation // ======================================================== GUILayout.BeginHorizontal(); editSpAnim.defaultAnimation = (exSpriteAnimClip)EditorGUILayout.ObjectField("Default Animation" , editSpAnim.defaultAnimation , typeof(exSpriteAnimClip) , false ); if (GUILayout.Button("Edit...", GUILayout.Width(40), GUILayout.Height(15))) { exSpriteAnimClipEditor editor = exSpriteAnimClipEditor.NewWindow(); editor.Edit(editSpAnim.defaultAnimation); } if (editSpAnim.defaultAnimation != null) { int idx = editSpAnim.animations.IndexOf(editSpAnim.defaultAnimation); if (idx == -1) { editSpAnim.animations.Add(editSpAnim.defaultAnimation); } } GUILayout.EndHorizontal(); // ======================================================== // Animations // ======================================================== Rect lastRect = new Rect(0, 0, 1, 1); Rect dropRect = new Rect(0, 0, 1, 1); EditorGUI.indentLevel = 0; showAnimations = EditorGUILayout.Foldout(showAnimations, "Animations"); if (showAnimations) { EditorGUI.indentLevel = 2; // int count = EditorGUILayout.IntField ( "Size", editSpAnim.animations.Count ); int count = exEditorHelper.IntField("Size", editSpAnim.animations.Count); lastRect = GUILayoutUtility.GetLastRect(); dropRect.height = lastRect.yMax - dropRect.y; count = Mathf.Max(count, 0); if (count != editSpAnim.animations.Count) { // if (count > editSpAnim.animations.Count) { int num = count - editSpAnim.animations.Count; for (int i = 0; i < num; ++i) { editSpAnim.animations.Add(null); } } else { editSpAnim.animations.RemoveRange(count, editSpAnim.animations.Count - count); } // GUI.changed = true; } int idxRemoved = -1; for (int i = 0; i < editSpAnim.animations.Count; ++i) { GUILayout.BeginHorizontal(); editSpAnim.animations[i] = (exSpriteAnimClip)EditorGUILayout.ObjectField("[" + i + "]" , editSpAnim.animations[i] , typeof(exSpriteAnimClip) , false ); if (GUILayout.Button("-", GUILayout.Width(15), GUILayout.Height(15))) { idxRemoved = i; } if (GUILayout.Button("Edit...", GUILayout.Width(40), GUILayout.Height(15))) { exSpriteAnimClipEditor editor = exSpriteAnimClipEditor.NewWindow(); editor.Edit(editSpAnim.animations[i]); } // TODO: I think we can instantiate animation state { // EditorGUI.indentLevel += 1; // // TODO: // EditorGUI.indentLevel -= 1; // } TODO end GUILayout.EndHorizontal(); } // if we have item to remove if (idxRemoved != -1) { exSpriteAnimClip animClip = editSpAnim.animations[idxRemoved]; editSpAnim.animations.RemoveAt(idxRemoved); if (animClip == editSpAnim.defaultAnimation) { editSpAnim.defaultAnimation = null; } } EditorGUI.indentLevel = 1; EditorGUILayout.Space(); lastRect = GUILayoutUtility.GetLastRect(); dropRect.x = lastRect.x + 30; dropRect.y = lastRect.yMax; dropRect.width = lastRect.xMax - 30 - 4; dropRect.height = 20; exEditorHelper.DrawRect(dropRect, new Color(0.2f, 0.2f, 0.2f, 1.0f), new Color(0.5f, 0.5f, 0.5f, 1.0f)); GUILayout.Space(20); // ======================================================== // drag and drop // ======================================================== if (dropRect.Contains(Event.current.mousePosition)) { if (Event.current.type == EventType.DragUpdated) { // Show a copy icon on the drag foreach (Object o in DragAndDrop.objectReferences) { if (o is exSpriteAnimClip) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; break; } } } else if (Event.current.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (Object o in DragAndDrop.objectReferences) { if (o is exSpriteAnimClip) { editSpAnim.animations.Add(o as exSpriteAnimClip); } } GUI.changed = true; } } } EditorGUILayout.Space(); // TODO: FIXME { // ======================================================== // // ======================================================== if (checkDefaultSprite && editSpAnim.animations.Count > 0 && editSpAnim.animations[0] != null && editSpAnim.animations[0].frameInfos.Count > 0) { exSpriteAnimClip.FrameInfo fi = editSpAnim.animations[0].frameInfos[0]; sprite.textureGUID = fi.textureGUID; sprite.SetSprite(fi.atlas, fi.index); sprite.Build(); } // } TODO end // ======================================================== // set dirty if anything changed // ======================================================== if (GUI.changed) { EditorUtility.SetDirty(editSpAnim); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void AddSelected( exSpriteAnimClip.FrameInfo _fi ) { if ( selectedFrameInfos.IndexOf(_fi) == -1 ) { selectedFrameInfos.Add(_fi); } }
// ------------------------------------------------------------------ /// \param _animClip the sprite animation clip wants to add /// \return the instantiate animation state of the added _animClip /// Add a sprite animation clip, create a new animation state and saves /// it to the lookup table by the name of the clip /// /// \note if the animation already in the exSpriteAnimation.animations, /// it will override the old clip and return a new animation state. // ------------------------------------------------------------------ public exSpriteAnimState AddAnimation ( exSpriteAnimClip _animClip ) { return AddAnimation ( _animClip.name, _animClip ); }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void AddSelected( exSpriteAnimClip.EventInfo _ei ) { if ( selectedEventInfos.IndexOf(_ei) == -1 ) { selectedEventInfos.Add(_ei); } }
// ------------------------------------------------------------------ /// \param _animClip the sprite animation clip wants to remove /// Remove a sprite animation clip from exSpriteAnimation.animations, // ------------------------------------------------------------------ public void RemoveAnimation ( exSpriteAnimClip _animClip ) { // if we already have the animation, just return the animation state if ( animations.IndexOf(_animClip) == -1 ) { return; } // animations.Remove (_animClip); nameToState.Remove (_animClip.name); }
// DISABLE: the focus only occur when main window lost foucs, then come in { // // ------------------------------------------------------------------ // // Desc: // // ------------------------------------------------------------------ // void OnFocus () { // OnSelectionChange (); // } // } DISABLE end // ------------------------------------------------------------------ /// \param _obj /// Check if the object is valid sprite animation clip and open it in sprite animation clip editor. // ------------------------------------------------------------------ public void Edit( Object _obj ) { // check if repaint if ( curEdit != _obj ) { Object obj = _obj; if ( obj is GameObject ) { GameObject go = obj as GameObject; // get exSpriteAnimation from itself, children or root exSpriteAnimation spAnim = go.GetComponent<exSpriteAnimation>(); // DISABLE { // if ( spAnim == null ) { // spAnim = go.GetComponentInChildren<exSpriteAnimation>(); // if ( spAnim == null ) { // spAnim = go.transform.root.GetComponentInChildren<exSpriteAnimation>(); // } // } // } DISABLE end if ( spAnim ) { int idx = spAnim.animations.IndexOf(curEdit); // if curEdit is exists in the selected gameObject, don't do anything if ( idx != -1 ) { Repaint (); return; } // if we have default animation, use it if ( spAnim.defaultAnimation != null ) { obj = spAnim.defaultAnimation; } // else we will check if we have animations in our list and use the first one else if ( spAnim.animations.Count > 0 ) { obj = spAnim.animations[0]; } } } // if this is another anim clip, swtich to it. if ( obj is exSpriteAnimClip && obj != curEdit ) { curEdit = obj as exSpriteAnimClip; Init (); Repaint (); return; } } }
// ------------------------------------------------------------------ /// \param _name the name of the animation state /// \param _animClip the referenced animation clip /// Constructor of exSpriteAnimState, it will copy the settings from _animClip. // ------------------------------------------------------------------ public exSpriteAnimState ( string _name, exSpriteAnimClip _animClip ) { Init ( _name, _animClip ); }
public void addAnimation(exSpriteAnimClip animation) { m_animation.animations.Add(animation); }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void FrameInfoViewField( Rect _rect, exSpriteAnimClip _animClip ) { float curX = 0.0f; int oldDepth = GUI.depth; GUI.BeginGroup(_rect); // ======================================================== // draw none selected object first // ======================================================== List<exSpriteAnimClip.FrameInfo> invalidFrames = new List<exSpriteAnimClip.FrameInfo>(); foreach ( exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos ) { float width = (fi.length / _animClip.length) * totalWidth; Texture2D tex2D = exEditorHelper.LoadAssetFromGUID<Texture2D>(fi.textureGUID); if ( tex2D == null ) { invalidFrames.Add(fi); continue; } FrameInfoField ( new Rect( curX, yFrameInfoOffset, width, _rect.height - 2 * yFrameInfoOffset ), fi ); curX += width; } foreach ( exSpriteAnimClip.FrameInfo fi in invalidFrames ) { curEdit.RemoveFrame(fi); selectedFrameInfos.Remove(fi); // unselect it if we have } // ======================================================== // draw resize field // ======================================================== playingSelects = false; if ( selectedFrameInfos.Count > 0 ) ResizeField (_animClip); // ======================================================== // process mouse event Event e = Event.current; curX = 0.0f; // ======================================================== foreach ( exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos ) { bool selected = selectedFrameInfos.IndexOf(fi) != -1; float width = (fi.length / _animClip.length) * totalWidth; Rect rect = new Rect( curX, yFrameInfoOffset, width, _rect.height - 2 * yFrameInfoOffset ); if ( e.type == EventType.MouseDown && e.button == 0 ) { if ( rect.Contains( e.mousePosition ) ) { curSeconds = (curX+0.1f)/totalWidth * _animClip.length; GUIUtility.keyboardControl = -1; // remove any keyboard control selectedEventInfos.Clear(); // unselect all events if ( e.command || e.control ) { ToggleSelected(fi); } else { inDraggingFrameInfoState = true; if ( selected == false ) { if ( e.command == false && e.control == false ) { selectedFrameInfos.Clear(); AddSelected(fi); } } } e.Use(); Repaint(); } } curX += width; } GUI.EndGroup(); GUI.depth = oldDepth; }
// ------------------------------------------------------------------ /// \param _animClip the sprite animation clip /// add the sprite animation clip to the sprite animation db // ------------------------------------------------------------------ public static void AddSpriteAnimClip( exSpriteAnimClip _animClip ) { Init(); string guidAnimClip = exEditorHelper.AssetToGUID (_animClip); if ( db.spAnimClipGUIDs.Contains(guidAnimClip) == false ) { db.spAnimClipGUIDs.Add(guidAnimClip); // update sprite anim clip foreach ( exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos ) { AddFrameInfo ( _animClip, fi ); } EditorUtility.SetDirty(db); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void ResizeField( exSpriteAnimClip _animClip ) { float frameInfoHeight = frameInfoViewRect.height - 2.0f * yFrameInfoOffset; // add indices List<int> indices = new List<int>(); foreach ( exSpriteAnimClip.FrameInfo fi in selectedFrameInfos ) { int idx = _animClip.frameInfos.IndexOf(fi); if ( idx != -1 ) indices.Add(idx); } indices.Sort(); // check if resizable int lastIdx = -1; // NOTE: it is possible when we play the game, turn back, the selectedFrameInfos.Count > 0 but nothing inside it is correct. bool canResize = indices.Count > 0; foreach ( int idx in indices ) { if ( lastIdx != -1 && idx - lastIdx != 1 ) { canResize = false; break; } lastIdx = idx; } // if ( canResize ) { float borderWidth = 0.0f; float curX = 0.0f; for ( int i = 0; i < indices[0]; ++i ) { exSpriteAnimClip.FrameInfo fi = _animClip.frameInfos[i]; float width = (fi.length / _animClip.length) * totalWidth; curX += width; } foreach ( exSpriteAnimClip.FrameInfo fi in selectedFrameInfos ) { float width = (fi.length / _animClip.length) * totalWidth; borderWidth += width; } float xStart = curX; float yStart = yFrameInfoOffset; Color oldBGColor = GUI.backgroundColor; GUI.backgroundColor = Color.white; Rect rect = new Rect ( xStart, yStart, borderWidth, frameInfoHeight ); GUI.Box ( rect, GUIContent.none, exEditorHelper.RectBorderStyle() ); GUI.backgroundColor = oldBGColor; // if ( selectedFrameInfos.Count > 1 ) { playingSelects = true; playingStart = (xStart+0.1f)/totalWidth * _animClip.length; playingEnd = (xStart + borderWidth)/totalWidth * _animClip.length; } // draw resize handle ResizeHandleField ( new Rect( xStart + borderWidth - 5.0f, yStart, 10.0f, frameInfoHeight ) ); } }
// ------------------------------------------------------------------ /// \param _animClip the animation clip /// \param _fi the frame info in the _animClip /// remove frame info from sprite animation cip db // ------------------------------------------------------------------ public static void RemoveFrameInfo( exSpriteAnimClip _animClip, exSpriteAnimClip.FrameInfo _fi ) { Init(); // first, we need to check if the textureGUID of this frame is used in another frame of the same clip foreach ( exSpriteAnimClip.FrameInfo fi in _animClip.frameInfos ) { if ( fi.textureGUID == _fi.textureGUID ) return; } // if we are the only textureGUID used in this clip, remove the clip if ( db.texGuidToAnimClipGUIDs.ContainsKey(_fi.textureGUID) ) { List<string> animClips = db.texGuidToAnimClipGUIDs[_fi.textureGUID]; string guidAnimClip = exEditorHelper.AssetToGUID(_animClip); animClips.Remove (guidAnimClip); // find and remove GUIDInfo RemoveGUIDInfo ( guidAnimClip, _fi.textureGUID ); } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void SpriteAnimClipField(Rect _rect, int _topHeight, int _botHeight, int _scalarHeight, exSpriteAnimClip _animClip) { // ======================================================== // init varaible // ======================================================== float boxWidth = _rect.width; float boxHeight = _rect.height - _topHeight - _botHeight; // NOTE: a protection to prevent while dead loop _animClip.editorScale = Mathf.Clamp(_animClip.editorScale, 0.01f, 10.0f); // constant float widthToShowLabel = 60.0f; float minWidth = 10.0f; float maxWidth = 80.0f; float minUnitSecond = 1.0f / _animClip.sampleRate; // variable // int[] lodScales = new int[] { 5, 2, 3, 2 }; List <int> lodScales = new List <int>(); int tmpSampleRate = (int)_animClip.sampleRate; while (true) { int div = 0; if (tmpSampleRate == 30) { div = 3; } else if (tmpSampleRate % 2 == 0) { div = 2; } else if (tmpSampleRate % 5 == 0) { div = 5; } else if (tmpSampleRate % 3 == 0) { div = 3; } else { break; } tmpSampleRate /= div; lodScales.Insert(0, div); } int curIdx = lodScales.Count; lodScales.AddRange(new int[] { 5, 2, 3, 2, 5, 2, 3, 2, }); // float unitWidth = 1000.0f; // width for 1 second float curUnitSecond = 1.0f; float curCellWidth = unitWidth * _animClip.editorScale; // get curUnitSecond and curIdx if (curCellWidth < minWidth) { while (curCellWidth < minWidth) { curUnitSecond = curUnitSecond * lodScales[curIdx]; curCellWidth = curCellWidth * lodScales[curIdx]; curIdx += 1; if (curIdx >= lodScales.Count) { curIdx = lodScales.Count - 1; break; } } } else if (curCellWidth > maxWidth) { while ((curCellWidth > maxWidth) && (curUnitSecond > minUnitSecond)) { curIdx -= 1; if (curIdx < 0) { curIdx = 0; break; } curUnitSecond = curUnitSecond / lodScales[curIdx]; curCellWidth = curCellWidth / lodScales[curIdx]; } } // check if prev width is good to show if (curUnitSecond > minUnitSecond) { int prev = curIdx - 1; if (prev < 0) { prev = 0; } float prevCellWidth = curCellWidth / lodScales[prev]; float prevUnitSecond = curUnitSecond / lodScales[prev]; if (prevCellWidth >= minWidth) { curIdx = prev; curUnitSecond = prevUnitSecond; curCellWidth = prevCellWidth; } } // init total width and cell-count totalWidth = _animClip.editorScale * _animClip.length * unitWidth; if (totalWidth > boxWidth / 2.0f) { _animClip.editorOffset = Mathf.Clamp(_animClip.editorOffset, boxWidth - totalWidth - boxWidth / 2.0f, 0); } else { _animClip.editorOffset = 0; } // get lod interval list int[] lodIntervalList = new int[lodScales.Count + 1]; lodIntervalList[curIdx] = 1; for (int i = curIdx - 1; i >= 0; --i) { lodIntervalList[i] = lodIntervalList[i + 1] / lodScales[i]; } for (int i = curIdx + 1; i < lodScales.Count + 1; ++i) { lodIntervalList[i] = lodIntervalList[i - 1] * lodScales[i - 1]; } // get lod width list float[] lodWidthList = new float[lodScales.Count + 1]; lodWidthList[curIdx] = curCellWidth; for (int i = curIdx - 1; i >= 0; --i) { lodWidthList[i] = lodWidthList[i + 1] / lodScales[i]; } for (int i = curIdx + 1; i < lodScales.Count + 1; ++i) { lodWidthList[i] = lodWidthList[i - 1] * lodScales[i - 1]; } // get idx from int idxFrom = curIdx; for (int i = 0; i < lodScales.Count + 1; ++i) { if (lodWidthList[i] > maxWidth) { idxFrom = i; break; } } // ======================================================== // draw the scalar GUI.BeginGroup(_rect); // ======================================================== // float xStart = 0.0f; float yStart = _topHeight; // NOTE: +50 here can avoid us clip text so early int iStartFrom = Mathf.CeilToInt(-(_animClip.editorOffset + 50.0f) / curCellWidth); int cellCount = Mathf.CeilToInt((boxWidth - _animClip.editorOffset) / curCellWidth); for (int i = iStartFrom; i < cellCount; ++i) { float x = xStart + _animClip.editorOffset + i * curCellWidth + 1; int idx = idxFrom; while (idx >= 0) { if (i % lodIntervalList[idx] == 0) { float heightRatio = lodWidthList[idx] / maxWidth; // draw scalar if (heightRatio >= 1.0f) { exEditorHelper.DrawLine(new Vector2(x, yStart), new Vector2(x, yStart - _scalarHeight), Color.gray, 1.0f); exEditorHelper.DrawLine(new Vector2(x, yStart), new Vector2(x + 1, yStart - _scalarHeight), Color.gray, 1.0f); } else if (heightRatio >= 0.5f) { exEditorHelper.DrawLine(new Vector2(x, yStart), new Vector2(x, yStart - _scalarHeight * heightRatio), Color.gray, 1.0f); } else { exEditorHelper.DrawLine(new Vector2(x, yStart), new Vector2(x, yStart - _scalarHeight * heightRatio), Color.gray, 1.0f); } // draw lable if (lodWidthList[idx] >= widthToShowLabel) { GUI.Label(new Rect(x + 4.0f, yStart - 22, 50, 20), exTimeHelper.ToString_Frames(i * curUnitSecond, _animClip.sampleRate)); } // break; } --idx; } } // ======================================================== // draw background // ======================================================== Color old = GUI.color; GUI.color = Color.gray; GUI.DrawTexture(new Rect(0, yStart, boxWidth, boxHeight), exEditorHelper.WhiteTexture()); GUI.color = old; // ======================================================== // draw event info view background (before in-box scalar) // ======================================================== int eventViewHeight = 25; eventInfoViewRect = new Rect(_animClip.editorOffset, yStart, totalWidth, eventViewHeight); old = GUI.color; GUI.color = new Color(0.65f, 0.65f, 0.65f, 1.0f); GUI.DrawTexture(eventInfoViewRect, exEditorHelper.WhiteTexture()); GUI.color = old; // ======================================================== // draw in-box scalar // ======================================================== for (int i = iStartFrom; i < cellCount; ++i) { float x = _animClip.editorOffset + i * curCellWidth + 1; int idx = idxFrom; while (idx >= 0) { if (i % lodIntervalList[idx] == 0) { float ratio = lodWidthList[idx] / maxWidth; exEditorHelper.DrawLine(new Vector2(x, yStart), new Vector2(x, yStart + boxHeight), new Color(0.4f, 0.4f, 0.4f, ratio - 0.3f), 1.0f); break; } --idx; } } // ======================================================== // draw unused block // ======================================================== exEditorHelper.DrawLine(new Vector2(0, yStart + eventViewHeight), new Vector2(boxWidth, yStart + eventViewHeight), new Color(0.8f, 0.8f, 0.8f, 1.0f), 1.0f); Color oldBGColor; if (boxWidth > _animClip.editorOffset + totalWidth) { Rect unusedBlockRect = new Rect(_animClip.editorOffset + totalWidth + 1, yStart + 1.0f, boxWidth - (_animClip.editorOffset + totalWidth + 2), boxHeight - 2.0f); exEditorHelper.DrawRect(unusedBlockRect, new Color(0.7f, 0.7f, 0.7f, 1.0f), new Color(0.8f, 0.8f, 0.8f, 1.0f)); } // ======================================================== // draw frame info view // ======================================================== frameInfoViewRect = new Rect(_animClip.editorOffset, yStart + eventViewHeight, totalWidth, boxHeight - eventViewHeight); FrameInfoViewField(frameInfoViewRect, _animClip); // ======================================================== // draw border // ======================================================== oldBGColor = GUI.backgroundColor; GUI.backgroundColor = Color.black; GUI.Box(new Rect(0, yStart, boxWidth, boxHeight), GUIContent.none, exEditorHelper.RectBorderStyle()); GUI.backgroundColor = oldBGColor; // ======================================================== // DEBUG { // Color tmpclr = GUI.backgroundColor; // GUI.backgroundColor = Color.red; // GUI.Box ( new Rect( 0, 0, _rect.width, _rect.height ), // GUIContent.none, // exEditorHelper.RectBorderStyle() ); // GUI.backgroundColor = tmpclr; // } DEBUG end GUI.EndGroup(); // draw needle // ======================================================== // GUILayoutUtility.GetRect(_rect.width, _rect.height + _scalarHeight); // DEBUG { // GUILayout.BeginHorizontal(); // GUILayout.Space(30); // GUILayout.BeginVertical(); // GUILayout.Label ( "curIdx: " + curIdx ); // GUILayout.Label ( "idxFrom: " + idxFrom ); // GUILayout.Label ( "curCellWidth: " + curCellWidth ); // GUILayout.Label ( "curUnitSecond: " + curUnitSecond ); // GUILayout.Label ( "totalWidth: " + totalWidth ); // for ( int i = 0; i < lodScales.Count; ++i ) { // GUILayout.BeginHorizontal( GUILayout.MaxWidth(800) ); // GUILayout.Label ( "lod scales " + i + " = " + lodScales[i] ); // GUILayout.Label ( "lod width " + i + " = " + lodWidthList[i] ); // GUILayout.Label ( "lod interval " + i + " = " + lodIntervalList[i] ); // GUILayout.EndHorizontal(); // } // GUILayout.EndVertical(); // GUILayout.EndHorizontal(); // } DEBUG end // ======================================================== Event e = Event.current; // ======================================================== if (_rect.Contains(e.mousePosition)) { if (e.type == EventType.ScrollWheel) { float s = 1000.0f; while ((_animClip.editorScale / s) < 1.0f || (_animClip.editorScale / s) > 10.0f) { s /= 10.0f; } _animClip.editorScale -= e.delta.y * s * 0.05f; _animClip.editorScale = Mathf.Clamp(_animClip.editorScale, 0.001f, 100.0f); Repaint(); e.Use(); } else if (e.type == EventType.MouseDrag) { if (e.button == 1) { _animClip.editorOffset += e.delta.x; Repaint(); e.Use(); } } else if (e.type == EventType.DragUpdated) { // Show a copy icon on the drag foreach (Object o in DragAndDrop.objectReferences) { if (o is Texture2D || exEditorHelper.IsDirectory(o)) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; break; } } e.Use(); } else if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); // store old selection state List <Object> oldSelObjects = new List <Object>(); foreach (Object o in Selection.objects) { oldSelObjects.Add(o); } Object oldSelActiveObject = Selection.activeObject; // try { EditorUtility.DisplayProgressBar("Adding Textures...", "Start adding ", 0.5f); // sort List <Object> objList = new List <Object>(DragAndDrop.objectReferences.Length); foreach (Object o in DragAndDrop.objectReferences) { if (exEditorHelper.IsDirectory(o)) { Selection.activeObject = o; Object[] objs = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets); objList.AddRange(objs); } else if (o is Texture2D) { objList.Add(o); } } objList.Sort(exEditorHelper.CompareObjectByName); // DELME { // // sort // Object[] objList = Selection.GetFiltered( typeof(Texture2D), SelectionMode.DeepAssets); // System.Array.Sort( objList, exEditorHelper.CompareObjectByName ); // } DELME end // add objects as frames _animClip.AddFrames(objList.ToArray()); EditorUtility.ClearProgressBar(); } catch (System.Exception) { EditorUtility.ClearProgressBar(); throw; } // CalculatePreviewScale(); Repaint(); // recover selections Selection.activeObject = oldSelActiveObject; Selection.objects = oldSelObjects.ToArray(); e.Use(); } } }
// ------------------------------------------------------------------ // Desc: // ------------------------------------------------------------------ void EventInfoViewField(Rect _rect, exSpriteAnimClip _animClip) { float maxHeight = _rect.height - 3; Rect lastRect = new Rect(-100, _rect.y, 7, maxHeight); Rect curRect = new Rect(-100, _rect.y, 7, maxHeight); exSpriteAnimClip.EventInfo lastClicked = null; // NOTE: when editor.playing, the selectedFrameInfos will become invalid, don't know why :( bool selectedAreInvalid = true; foreach (exSpriteAnimClip.EventInfo eventInfo in _animClip.eventInfos) { if (selectedEventInfos.IndexOf(eventInfo) != -1) { selectedAreInvalid = false; } float at = _rect.x + (eventInfo.time / _animClip.length) * totalWidth; lastRect = curRect; curRect = new Rect(at - 4, _rect.y, 7, maxHeight); if (exIntersection2D.RectRect(lastRect, curRect)) { curRect.height = Mathf.Max(lastRect.height - 5.0f, 10.0f); } exSpriteAnimClip.EventInfo clicked_ei = null; if (at >= spriteAnimClipRect.x && at <= spriteAnimClipRect.xMax) { clicked_ei = EventInfoField(curRect, eventInfo); } if (clicked_ei != null) { lastClicked = clicked_ei; } } if (selectedAreInvalid) { selectedEventInfos.Clear(); } // ======================================================== Event e = Event.current; // ======================================================== if (lastClicked != null) { if (e.command || e.control) { ToggleSelected(lastClicked); } else { inDraggingEventInfoState = true; activeEventInfo = lastClicked; bool selected = selectedEventInfos.IndexOf(lastClicked) != -1; if (selected == false) { if (e.command == false && e.control == false) { selectedEventInfos.Clear(); AddSelected(lastClicked); } } } e.Use(); Repaint(); } // ======================================================== // // ======================================================== if (e.isMouse) { if (_rect.Contains(e.mousePosition)) { // mouse down if (e.type == EventType.MouseDown && e.button == 0 && e.clickCount == 1) { GUIUtility.keyboardControl = -1; // remove any keyboard control selectedFrameInfos.Clear(); mouseDownPos = e.mousePosition; inRectSelectEventState = true; UpdateSelectRect(mouseDownPos); ConfirmRectSelectEventInfo(); Repaint(); e.Use(); } // double click mouse down if (e.type == EventType.MouseDown && e.clickCount == 2 && e.command == false) { // Undo.RegisterUndo(curEdit, "AddEventInfo"); // DISABLE exSpriteAnimClip.EventInfo eventInfo = new exSpriteAnimClip.EventInfo(); eventInfo.time = curEdit.SnapToSeconds(((e.mousePosition.x - _rect.x) * _animClip.length) / totalWidth); _animClip.AddEvent(eventInfo); EditorUtility.SetDirty(_animClip); e.Use(); } } } }