using System; using System.IO; using System.Text; using System.Threading; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Drawing; using System.Drawing.Drawing2D; using System.Data; using System.Diagnostics; using Gravical.Library.GravicalIX; using Gravical.Library.GravicalDB; using Gravical.Library.Imgen; namespace Gravical.Applications.StickAnimator { public class Animation : INameProvider { #region Member Fields // State private int mFramesPerSecond; private int mFrameCount; private SizeF mCanvassSize; private SortedList mAllFigures; private long mNextNameValue = 1; // Internal private SortedList mMasterFiguresSorted; private ArrayList mMasterFiguresUnsorted; private bool mRequiresSave = false; #endregion #region Construction public Animation() { // The figures mFramesPerSecond = 30; mFrameCount = 100; mCanvassSize = new SizeF(640, 480); mMasterFiguresSorted = new SortedList(0x100); mMasterFiguresUnsorted = new ArrayList(0x100); mAllFigures = new SortedList(0x100); mNextNameValue = 1; } #endregion #region Protected Properties protected int AllFiguresCount { get { return mAllFigures.Count; } } protected Figure GetFigureFromAll(int index) { return (Figure)mAllFigures.GetByIndex(index); } protected long NextNameValue { get { return mNextNameValue; } } #endregion #region Public Properties public int FramesPerSecond { get { return mFramesPerSecond; } set { if(mFramesPerSecond != value) mRequiresSave = true; mFramesPerSecond = value; } } public int FrameCount { get { return mFrameCount; } set { if(mFrameCount != value) mRequiresSave = true; mFrameCount = value; } } public SizeF CanvassSize { get { return mCanvassSize; } set { if(mCanvassSize != value) mRequiresSave = true; mCanvassSize = value; } } public float Width { get { return mCanvassSize.Width; } } public float Height { get { return mCanvassSize.Height; } } public PointF CanvassCenter { get { return new PointF(mCanvassSize.Width / 2f, mCanvassSize.Height / 2f); } } public int MasterFigureCount { get { return mMasterFiguresUnsorted.Count; } } public bool RequiresSave { get { return mRequiresSave; } set { mRequiresSave = value; } } #endregion #region Create public void Create(int framesPerSecond, int frameCount, SizeF canvass_size, SortedList figures, long nextNameValue) { // Init mFramesPerSecond = framesPerSecond; mFrameCount = frameCount; mCanvassSize = canvass_size; mAllFigures = (SortedList)figures.Clone(); mNextNameValue = nextNameValue; // Create a name list SortedList figures_by_name = new SortedList(0x100); // Loop all the figures for(int Fi = 0; Fi < mAllFigures.Count; Fi++) { Figure figure = (Figure)mAllFigures.GetByIndex(Fi); // Init figure.ChainClear(); // Is this already in the master list int iName = figures_by_name.IndexOfKey(figure.Name); if(iName < 0) { figures_by_name.Add(figure.Name, figure); } else { Figure first_in_chain = (Figure)figures_by_name.GetByIndex(iName); if(first_in_chain.Keyframe > figure.Keyframe) { // Add it up front figure.ChainSetNext(first_in_chain); first_in_chain.ChainSetPrev(figure); figures_by_name.SetByIndex(iName, figure); // Recompute figure.ChainComputeLife(); } else { // Add it after first_in_chain.ChainInsertAft(figure); } } } // Build the lists for(int Fi = 0; Fi < figures_by_name.Count; Fi++) { Figure figure = (Figure)figures_by_name.GetByIndex(Fi); // Add mMasterFiguresSorted.Add(figure.Id, figure); mMasterFiguresUnsorted.Add(figure); } } #endregion #region DeleteMasterFigure public void DeleteMasterFigure(Guid id) { Figure figure = (Figure)mMasterFiguresSorted[id]; int Fi; // Remove all of its children if(figure != null) { // Loop all children for(Figure child = figure.ChainNext; child != null; child = child.ChainNext) { // Remove from the full list Fi = mAllFigures.IndexOfKey(id); if(Fi >= 0) mAllFigures.RemoveAt(Fi); } } // Remove it Fi = mMasterFiguresSorted.IndexOfKey(id); if(Fi >= 0) mMasterFiguresSorted.RemoveAt(Fi); // Remove from the full list Fi = mAllFigures.IndexOfKey(id); if(Fi >= 0) mAllFigures.RemoveAt(Fi); // Look for it in the unsorted list for(Fi = 0; Fi < mMasterFiguresUnsorted.Count; Fi++) { // Check if(((Figure)mMasterFiguresUnsorted[Fi]).Id == id) { mMasterFiguresUnsorted.RemoveAt(Fi); --Fi; } } // We need saving mRequiresSave = true; } #endregion #region AddMasterFigure public void AddMasterFigure(Figure figure) { // Add mAllFigures.Add(figure.Id, figure); mMasterFiguresSorted.Add(figure.Id, figure); mMasterFiguresUnsorted.Add(figure); // We need saving mRequiresSave = true; } #endregion #region GetMasterFigureFor public int GetMasterFigureIndexFor(Guid id) { // Look for it in the unsorted list for(int Fi = 0; Fi < mMasterFiguresUnsorted.Count; Fi++) if(((Figure)mMasterFiguresUnsorted[Fi]).Id == id) return Fi; // Not found return -1; } #endregion #region GetMasterFigure public Figure GetMasterFigure(int index) { return (Figure)mMasterFiguresUnsorted[index]; } public Figure GetMasterFigure(Figure figure) { // Loop back to find the master for( ; figure != null; figure = figure.ChainPrev) if(figure.ChainPrev == null) return figure; // This should never happen return null; } #endregion #region GetObjectByJoint public object GetObjectByJoint(RenderArgs a, float x, float y, int frame) { // Loop all figures for(int Fi = 0; Fi < mAllFigures.Count; Fi++) { Figure figure = (Figure)mAllFigures.GetByIndex(Fi); // Is this figure on our frame if(figure.Keyframe != frame) continue; // Check the anchor if(figure.HitTestAnchor(a, x, y)) return figure; // Check the segments Segment segment = figure.HitTestSegments(a, x, y); if(segment != null) return segment; } // Nothing found return null; } #endregion #region GetLivingFigureList public ArrayList GetLivingFigureList(int frame) { ArrayList list = new ArrayList(0x100); // Loop them all for(int Fi = 0; Fi < mAllFigures.Count; Fi++) if(((Figure)mAllFigures.GetByIndex(Fi)).IsLiving(frame)) list.Add(mAllFigures.GetByIndex(Fi)); // Return the list return list; } #endregion #region GetAnimatedFigureList public ArrayList GetAnimatedFigureList(int frame) { ArrayList list = new ArrayList(0x100); // Loop them all for(int Fi = 0; Fi < mAllFigures.Count; Fi++) { Figure figure = (Figure)mAllFigures.GetByIndex(Fi); // If it is not alive if(!figure.IsLiving(frame)) continue; // If this is the keyframe, or we have nothing to tween with if(figure.Keyframe == frame || figure.ChainNext == null) list.Add(figure); else list.Add(figure.Tween(figure.ChainNext, frame)); } // Return the list return list; } #endregion #region GetLivingFigure public Figure GetLivingFigure(int iMaster, int frame) { Figure master = (Figure)mMasterFiguresUnsorted[iMaster]; // Find this frame return master.ChainGetLiving(frame); } #endregion #region IsFigurePresent public bool IsFigurePresent(Guid id) { return mAllFigures.ContainsKey(id); } #endregion #region ChangeFigureName public bool DoesFigureNameExist(string name) { // If the name already exists for(int Fi = 0; Fi < mAllFigures.Count; Fi++) if(((Figure)mAllFigures.GetByIndex(Fi)).Name == name) return true; // Nope return false; } public void ChangeFigureName(Figure figure, string name) { // If the name hasnt changed if(name == figure.Name) return; // If the name already exists if(DoesFigureNameExist(name)) throw new Exception("Name already exists"); // Loop them all for(figure = GetMasterFigure(figure); figure != null; figure = figure.ChainNext) figure.Name = name; // Requires a save mRequiresSave = true; } #endregion #region ChangeSegmentName public bool DoesSegmentNameExist(Figure figure, string name) { // Loop them figures in the list for(figure = GetMasterFigure(figure); figure != null; figure = figure.ChainNext) { // Loop all segments for the current figure for(int Si = 0; Si < figure.Count; Si++) if(figure[Si].Name == name) return true; } // Nope return false; } public void ChangeSegmentName(Figure figure, string from, string to) { // If the name hasnt changed if(to == from) return; // If the name already exists if(DoesSegmentNameExist(figure, to)) throw new Exception("Name already exists"); // Update everything in the chain for(figure = GetMasterFigure(figure); figure != null; figure = figure.ChainNext) { // Loop all segments for the current figure for(int Si = 0; Si < figure.Count; Si++) if(figure[Si].Name == from) figure[Si].Name = to; } // Requires a save mRequiresSave = true; } #endregion #region ClearFrames public void ClearFrames(int iMaster, int frame, int count) { Figure master = GetMasterFigure(iMaster); if(master == null) return; // Set the current Figure current = null; // Find where it starts for(current = master; current != null; current = current.ChainNext) { // If the keyframe starts inside if(current.Keyframe >= frame && current.Keyframe <= frame + count) break; // If the frame starts before but extends into if(current.Keyframe < frame && frame <= current.Endframe) break; } // If there isnt one if(current == null) return; // If this keyframe is before us if(current.Keyframe < frame) { // Shorten it current.Life = frame - current.Keyframe - 1; // Advance current = current.ChainNext; } // Remove any keyframes that are in this segment for( ; current != null; current = current.ChainNext) { // If we are past if(current.Keyframe > frame + count) break; // Remove it from the chain if(current.ChainPrev == null) { // Remove from the master list mMasterFiguresSorted.Remove(current.Id); mMasterFiguresUnsorted.Remove(current); mAllFigures.Remove(current.Id); // If we have a next, add it in if(current.ChainNext != null) { // Advance current = current.ChainNext; // Update current.ChainPrev = null; mMasterFiguresSorted.Add(current.Id, current); mMasterFiguresUnsorted.Add(current); } } else { // Remove it from the list mAllFigures.Remove(current.Id); // Remove it from the linkage if(current.ChainNext == null) { current.ChainPrev.ChainNext = null; } else { current.ChainPrev.ChainNext = current.ChainNext; current.ChainNext.ChainPrev = current.ChainPrev; } } } // Update mRequiresSave = true; } #endregion #region CollapseFrames public void CollapseFrames(int iMaster, int frame, int count) { // Clear all frames in the area ClearFrames(iMaster, frame, count); // Get the master figure here Figure master = GetMasterFigure(iMaster); if(master == null) return; // Move down from here for(Figure figure = master.ChainGetNearestFore(frame + count); figure != null; figure = figure.ChainNext) { // Move it down exactly this many figure.Keyframe -= (count + 1); } // Update mRequiresSave = true; } #endregion #region InsertKeyframe public void InsertKeyframe(int iMaster, int frame) { try { Figure master = (Figure)mMasterFiguresUnsorted[iMaster]; Figure newfigure = null; // We need saving mRequiresSave = true; // If there is no frame this low, move the keyframe of the first if(master.Keyframe > frame) { // Deep clone the figure newfigure = master.KeyframeClone(this); // Make this the new master mMasterFiguresUnsorted[iMaster] = newfigure; mMasterFiguresSorted.Remove(master.Id); mMasterFiguresSorted.Add(newfigure.Id, newfigure); mAllFigures.Add(newfigure.Id, newfigure); // Establish the life newfigure.Keyframe = frame; newfigure.Life = master.Keyframe - newfigure.Keyframe; // Insert into the chain newfigure.ChainSetPrev(null); newfigure.ChainSetNext(master); master.ChainSetPrev(newfigure); // Done return; } // If there is already a living frame here, Figure living = master.ChainGetLiving(frame); if(living != null) { // Transform from the tween newfigure = living.Tween(living.ChainNext, frame); // Set the life newfigure.Keyframe = frame; newfigure.Life = (living.Endframe - frame); living.Life -= newfigure.Life + 1; // Perform an insert and move the other frames up inserting after this living.ChainInsertAft(newfigure); // Insert into the figures list mAllFigures.Add(newfigure.Id, newfigure); // Done return; } // Otherwise, extend the previous living to here living = master.ChainGetNearestLivingBack(frame); // This should not happen, but just in case if(living == null) return; // Set living.Life += Math.Max(0, (frame - living.Endframe) - 1); // Duplicate it and make a keyframe newfigure = master.KeyframeClone(this); newfigure.Keyframe = frame; newfigure.Life = 0; // Link it on in living.ChainInsertAft(newfigure); // Insert into the figures list mAllFigures.Add(newfigure.Id, newfigure); } catch(Exception ex) { Display.SystemLog("Animation.InsertFrame", ex); } } #endregion #region InsertFrame public void InsertFrame(int iMaster, int frame) { try { Figure master = (Figure)mMasterFiguresUnsorted[iMaster]; // We need saving mRequiresSave = true; // If there is no frame this low, move the keyframe of the first if(master.Keyframe > frame) { int life_extension = (master.Keyframe - frame); // Set the keyframe master.Keyframe = frame; master.Life += life_extension; // Done return; } // If there is already a living frame here, Figure living = master.ChainGetLiving(frame); if(living != null) { // Rerform an insert and move the other frames up inserting after this living.ChainInsertFrames(1); // Done return; } // Otherwise, extend the previous living to here living = master.ChainGetNearestLivingBack(frame); // This should not happen, but just in case if(living == null) return; // Set living.Life += (frame - living.Endframe); } catch(Exception ex) { Display.SystemLog("Animation.InsertFrame", ex); } } #endregion #region NameProvider public string GetNewName(string type) { string new_name = type + mNextNameValue; // Update ++mNextNameValue; mRequiresSave = true; // Return it return new_name; } #endregion } }