using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using Math3;
using BinTree;
using Microsoft.SqlServer.Server;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Xml;
//using Animation_Editor;

namespace SpriteEditor_2017
{
    public class classSpriteMaker
    {
        public static classSpriteMaker instance;
        public static BinaryFormatter formatter = new BinaryFormatter();
        FileStream fs = null;// universal filestream required to load/save -> used by debugging tools to record fs.position outside load/save operations

        // standard string identifying null limb that defines end of (enuFSM.Celebrate)DrawSequence-list (limbs listed after DoNotDraw/null are not drawn)
        public static int cLimb_DoNotDraw = -1;

        // filler-data used for MasterLimb file-storage
        const string conMasterLimb_HingeName = "___none___";
        const string conMasterLimb_MasterLimb = "___none___";
        const double conMasterLimb_Contact_MasterRad = 0;
        const double conMasterLimb_Contact_MasterMag = 0;
        const double conMasterLimb_Contact_SlaveRad = 0;
        const double conMasterLimb_Contact_SlaveMag = 0;

        public const string conSpriteFileExtension3 = ".sp3";
        public const string conSpriteFileExtension4 = ".sp4";
        public const string conSpriteFileExtension5 = ".sp5";
        public const string conSpriteFileExtension6 = ".sp6";
        public const string conTextSpriteFileExtension = ".spT";
        public const string conCostumeInfoFileExtension = ".cst";

        public enum enuFileExtensionsSupported { SP3, SP4, SP5, SP6, All, _numFileExtensionsSupported };

        const int conMaxNameSize = 120;                  // standard size for all names in Binary-RandomAccess file storage of sprites
        public const int conNumImagesPerQuadrant = 32;  // standard number of images in sprite's limb rotations (total 4x32 = 128 images per limb to describe one rotation)


        /// <summary>
        /// limb information loaded from the file piece-meal is then used once compiled together to create limbs during sprite-loading
        /// </summary>
        public class classLoadLimbsInfo
        {
            public string LimbName;
            public string HingeName;
            public string MasterLimbName;
            public classRadialCoordinate cRad_ContactMaster;
            public classRadialCoordinate cRad_ContactSlave;
            public List<Bitmap> lstBmp = new List<Bitmap>();
        }

        /// <summary>
        /// used to generate, load & save all sprites
        /// </summary>
        public classSpriteMaker()
        {
            instance = this;
            //classSprite cSpriteRef = null;
            //if (cLimb_DoNotDraw == null)
            //    cLimb_DoNotDraw =  classSprite_Limb.New(classSprite.conDrawSequenceDoNotDraw, ref cSpriteRef, null);
        }

        enuFileExtensionsSupported GetSpriteVersionByFilename(string strFilename)
        {
            int intCutChar = strFilename.LastIndexOf('.');
            if (intCutChar > 0)
            {
                string strExtension = strFilename.Substring(intCutChar + 1).ToUpper();
                for (int intExtensionCounter = 0; intExtensionCounter < (int)enuFileExtensionsSupported._numFileExtensionsSupported; intExtensionCounter++)
                {
                    enuFileExtensionsSupported eExtensionCounter = (enuFileExtensionsSupported)intExtensionCounter;
                    string strExtensionCounter = eExtensionCounter.ToString();
                    if (string.Compare(strExtension, strExtensionCounter) == 0)
                        return eExtensionCounter;
                }
            }
            return enuFileExtensionsSupported._numFileExtensionsSupported;
        }

        public static string FileFileExtension_GetString(enuFileExtensionsSupported eExtension)
        {
            switch (eExtension)
            {
                case enuFileExtensionsSupported.All:

                    {
                        return "All files (*.*)|*.*";
                    }

                default:
                    {
                        return "(*." + eExtension.ToString() + ") | *." + eExtension.ToString();
                    }

            }
        }

        /// <summary>
        /// ensures all string information needed to save/load sprites are of standard length
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string FormatString(string str)
        {
            if (str.Length > conMaxNameSize)
                str = str.Substring(0, conMaxNameSize);
            else
                str.PadRight(conMaxNameSize);
            return str;
        }

        /// <summary>
        /// creates a new sprite with the specified name
        /// </summary>
        /// <param name="name">name of sprite to be created</param>
        /// <returns>returns an instance of a newly created sprite of the specified name</returns>
        public classSprite New(string name)
        {
            classSprite cSprite = null;
            classSprite cRetVal = null;
            if (cSprite != null)
            {
                if (classSprite.ShowErrorMessages)
                    if (MessageBox.Show("Sprites must have a unique name.  A sprite with the name " + name + " already exists.  Do you wish to overwrite?", "Name already exists", MessageBoxButtons.YesNo) == DialogResult.No)
                        return null;
                    else
                        cRetVal = cSprite;
            }
            return new classSprite(name);
        }

        /// <summary>
        /// used in iEnumerable OrderBy queries for alphabetizing lists of strings
        /// </summary>
        public class Compare_Alphabetical : IComparer<string>
        {
            /// <summary>
            /// compare two strings
            /// </summary>
            public int Compare(string str1, string str2)
            {
                return string.Compare(str1, str2);
            }
        }

        /// <summary>
        /// used in iEnumerable OrderBy queries for ordering lists of by length of strings
        /// </summary>
        public class Compare_StringLength : IComparer<string>
        {
            /// <summary>
            /// compare two strings
            /// </summary>
            public int Compare(string str1, string str2)
            {
                int int1 = str1.Length;
                int int2 = str2.Length;

                if (int1 > int2) return 1;
                else if (int1 < int2) return -1;
                else return 0;
            }
        }

        #region SaveLoad

        /// <summary>
        /// saves sprites to harddrive sequentially - SP6
        /// </summary>
        /// <param name="cSprite">sprite to be saved to file</param>
        /// <param name="strFilename">name and path of file to be saved</param>
        public void Save(ref classSprite cSprite, ref string strFilename) // sp5 format
        {
            int intCutChr = strFilename.IndexOf('.');
            if (intCutChr > 0)
                strFilename = strFilename.Substring(0, intCutChr);
            strFilename += classSpriteMaker.conSpriteFileExtension6;

            int intIndexLastBackslash = strFilename.LastIndexOf('\\');
            if (intIndexLastBackslash > 0)
            {
                string strName = strFilename.Substring(intIndexLastBackslash + 1);
                int intIndexExtension = strName.IndexOf(".");
                if (intIndexExtension > 0)
                    strName = strName.Substring(0, intIndexExtension);
                cSprite.Name = strName;
            }

            debugClear();
            eDebugOutput = enuDebugOutput.none;

            if (cSprite.TextSprite)
                TextSpriteInfo_Save(ref cSprite.textSpriteInfo, strFilename);

            try
            {
                fs = new FileStream(strFilename, FileMode.Create);

                fs.Position = 0;

                formatter.Serialize(fs, (string)FormatString(cSprite.Name));
                debug("after sprite name " + cSprite.Name);

                formatter.Serialize(fs, (int)cSprite.NumImagesPerQuadrant);
                debug("after NumIMagesPerQuadrant " + cSprite.NumImagesPerQuadrant);

                formatter.Serialize(fs, (bool)cSprite.UseRamCache);
                debug("after boolean : use RAM cache");

                formatter.Serialize(fs, (byte)cSprite.eRotatedLimbImage);
                debug("after eRotatedLimbImage");

                formatter.Serialize(fs, (int)cSprite.cCostumeInfo_Default.lstLimbs.Count);
                debug("after Limbs.Count " + cSprite.cCostumeInfo_Default.lstLimbs.Count.ToString());

                Save_LimbRecursion(ref cSprite.cCostumeInfo_Default.cLimb_Master, ref fs);

                eDebugOutput = enuDebugOutput.none;
                // save animations
                intDebugIndent = 0;
                formatter.Serialize(fs, (int)cSprite.lstAnimations.Count);                                                          // A1 = int
                debug("after animations count");

                debug("forEach Animation");
                for (int intAnimationCounter = 0; intAnimationCounter < cSprite.lstAnimations.Count; intAnimationCounter++)
                {
                    intDebugIndent = 1;
                    classAnimation cAnimation = cSprite.lstAnimations[intAnimationCounter];
                    debug("-------------------------------- start animation " + cAnimation.Name + "-----------------------------");

                    formatter.Serialize(fs, (string)FormatString(cAnimation.Name));                                                 // A2 = string
                    debug("after animation name " + cAnimation.Name);

                    intDebugIndent = 1;
                    formatter.Serialize(fs, (int)cAnimation.lstFrames.Count);
                    debug("after FramesCount " + cAnimation.lstFrames.Count.ToString());

                    debug("forEAch Frame");
                    for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                    {
                        intDebugIndent = 2;
                        debug("forEAch --------------------------------------Frame[" + intFrameCounter.ToString() + "] loopStart----------------------------------");

                        classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];


                        formatter.Serialize(fs, (bool)cFrame.Vertical_Mirror);
                        debug("after vertical mirror " + cFrame.Vertical_Mirror.ToString());

                        formatter.Serialize(fs, (bool)cFrame.Horizontal_Mirror);
                        debug("after Horizontal mirror " + cFrame.Horizontal_Mirror.ToString());

                        formatter.Serialize(fs, (string)(cFrame.Limb_DrawRelativeTo >= 0
                                                                                     ? cSprite.cCostumeInfo_Default.lstLimbs[cFrame.Limb_DrawRelativeTo].Name
                                                                                     : "null"));
                        debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                        // draw sequence
                        formatter.Serialize(fs, (int)cFrame.lstDrawSequence.Count);
                        debug("after drawSequence Count " + cFrame.lstDrawSequence.Count.ToString());

                        debug("forEAch DrawSequenceLimb");
                        for (int intLimbCounter = 0; intLimbCounter < cFrame.lstDrawSequence.Count; intLimbCounter++)
                        {
                            classSprite_Limb cLimb = cFrame.lstDrawSequence[intLimbCounter] >= 0
                                                                                            ? cSprite.cCostumeInfo_Default.lstLimbs[cFrame.lstDrawSequence[intLimbCounter]]
                                                                                            : null;
                            debug("-----------" + intLimbCounter.ToString() + ":" + (cLimb != null
                                                                                           ? cLimb.Name
                                                                                           : "null") + " -------------");
                            intDebugIndent = 3;
                            if (cFrame.lstDrawSequence[intLimbCounter] == -1)
                            {
                                formatter.Serialize(fs, (string)FormatString(classSprite.conDrawSequenceDoNotDraw));
                                debug("after " + classSprite.conDrawSequenceDoNotDraw);
                            }
                            else
                            {
                                formatter.Serialize(fs, (string)FormatString(cLimb.Name));
                                debug("after " + cLimb.Name);
                            }
                        }

                        intDebugIndent = 2;
                        debug("forEach LimbData-----------------------------------------------");
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        //eDebugOutput = enuDebugOutput.none;
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        for (int intLimbCounter = 0; intLimbCounter < cAnimation.lstFrames[intFrameCounter].lstData.Count; intLimbCounter++)
                        {
                            intDebugIndent = 3;
                            classAnimation_Frame_LimbData cData = cFrame.lstData[intLimbCounter];
                            debug("-------------limb:" + intLimbCounter.ToString() + "(" + cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name + ")---------------");
                            formatter.Serialize(fs, (string)FormatString(cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name));                             // name
                            debug("after LimbName " + cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                            formatter.Serialize(fs, (bool)cData.Override);
                            debug("after Override" + cData.Override.ToString());

                            formatter.Serialize(fs, (double)cData.Angle);                                               // angle
                            debug("after Angle" + cData.Angle.ToString());
                            
                            formatter.Serialize(fs, (double)cData.SlaveContactMagnitude_Factor);                        // slaveContactMagnitude_Factor
                            debug("after SCMag_Factor" + cData.SlaveContactMagnitude_Factor.ToString());

                            formatter.Serialize(fs, (byte)cData.Opacity);                                               // opacity
                            debug("after opacity");

                            formatter.Serialize(fs, (bool)cData.ColorFilter.Valid);                                     // color-filter.valid`  
                            debug("after Color-filter.valid");

                            formatter.Serialize(fs, (byte)cData.ColorFilter.clr.R);                                     // color-filter.R
                            debug("after Color_filter.clr.R");

                            formatter.Serialize(fs, (byte)cData.ColorFilter.clr.G);                                     // color-filter.G
                            debug("after Color_filter.clr.G");

                            formatter.Serialize(fs, (byte)cData.ColorFilter.clr.B);                                     // color-filter.B
                            debug("after Color_filter.clr.B");

                            formatter.Serialize(fs, (string)cData.ImageList_Name);
                            debug("after LimbDrawList_Name " + cData.ImageList_Name);
                        }
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        //eDebugOutput = enuDebugOutput.none;
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        debug("forEach Frame loopEnd");
                    }

                    debug("END OF aNIMATION " + cAnimation.Name);
                    //eDebugOutput = enuDebugOutput.none;

                }
                intDebugIndent = 0;
                debug("AFter Animation Loop");
            }
            catch (Exception e)
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("Error saving File(" + strFilename + "):" + e.Message, "Error");
            }
            strDebugFilename = "rtfSave";
            eDebugOutput = enuDebugOutput.none;
            debugSave();
            if (fs != null) fs.Close();
        }
        
        
        /// <summary>
        /// saves sprites to harddrive sequentially
        /// </summary>
        /// <param name="cSprite">sprite to be saved to file</param>
        /// <param name="strFilename">name and path of file to be saved</param>
        public void Save_OBSOLETE_SP5(ref classSprite cSprite, ref string strFilename) // sp5 format
        {
            int intCutChr = strFilename.IndexOf('.');
            if (intCutChr > 0)
                strFilename = strFilename.Substring(0, intCutChr);
            strFilename += classSpriteMaker.conSpriteFileExtension5;

            int intIndexLastBackslash = strFilename.LastIndexOf('\\');
            if (intIndexLastBackslash > 0)
            {
                string strName = strFilename.Substring(intIndexLastBackslash + 1);
                int intIndexExtension = strName.IndexOf(".");
                if (intIndexExtension > 0)
                    strName = strName.Substring(0, intIndexExtension);
                cSprite.Name = strName;
            }

            debugClear();
            eDebugOutput = enuDebugOutput.none;

            if (cSprite.TextSprite)
                TextSpriteInfo_Save(ref cSprite.textSpriteInfo, strFilename);

            try
            {
                fs = new FileStream(strFilename, FileMode.Create);

                fs.Position = 0;

                formatter.Serialize(fs, (string)FormatString(cSprite.Name));
                debug("after sprite name " + cSprite.Name);

                formatter.Serialize(fs, (int)cSprite.NumImagesPerQuadrant);
                debug("after NumIMagesPerQuadrant " + cSprite.NumImagesPerQuadrant);

                formatter.Serialize(fs, (bool)cSprite.UseRamCache);
                debug("before boolean : use RAM cache");

                formatter.Serialize(fs, (int)cSprite.cCostumeInfo_Default.lstLimbs.Count);
                debug("after Limbs.Count " + cSprite.cCostumeInfo_Default.lstLimbs.Count.ToString());

                Save_LimbRecursion(ref cSprite.cCostumeInfo_Default.cLimb_Master, ref fs);

                eDebugOutput = enuDebugOutput.none;
                // save animations
                intDebugIndent = 0;
                formatter.Serialize(fs, (int)cSprite.lstAnimations.Count);                                                          // A1 = int
                debug("after animations count");

                debug("forEach Animation");
                for (int intAnimationCounter = 0; intAnimationCounter < cSprite.lstAnimations.Count; intAnimationCounter++)
                {
                    intDebugIndent = 1;
                    classAnimation cAnimation = cSprite.lstAnimations[intAnimationCounter];
                    debug("-------------------------------- start animation " + cAnimation.Name + "-----------------------------");

                    formatter.Serialize(fs, (string)FormatString(cAnimation.Name));                                                 // A2 = string
                    debug("after animation name " + cAnimation.Name);

                    intDebugIndent = 1;
                    formatter.Serialize(fs, (int)cAnimation.lstFrames.Count);
                    debug("after FramesCount " + cAnimation.lstFrames.Count.ToString());

                    debug("forEAch Frame");
                    for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                    {
                        intDebugIndent = 2;
                        debug("forEAch --------------------------------------Frame[" + intFrameCounter.ToString() + "] loopStart----------------------------------");

                        classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];


                        formatter.Serialize(fs, (bool)cFrame.Vertical_Mirror);
                        debug("after vertical mirror " + cFrame.Vertical_Mirror.ToString());

                        formatter.Serialize(fs, (bool)cFrame.Horizontal_Mirror);
                        debug("after Horizontal mirror " + cFrame.Horizontal_Mirror.ToString());

                        formatter.Serialize(fs, (string)(cFrame.Limb_DrawRelativeTo >= 0
                                                                                     ? cSprite.cCostumeInfo_Default.lstLimbs[cFrame.Limb_DrawRelativeTo].Name
                                                                                     : "null"));
                        debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                        // draw sequence
                        formatter.Serialize(fs, (int)cFrame.lstDrawSequence.Count);
                        debug("after drawSequence Count " + cFrame.lstDrawSequence.Count.ToString());

                        debug("forEAch DrawSequenceLimb");
                        for (int intLimbCounter = 0; intLimbCounter < cFrame.lstDrawSequence.Count; intLimbCounter++)
                        {
                            classSprite_Limb cLimb = cFrame.lstDrawSequence[intLimbCounter] >= 0
                                                                                            ? cSprite.cCostumeInfo_Default.lstLimbs[cFrame.lstDrawSequence[intLimbCounter]]
                                                                                            : null;
                            debug("-----------" + intLimbCounter.ToString() + ":" + (cLimb != null
                                                                                           ? cLimb.Name
                                                                                           : "null") + " -------------");
                            intDebugIndent = 3;
                            if (cFrame.lstDrawSequence[intLimbCounter] == -1)
                            {
                                formatter.Serialize(fs, (string)FormatString(classSprite.conDrawSequenceDoNotDraw));
                                debug("after " + classSprite.conDrawSequenceDoNotDraw);
                            }
                            else
                            {
                                formatter.Serialize(fs, (string)FormatString(cLimb.Name));
                                debug("after " + cLimb.Name);
                            }
                        }

                        intDebugIndent = 2;
                        debug("forEach LimbData-----------------------------------------------");
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        //eDebugOutput = enuDebugOutput.none;
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        for (int intLimbCounter = 0; intLimbCounter < cAnimation.lstFrames[intFrameCounter].lstData.Count; intLimbCounter++)
                        {
                            intDebugIndent = 3;
                            classAnimation_Frame_LimbData cData = cFrame.lstData[intLimbCounter];
                            debug("-------------limb:" + intLimbCounter.ToString() + "(" + cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name + ")---------------");
                            formatter.Serialize(fs, (string)FormatString(cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name));                             // name
                            debug("after LimbName " + cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                            formatter.Serialize(fs, (bool)cData.Override);
                            debug("after Override" + cData.Override.ToString());

                            formatter.Serialize(fs, (double)cData.Angle);                                               // angle
                            debug("after Angle" + cData.Angle.ToString());
                            
                            formatter.Serialize(fs, (double)cData.SlaveContactMagnitude_Factor);                        // slaveContactMagnitude_Factor
                            debug("after SCMag_Factor" + cData.SlaveContactMagnitude_Factor.ToString());

                            formatter.Serialize(fs, (string)cData.ImageList_Name);
                            debug("after LimbDrawList_Name " + cData.ImageList_Name);
                        }
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        //eDebugOutput = enuDebugOutput.none;
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        debug("forEach Frame loopEnd");
                    }

                    debug("END OF aNIMATION " + cAnimation.Name);
                    //eDebugOutput = enuDebugOutput.none;

                }
                intDebugIndent = 0;
                debug("AFter Animation Loop");
            }
            catch (Exception e)
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("Error saving File(" + strFilename + "):" + e.Message, "Error");
            }
            strDebugFilename = "rtfSave";
            eDebugOutput = enuDebugOutput.none;
            debugSave();
            if (fs != null) fs.Close();
        }

        /// <summary>
        /// recursion is used to save the sprite's limbs starting from the masterLimb and branching out to the multiple slave limbs each limb has
        /// </summary>
        /// <param name="cLimb">current limb being saved will recursively call SAve_LimbRecursion for each of its slaveLimbs attached to it</param>
        /// <param name="fs"></param>
        void Save_LimbRecursion(ref classSprite_Limb cLimb, ref FileStream fs)
        {
            intDebugIndent = 1;
            debug("Begin Recursion");
            debug("before cLimb.Name");
            formatter.Serialize(fs, (string)cLimb.Name);
            debug("after cLimb.Name " + cLimb.Name);

            if (cLimb.Hinge != null)
            {
                debug("not a master limb");

                debug("before LimbMasterName");
                formatter.Serialize(fs, (string)FormatString(cLimb.Hinge.Limb_Master.Name));
                debug("after LimbMaster.Name " + cLimb.Hinge.Limb_Master.Name);

                debug("before cmRad");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Master.Radians);
                debug("after cmRad " + cLimb.Hinge.Contact.Master.Radians.ToString());

                debug("before cmMag ");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Master.Magnitude);
                debug("after cmMag " + cLimb.Hinge.Contact.Master.Magnitude.ToString());


                debug("before csRad");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Slave.Radians);
                debug("after csRad " + cLimb.Hinge.Contact.Slave.Radians.ToString());

                debug("before csMag");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Slave.Magnitude);
                debug("after csMag " + cLimb.Hinge.Contact.Slave.Magnitude.ToString());
            }
            else
            {
                debug("master limb");
                debug("before MasterHingeName ");
                //formatter.Serialize(fs, (string)FormatString(conMasterLimb_HingeName));
                debug("after MasterHingeName " + conMasterLimb_HingeName);

                debug("before MasterLimbName");
                formatter.Serialize(fs, (string)FormatString(conMasterLimb_MasterLimb));
                debug("after MasterLimbName " + conMasterLimb_MasterLimb);

                debug("before cmRad");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_MasterRad);
                debug("after cmRad " + conMasterLimb_Contact_MasterRad);


                debug("before cmMag");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_MasterMag);
                debug("after cmMag " + conMasterLimb_Contact_MasterMag);

                debug("before csRad");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_SlaveRad);
                debug("after csRad " + conMasterLimb_Contact_SlaveRad);

                debug("before csMag");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_SlaveMag);
                debug("after csMag " + conMasterLimb_Contact_SlaveMag);
            }

            debug("before number of lists");
            formatter.Serialize(fs, (int)cLimb.lstImages.Count);
            debug("after number of lists " + cLimb.lstImages.Count.ToString());

            for (int intListCounter = 0; intListCounter < cLimb.lstImages.Count; intListCounter++)
            {
                classSprite_Limb.classSprite_Limb_Images cImages = cLimb.lstImages[intListCounter];

                debug("before image list name");
                formatter.Serialize(fs, (string)cImages.Name);
                debug("after images list name :" + cImages.Name);

                debug("forEach image");
                switch(cLimb.cSprite.eRotatedLimbImage)
                {
                    case classSprite.enuRotatedLimbImage.SaveToFile:
                        {


                            for (int intImageCounter = 0; intImageCounter < cLimb.cSprite.NumImagesPerQuadrant; intImageCounter++)
                            {
                                intDebugIndent = 2;
                                Bitmap bmp = cImages.bmpImages[intImageCounter];
                                debug("before bmp");
                                formatter.Serialize(fs, (Bitmap)bmp);
                                debug("after bmp");
                            }
                        }
                        break;

                    default:
                        {
                            intDebugIndent = 2;
                            Bitmap bmp = cImages.bmpImages[0];
                            debug("before bmp");
                            formatter.Serialize(fs, (Bitmap)bmp);
                            debug("after bmp");
                        }
                        break;
                }
            }


            debug("forEach slave");
            for (int intSlaveCounter = 0; intSlaveCounter < cLimb.lstHinge_Slaves.Count; intSlaveCounter++)
            {
                classSprite_Limb cLimbSlave = cLimb.lstHinge_Slaves[intSlaveCounter].Limb_Slave;
                Save_LimbRecursion(ref cLimbSlave, ref fs);
            }
            intDebugIndent = 1;
            debug("exit recursion :" + cLimb.Name);
        }

        /// <summary>
        /// saves sprites to harddrive sequentially
        /// </summary>
        /// <param name="cSprite">sprite to be saved to file</param>
        /// <param name="strFilename">name and path of file to be saved</param>
        public void Save_CostumeInfo(ref classSprite_CostumeInfo cCostumeInfo, string strFilename)
        {
            int intCutChr = strFilename.IndexOf('.');
            if (intCutChr > 0)
            {
                strFilename = strFilename.Substring(0, intCutChr);

            }
            strFilename += classSpriteMaker.conCostumeInfoFileExtension;

            debugClear();
            eDebugOutput = enuDebugOutput.none;
            try
            {
                fs = new FileStream(strFilename, FileMode.Create);

                fs.Position = 0;

                debug("before sprite name");
                formatter.Serialize(fs, (string)FormatString(cCostumeInfo.SpriteName));
                debug("after sprite name " + cCostumeInfo.Name);


                debug("before sprite name");
                formatter.Serialize(fs, (string)FormatString(cCostumeInfo.Name));
                debug("after sprite name " + cCostumeInfo.Name);

                debug("entering Recursion ");
                Save_LimbRecursion(ref cCostumeInfo.cLimb_Master, ref fs);

                intDebugIndent = 0;
                debug("AFter Animation Loop");
            }
            catch (Exception e)
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("Error saving File(" + strFilename + "):" + e.Message, "Error");
            }
            strDebugFilename = "rtfSave";
            eDebugOutput = enuDebugOutput.none;
            debugSave();
            if (fs != null) fs.Close();
        }

        /// <summary>
        /// recursion is used to save the sprite's limbs starting from the masterLimb and branching out to the multiple slave limbs each limb has
        /// </summary>
        /// <param name="cLimb">current limb being saved will recursively call SAve_LimbRecursion for each of its slaveLimbs attached to it</param>
        /// <param name="fs"></param>
        void Save_CostumeInfo_Recursion(ref classSprite_Limb cLimb, ref FileStream fs)
        {
            intDebugIndent = 1;
            debug("Begin Recursion");
            debug("before cLimb.Name");
            formatter.Serialize(fs, (string)cLimb.Name);
            debug("after cLimb.Name " + cLimb.Name);

            if (cLimb.Hinge != null)
            {
                debug("not a master limb");

                debug("before LimbMasterName");
                formatter.Serialize(fs, (string)FormatString(cLimb.Hinge.Limb_Master.Name));
                debug("after LimbMaster.Name " + cLimb.Hinge.Limb_Master.Name);

                debug("before cmRad");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Master.Radians);
                debug("after cmRad " + cLimb.Hinge.Contact.Master.Radians.ToString());

                debug("before cmMag ");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Master.Magnitude);
                debug("after cmMag " + cLimb.Hinge.Contact.Master.Magnitude.ToString());


                debug("before csRad");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Slave.Radians);
                debug("after csRad " + cLimb.Hinge.Contact.Slave.Radians.ToString());

                debug("before csMag");
                formatter.Serialize(fs, (double)cLimb.Hinge.Contact.Slave.Magnitude);
                debug("after csMag " + cLimb.Hinge.Contact.Slave.Magnitude.ToString());
            }
            else
            {
                debug("master limb");
                debug("before MasterHingeName ");
                //formatter.Serialize(fs, (string)FormatString(conMasterLimb_HingeName));
                debug("after MasterHingeName " + conMasterLimb_HingeName);

                debug("before MasterLimbName");
                formatter.Serialize(fs, (string)FormatString(conMasterLimb_MasterLimb));
                debug("after MasterLimbName " + conMasterLimb_MasterLimb);

                debug("before cmRad");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_MasterRad);
                debug("after cmRad " + conMasterLimb_Contact_MasterRad);


                debug("before cmMag");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_MasterMag);
                debug("after cmMag " + conMasterLimb_Contact_MasterMag);

                debug("before csRad");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_SlaveRad);
                debug("after csRad " + conMasterLimb_Contact_SlaveRad);

                debug("before csMag");
                formatter.Serialize(fs, (double)conMasterLimb_Contact_SlaveMag);
                debug("after csMag " + conMasterLimb_Contact_SlaveMag);
            }

            debug("before number of lists");
            formatter.Serialize(fs, (int)cLimb.lstImages.Count);
            debug("after number of lists " + cLimb.lstImages.Count.ToString());

            for (int intListCounter = 0; intListCounter < cLimb.lstImages.Count; intListCounter++)
            {
                classSprite_Limb.classSprite_Limb_Images cImages = cLimb.lstImages[intListCounter];

                debug("before image list name");
                formatter.Serialize(fs, (string)cImages.Name);
                debug("after images list name :" + cImages.Name);

                debug("forEach image");
                for (int intImageCounter = 0; intImageCounter < cLimb.cSprite.NumImagesPerQuadrant; intImageCounter++)
                {
                    intDebugIndent = 2;
                    Bitmap bmp = cImages.bmpImages[intImageCounter];
                    debug("before bmp");
                    formatter.Serialize(fs, (Bitmap)bmp);
                    debug("after bmp");
                }
            }


            debug("forEach slave");
            for (int intSlaveCounter = 0; intSlaveCounter < cLimb.lstHinge_Slaves.Count; intSlaveCounter++)
            {
                classSprite_Limb cLimbSlave = cLimb.lstHinge_Slaves[intSlaveCounter].Limb_Slave;
                Save_LimbRecursion(ref cLimbSlave, ref fs);
            }
            intDebugIndent = 1;
            debug("exit recursion :" + cLimb.Name);
        }

        #region Debug_SaveLoad

        /// <summary>
        /// debugging tools to help read data being compiled by debugger
        /// </summary>
        RichTextBox rtxDebug = new RichTextBox();
        int intDebugIndent = 0;// /t is added for each integral value of intDebugIndent for debugging reports
        string strDebugFilename = "debug";
        string strDebugPath = "c:\\debug\\";
        enum enuDebugOutput { none, output, rtf, txt };


        enuDebugOutput _eDebugOutput = enuDebugOutput.none;
        enuDebugOutput eDebugOutput
        {
            get { return _eDebugOutput; }
            set
            {
                _eDebugOutput = value;
                //_eDebugOutput = enuDebugOutput.none;
            }
        }

        /// <summary>
        /// debugging tool used to find/repair save/load bugging issues
        /// </summary>
        void debugSave()
        {
            switch (eDebugOutput)
            {
                case enuDebugOutput.rtf:
                    string strFullName = strDebugPath + strDebugFilename + ".rtf";
                    if (System.IO.File.Exists(strFullName))
                        System.IO.File.Delete(strFullName);
                    rtxDebug.SaveFile(strFullName, RichTextBoxStreamType.RichText);
                    System.IO.File.WriteAllText(strDebugPath + strDebugFilename + ".txt", rtxDebug.Text);
                    System.Diagnostics.Debug.Print(rtxDebug.Text);
                    break;
            }
        }

        void debugClear()
        {
            rtxDebug.Text = "";
        }

        void debug(string strMessage)
        {
            switch (eDebugOutput)
            {
                case enuDebugOutput.output:
                    System.Diagnostics.Debug.Print(strMessage + " (" + fs.Position.ToString() + ")");
                    break;

                case enuDebugOutput.txt:
                    System.IO.File.AppendAllText(strDebugPath + strDebugFilename + ".txt", strMessage);
                    break;

                case enuDebugOutput.rtf:
                    rtxDebug.Multiline = true;
                    rtxDebug.Text += "\n\r".PadRight(intDebugIndent, '\t') + fs.Position.ToString() + ":" + strMessage;
                    break;
            }
        }
        #endregion 


        string TextSpriteFilename(string SpriteFilename)
        {
            return SpriteFilename.Replace(conSpriteFileExtension3, conTextSpriteFileExtension)
                                 .Replace(conSpriteFileExtension4, conTextSpriteFileExtension)
                                 .Replace(conSpriteFileExtension5, conTextSpriteFileExtension)
                                 .Replace(conSpriteFileExtension6, conTextSpriteFileExtension);
        }

        classTextSpriteInfo TextSpriteInfo_Load(string filename)
        {
            string strTextSpriteFilename = TextSpriteFilename(filename);
            if (System.IO.File.Exists(strTextSpriteFilename))
            {
                FileStream fsTextSprite = new FileStream(strTextSpriteFilename, FileMode.Open);
                fsTextSprite.Position = 0;

                classTextSpriteInfo cRetVal = new classTextSpriteInfo();

                string strFontFamilyName = ((string)formatter.Deserialize(fsTextSprite)).Trim();
                bool bolBold = (bool)formatter.Deserialize(fsTextSprite);
                bool bolUnderLined = (bool)formatter.Deserialize(fsTextSprite);
                bool bolItalic = (bool)formatter.Deserialize(fsTextSprite);
                bool bolStrikeOut = (bool)formatter.Deserialize(fsTextSprite);
                float fltSize = (float)formatter.Deserialize(fsTextSprite);

                FontStyle fntStyle = FontStyle.Regular;
                if (bolBold)
                    fntStyle = fntStyle | FontStyle.Bold;
                if (bolUnderLined)
                    fntStyle = fntStyle | FontStyle.Underline;
                if (bolItalic)
                    fntStyle = fntStyle | FontStyle.Italic;
                if (bolStrikeOut)
                    fntStyle = fntStyle | FontStyle.Strikeout;

                cRetVal.fnt = new Font(strFontFamilyName, fltSize, fntStyle);

                cRetVal.Color_Fore = Color_Read(ref fsTextSprite);
                cRetVal.Color_Transparent = Color_Read(ref fsTextSprite);

                cRetVal.Valid = true;

                return cRetVal;
            }
            else
                return new classTextSpriteInfo();
        }

        void TextSpriteInfo_Save(ref classTextSpriteInfo cTextSpriteInfo, string filename)
        {
            string strTextSpriteFilename = TextSpriteFilename(filename);

            FileStream fsTextSprite = new FileStream(strTextSpriteFilename, FileMode.Create);
            fsTextSprite.Position = 0;

            //              save font   
            formatter.Serialize(fsTextSprite, (string)cTextSpriteInfo.fnt.FontFamily.Name);
            formatter.Serialize(fsTextSprite, (bool)cTextSpriteInfo.fnt.Bold);
            formatter.Serialize(fsTextSprite, (bool)cTextSpriteInfo.fnt.Underline);
            formatter.Serialize(fsTextSprite, (bool)cTextSpriteInfo.fnt.Italic);
            formatter.Serialize(fsTextSprite, (bool)cTextSpriteInfo.fnt.Strikeout);
            formatter.Serialize(fsTextSprite, (float)cTextSpriteInfo.fnt.Size);
            //              save fore color
            Color_Write(ref fsTextSprite, cTextSpriteInfo.Color_Fore);
            //              save transparent color
            Color_Write(ref fsTextSprite, cTextSpriteInfo.Color_Transparent);

            fsTextSprite.Close();
        }


        Color Color_Read(ref FileStream fs)
        {
            int intRed = (int)formatter.Deserialize(fs);
            int intGreen = (int)formatter.Deserialize(fs);
            int intBlue = (int)formatter.Deserialize(fs);

            Color clrRetVal = Color.FromArgb(intRed, intGreen, intBlue);
            return clrRetVal;
        }

        void Color_Write(ref FileStream fs, Color clr)
        {
            formatter.Serialize(fs, (int)clr.R);
            formatter.Serialize(fs, (int)clr.G);
            formatter.Serialize(fs, (int)clr.B);
        }

        public classSprite Load(string filename)
        {
            enuFileExtensionsSupported eFileExtension = GetSpriteVersionByFilename(filename);
            switch (eFileExtension)
            {
                case enuFileExtensionsSupported.SP3:
                    return Load_SP3(filename);

                case enuFileExtensionsSupported.SP4:
                    return Load_SP4(filename);

                case enuFileExtensionsSupported.SP5:
                    return Load_SP5(filename);

                case enuFileExtensionsSupported.SP6:
                    return Load_SP6(filename);

                default:
                    return null;
            }
        }

        /// <summary>
        /// loads sprite sequentially from the harddrive
        /// </summary>
        /// <param name="filename">name of file to be loaded</param>
        /// <returns>the sprite requested</returns>
        public classSprite Load_SP3(string filename)
        {
            debugClear();
            eDebugOutput = enuDebugOutput.none;
            classSprite cRetVal = null;
            if (System.IO.File.Exists(filename))
            {
                try
                {
                    fs = new FileStream(filename, FileMode.Open);
                    fs.Position = 0;
                    intDebugIndent = 0;
                    debug("startLoad_G3");
                    string strSpriteName = ((string)formatter.Deserialize(fs)).Trim();
                    debug("before spriteName " + strSpriteName.ToString());
                    cRetVal = new classSprite(strSpriteName);
                    cRetVal.textSpriteInfo = TextSpriteInfo_Load(filename);
                    cRetVal.Animation_Delete(classSprite.conDefaultAnimationName);

                    /*
                    long lngFSPosition_BeforeTryReadTextSprite = fs.Position;
                    // used to prevent older sprite files from being un-readable
                    try
                    {
                        cRetVal.TextSprite = (bool)formatter.Deserialize(fs);
                    }
                    catch (Exception e)
                    {
                        System.Diagnostics.Debug.Print("classSpriteMaker.Load(string filename) ERROR:" + e.Message);
                        fs.Position = lngFSPosition_BeforeTryReadTextSprite;
                    }
                    */

                    cRetVal.NumImagesPerQuadrant = (int)formatter.Deserialize(fs);
                    debug("after intNUmImages " + cRetVal.NumImagesPerQuadrant.ToString());

                    cRetVal.UseRamCache = (bool)formatter.Deserialize(fs);
                    debug("after bool Use RAM Cache");

                    int intNumberLimbs = (int)formatter.Deserialize(fs);
                    debug("after intNumberLimibs " + intNumberLimbs.ToString());

                    debug("forEach Limb");
                    for (int intLimbCounter = 0; intLimbCounter < intNumberLimbs; intLimbCounter++)
                    {
                        intDebugIndent = 1;

                        classLoadLimbsInfo cCostume_LoadingInfo = new classLoadLimbsInfo();

                        cCostume_LoadingInfo.LimbName = (string)formatter.Deserialize(fs);
                        debug("after limbName " + cCostume_LoadingInfo.LimbName);

                        cCostume_LoadingInfo.MasterLimbName = ((string)formatter.Deserialize(fs)).Trim();
                        if (cCostume_LoadingInfo.MasterLimbName.Contains(classSprite.conMasterLimb_Name))
                        {
                            int intIndexMasterLimb = cCostume_LoadingInfo.MasterLimbName.IndexOf(classSprite.conMasterLimb_Name);
                            if (intIndexMasterLimb > 0)
                                cCostume_LoadingInfo.MasterLimbName = cCostume_LoadingInfo.MasterLimbName.Substring(intIndexMasterLimb);
                        }
                        debug("after MasterLimbName " + cCostume_LoadingInfo.MasterLimbName);

                        double dblMasterRad = (double)formatter.Deserialize(fs);
                        debug("after MasterRad " + dblMasterRad.ToString());

                        double dblMasterMag = (double)formatter.Deserialize(fs);
                        debug("after MasterMag " + dblMasterRad.ToString());

                        cCostume_LoadingInfo.cRad_ContactMaster = new classRadialCoordinate(dblMasterRad, dblMasterMag);

                        double dblSlaveRad = (double)formatter.Deserialize(fs);
                        debug("after SlaveRad " + dblSlaveRad.ToString());

                        double dblSlaveMag = (double)formatter.Deserialize(fs);
                        debug("after SlaveMag " + dblSlaveMag.ToString());

                        cCostume_LoadingInfo.cRad_ContactSlave = new classRadialCoordinate(dblSlaveRad, dblSlaveMag);

                        int intNumberLimbImageLists = (int)formatter.Deserialize(fs);
                        debug("after number of lists:" + intNumberLimbImageLists.ToString());

                        classSprite_Limb cLimbNew = null;
                        if (cCostume_LoadingInfo.LimbName.IndexOf("MasterLimb") < 0)
                        {
                            cLimbNew = classSprite_Limb.New(cCostume_LoadingInfo.LimbName, ref cRetVal, null);
                            cLimbNew.lstImages.Clear();
                        }

                        for (int intImageListCounter = 0; intImageListCounter < intNumberLimbImageLists; intImageListCounter++)
                        {
                            classSprite_Limb.classSprite_Limb_Images cImages = new classSprite_Limb.classSprite_Limb_Images();
                            cImages.Name = (string)formatter.Deserialize(fs);
                            if (cLimbNew != null && cLimbNew.lstImages != null)
                            {
                                cLimbNew.lstImages.Add(cImages);

                                object objLimbImages = (object)cImages;
                                cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                            }
                            debug("after Image list name:" + cImages.Name);

                            debug("forEach Bitmap");
                            for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                            {
                                intDebugIndent = 2;
                                Bitmap bmp = (Bitmap)formatter.Deserialize(fs);
                                debug("after Bmp ");
                                cCostume_LoadingInfo.lstBmp.Add(bmp);
                            }

                            if (cLimbNew != null)
                            {
                                cLimbNew.lstImages[intImageListCounter].bmpImages = new Bitmap[4 * cRetVal.NumImagesPerQuadrant];
                                for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                                    cLimbNew.lstImages[intImageListCounter].bmpImages[intImageCounter] = cCostume_LoadingInfo.lstBmp[intImageCounter];
                                cCostume_LoadingInfo.lstBmp.Clear();
                            }

                            if (intImageListCounter == 0)
                                if (cCostume_LoadingInfo.LimbName.IndexOf(classSprite.conMasterLimb_Name) < 0)
                                { // this is NOT the master limb -> build data trees for this limb/hinge
                                    classSprite_Limb cLimb_Master = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(cCostume_LoadingInfo.MasterLimbName);

                                    cLimbNew.Hinge = new classSprite_Hinge(ref cRetVal, ref cLimbNew, ref cLimb_Master);
                                    cLimb_Master.Slave_Add(ref cLimbNew);
                                    cLimbNew.Hinge.Contact.Master = cCostume_LoadingInfo.cRad_ContactMaster;
                                    cLimbNew.Hinge.Contact.Slave = cCostume_LoadingInfo.cRad_ContactSlave;
                                }
                        }
                    }

                    intDebugIndent = 0;
                    eDebugOutput = enuDebugOutput.none;
                    // load animations
                    int intNumberAnimations = (int)formatter.Deserialize(fs);
                    debug("after numAnimations " + intNumberAnimations.ToString());

                    debug("forEAch Animation");
                    cRetVal.cBT_Animations = new BinTree.classBinTree();
                    for (int intAnimationCounter = 0; intAnimationCounter < intNumberAnimations; intAnimationCounter++)
                    {
                        intDebugIndent = 1;
                        classAnimation cAnimation = new classAnimation(ref cRetVal);
                        debug("-------------------------start animation [" + intAnimationCounter.ToString() + "]" + cAnimation.Name + "--------------------");
                        cRetVal.lstAnimations.Add(cAnimation);

                        cAnimation.Name = ((string)formatter.Deserialize(fs)).Trim();
                        debug("after animation Name " + cAnimation.Name);

                        intDebugIndent = 1;
                        try
                        {
                            int intNumFrames = (int)formatter.Deserialize(fs);
                            debug("after numFrames " + intNumFrames.ToString());

                            debug("forEach Frame");
                            for (int intFrameCounter = 0; intFrameCounter < intNumFrames; intFrameCounter++)
                            {
                                debug("--------------------------------Framecounter:(" + intFrameCounter.ToString() + ")-----------------------------");
                                intDebugIndent = 2;
                                classAnimation_Frame cFrame = new classAnimation_Frame(ref cRetVal);
                                cAnimation.lstFrames.Add(cFrame);
                                cFrame.Animation = cAnimation;

                                cFrame.ptTL.X = (int)formatter.Deserialize(fs);
                                debug("after FramePtTL.x " + cFrame.ptTL.X.ToString());

                                cFrame.ptTL.Y = (int)formatter.Deserialize(fs);
                                debug("after FramePtTL.y " + cFrame.ptTL.Y.ToString());

                                cFrame.Vertical_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Vertical mirror:" + cFrame.Vertical_Mirror.ToString());

                                cFrame.Horizontal_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Horizontal mirror:" + cFrame.Horizontal_Mirror.ToString());

                                string strLimb_DrawRelativeTo = (string)formatter.Deserialize(fs);
                                cFrame.Limb_DrawRelativeTo = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf((classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strLimb_DrawRelativeTo));
                                debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                                int intNumLimbsToDraw = 0;

                                int intNumInDrawSequence = (int)formatter.Deserialize(fs);
                                debug("after NumInDrawSequence " + intNumInDrawSequence.ToString());

                                debug("forEAch LimbInDrawSequence");
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 2;
                                    string strDrawSequence_LimbName = ((string)formatter.Deserialize(fs)).Trim();
                                    debug("after DrawSequence LimbName " + strDrawSequence_LimbName);
                                    debug("-----------------------------Limb[" + intLimbCounter.ToString() + "]" + strDrawSequence_LimbName + "-------------------");
                                    classSprite_Limb cDrawSequenceLimb = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strDrawSequence_LimbName);
                                    int intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cDrawSequenceLimb);
                                    cFrame.lstDrawSequence.Add(intLimbIndex);
                                    if (cDrawSequenceLimb == null)
                                        intNumLimbsToDraw = cFrame.lstDrawSequence.Count;
                                }

                                debug("----------------------------------forEach LimbToDraw");
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                //eDebugOutput = enuDebugOutput.none;
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 3;
                                    classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrame);
                                    cFrame.lstData.Add(cData);

                                    string strName = ((string)formatter.Deserialize(fs)).Trim();                                // Name

                                    debug("-------------------LImbCounter(" + intLimbCounter.ToString() + ")" + strName + "--------------------");
                                    classSprite_Limb cLimbSearch = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strName);
                                    cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cLimbSearch);
                                    if (cData.intLimbIndex < 0)
                                    {
                                        cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cRetVal.cCostumeInfo_Default.cLimb_Master);
                                        debug("after Limbname : Null");
                                    }
                                    else debug("after LimbName " + cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                                    cData.Angle = (double)formatter.Deserialize(fs);                                            // Angle
                                    debug("after Angle " + cData.Angle.ToString());

                                    long lngFsPosition = fs.Position;
                                    double dblSlaveContactMagnitude_Factor = (double)formatter.Deserialize(fs);                  // SlavecontactMagnitude_Factor

                                    cData.SlaveContactMagnitude_Factor = dblSlaveContactMagnitude_Factor;
                                    debug("after SCMag_Factor " + cData.SlaveContactMagnitude_Factor.ToString());

                                    int intX = (int)formatter.Deserialize(fs);                                      // DrawTL.x
                                    debug("after ptDrawCenter.x " + cData.ptDrawCenter.X.ToString());

                                    int intY = (int)formatter.Deserialize(fs);                                      // DrawTL.y
                                    debug("after ptDrawCenter.y " + cData.ptDrawCenter.Y.ToString());

                                    cData.ptDrawCenter = new Point(intX, intY);

                                    debug("before LimbDrawList_Name");
                                    cData.ImageList_Name = (string)formatter.Deserialize(fs);
                                    debug("after LimbImageDrawList_Name " + cData.ImageList_Name);
                                }
                            }
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                            debug("End animation : " + cAnimation.Name);
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        }
                        catch (Exception err)
                        {
                            debug("err: " + err);
                            strDebugFilename = "rtf_Load";
                            eDebugOutput = enuDebugOutput.none;
                            debugSave();
                        }
                        object objAnimation = (object)cAnimation;
                        cRetVal.cBT_Animations.Insert(ref objAnimation, cAnimation.Name);
                    }
                    eDebugOutput = enuDebugOutput.none;
                    intDebugIndent = 0;
                    debug("end of load_g3");
                }
                catch (Exception e)
                {
                    if (classSprite.ShowErrorMessages)
                        MessageBox.Show("Error loading file(" + filename + "):" + e.Message, "Error");
                }

                if (fs != null) fs.Close();
                if (cRetVal != null)
                    cRetVal.AlphabetizeAnimations();

                debugSave();
                return cRetVal;
            }
            else
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("file \"" + filename + "\" not found.");
                return null;
            }
        }


        /// <summary>
        /// loads sprite sequentially from the harddrive
        /// </summary>
        /// <param name="filename">name of file to be loaded</param>
        /// <returns>the sprite requested</returns>
        public classSprite Load_SP6(string filename) 
        {
            debugClear();
            eDebugOutput = enuDebugOutput.none;
            classSprite cRetVal = null;
            if (System.IO.File.Exists(filename))
            {
                try
                {
                    fs = new FileStream(filename, FileMode.Open);
                    fs.Position = 0;
                    intDebugIndent = 0;
                    debug("startLoad_G3");
                    string strSpriteName = ((string)formatter.Deserialize(fs)).Trim();
                    debug("before spriteName " + strSpriteName.ToString());
                    cRetVal = new classSprite(strSpriteName);
                    cRetVal.textSpriteInfo = TextSpriteInfo_Load(filename);

                    cRetVal.Animation_Delete(classSprite.conDefaultAnimationName);

                    cRetVal.NumImagesPerQuadrant = (int)formatter.Deserialize(fs);
                    debug("after intNUmImages " + cRetVal.NumImagesPerQuadrant.ToString());

                    cRetVal.UseRamCache = (bool)formatter.Deserialize(fs);
                    debug("after bool Use RAM Cache");

                    cRetVal.eRotatedLimbImage = (classSprite.enuRotatedLimbImage)(byte)formatter.Deserialize(fs);
                    debug("after enuRotatedLimbImage");

                    int intNumberLimbs = (int)formatter.Deserialize(fs);
                    debug("after intNumberLimibs " + intNumberLimbs.ToString());

                    debug("forEach Limb");
                    for (int intLimbCounter = 0; intLimbCounter < intNumberLimbs; intLimbCounter++)
                    {
                        intDebugIndent = 1;

                        classLoadLimbsInfo cCostume_LoadingInfo = new classLoadLimbsInfo();

                        cCostume_LoadingInfo.LimbName = (string)formatter.Deserialize(fs);
                        debug("after limbName " + cCostume_LoadingInfo.LimbName);

                        cCostume_LoadingInfo.MasterLimbName = ((string)formatter.Deserialize(fs)).Trim();
                        if (cCostume_LoadingInfo.MasterLimbName.Contains(classSprite.conMasterLimb_Name))
                        {
                            int intIndexMasterLimb = cCostume_LoadingInfo.MasterLimbName.IndexOf(classSprite.conMasterLimb_Name);
                            if (intIndexMasterLimb > 0)
                                cCostume_LoadingInfo.MasterLimbName = cCostume_LoadingInfo.MasterLimbName.Substring(intIndexMasterLimb);
                        }
                        debug("after MasterLimbName " + cCostume_LoadingInfo.MasterLimbName);

                        double dblMasterRad = (double)formatter.Deserialize(fs);
                        debug("after MasterRad " + dblMasterRad.ToString());

                        double dblMasterMag = (double)formatter.Deserialize(fs);
                        debug("after MasterMag " + dblMasterRad.ToString());

                        cCostume_LoadingInfo.cRad_ContactMaster = new classRadialCoordinate(dblMasterRad, dblMasterMag);

                        double dblSlaveRad = (double)formatter.Deserialize(fs);
                        debug("after SlaveRad " + dblSlaveRad.ToString());

                        double dblSlaveMag = (double)formatter.Deserialize(fs);
                        debug("after SlaveMag " + dblSlaveMag.ToString());

                        cCostume_LoadingInfo.cRad_ContactSlave = new classRadialCoordinate(dblSlaveRad, dblSlaveMag);

                        int intNumberLimbImageLists = (int)formatter.Deserialize(fs);
                        debug("after number of lists:" + intNumberLimbImageLists.ToString());

                        classSprite_Limb cLimbNew = null;
                        if (cCostume_LoadingInfo.LimbName.IndexOf("MasterLimb") < 0)
                        {
                            cLimbNew = classSprite_Limb.New(cCostume_LoadingInfo.LimbName, ref cRetVal, null);
                            cLimbNew.lstImages.Clear();
                        }

                        for (int intImageListCounter = 0; intImageListCounter < intNumberLimbImageLists; intImageListCounter++)
                        {
                            classSprite_Limb.classSprite_Limb_Images cImages = new classSprite_Limb.classSprite_Limb_Images();
                            cImages.Name = (string)formatter.Deserialize(fs);
                            if (cLimbNew != null && cLimbNew.lstImages != null)
                            {
                                cLimbNew.lstImages.Add(cImages);

                                object objLimbImages = (object)cImages;
                                cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                            }
                            debug("after Image list name:" + cImages.Name);

                            debug("forEach Bitmap");
                            for (int intImageCounter = 0;
                                intImageCounter < (cRetVal.eRotatedLimbImage == classSprite.enuRotatedLimbImage.SaveToFile 
                                                                              ? cRetVal.NumImagesPerQuadrant
                                                                              : 1); 
                                intImageCounter++)
                            {
                                intDebugIndent = 2;
                                Bitmap bmp = (Bitmap)formatter.Deserialize(fs);
                                debug("after Bmp ");
                                cCostume_LoadingInfo.lstBmp.Add(bmp);
                            }

                            if (cLimbNew != null)
                            {
                                cLimbNew.lstImages[intImageListCounter].bmpImages = new Bitmap[4 * cRetVal.NumImagesPerQuadrant];
                                switch(cRetVal.eRotatedLimbImage)
                                {
                                    case classSprite.enuRotatedLimbImage.SaveToFile:
                                        {
                                            for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                                                cLimbNew.lstImages[intImageListCounter].bmpImages[intImageCounter] = cCostume_LoadingInfo.lstBmp[intImageCounter];
                                        }
                                        break;

                                    case classSprite.enuRotatedLimbImage.GenerateAtLoadTime:
                                        {
                                            cLimbNew.lstImages[intImageListCounter].bmpImages[0] = cCostume_LoadingInfo.lstBmp[0];
                                            float fltDeltaAngle = 90f / (float)conNumImagesPerQuadrant;
                                            for (float fltAngleCounter = 1; fltAngleCounter < conNumImagesPerQuadrant; fltAngleCounter++)
                                                cLimbNew.lstImages[intImageListCounter].bmpImages[(int)fltAngleCounter] = Math3.classGraphics.Rotate(cLimbNew.lstImages[intImageListCounter].bmpImages[0], fltDeltaAngle * fltAngleCounter);
                                        }
                                        break;

                                    case classSprite.enuRotatedLimbImage.GenerateOnRequest:
                                        {
                                            cLimbNew.lstImages[intImageListCounter].bmpImages[0] = cCostume_LoadingInfo.lstBmp[0];
                                        }
                                        break;

                                    default:
                                        MessageBox.Show("this should not happen");
                                        break;
                                }

                                cCostume_LoadingInfo.lstBmp.Clear();
                            }

                            if (intImageListCounter == 0)
                                if (cCostume_LoadingInfo.LimbName.IndexOf(classSprite.conMasterLimb_Name) < 0)
                                { // this is NOT the master limb -> build data trees for this limb/hinge
                                    classSprite_Limb cLimb_Master = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(cCostume_LoadingInfo.MasterLimbName);

                                    cLimbNew.Hinge = new classSprite_Hinge(ref cRetVal, ref cLimbNew, ref cLimb_Master);
                                    cLimb_Master.Slave_Add(ref cLimbNew);
                                    cLimbNew.Hinge.Contact.Master = cCostume_LoadingInfo.cRad_ContactMaster;
                                    cLimbNew.Hinge.Contact.Slave = cCostume_LoadingInfo.cRad_ContactSlave;
                                }
                        }
                    }

                    intDebugIndent = 0;
                    eDebugOutput = enuDebugOutput.none;
                    // load animations
                    int intNumberAnimations = (int)formatter.Deserialize(fs);
                    debug("after numAnimations " + intNumberAnimations.ToString());

                    debug("forEAch Animation");
                    cRetVal.cBT_Animations = new BinTree.classBinTree();
                    for (int intAnimationCounter = 0; intAnimationCounter < intNumberAnimations; intAnimationCounter++)
                    {
                        intDebugIndent = 1;
                        classAnimation cAnimation = new classAnimation(ref cRetVal);
                        debug("-------------------------start animation [" + intAnimationCounter.ToString() + "]" + cAnimation.Name + "--------------------");
                        cRetVal.lstAnimations.Add(cAnimation);

                        cAnimation.Name = ((string)formatter.Deserialize(fs)).Trim();
                        debug("after animation Name " + cAnimation.Name);

                        intDebugIndent = 1;
                        try
                        {
                            int intNumFrames = (int)formatter.Deserialize(fs);
                            debug("after numFrames " + intNumFrames.ToString());

                            debug("forEach Frame");
                            for (int intFrameCounter = 0; intFrameCounter < intNumFrames; intFrameCounter++)
                            {
                                debug("--------------------------------Framecounter:(" + intFrameCounter.ToString() + ")-----------------------------");
                                intDebugIndent = 2;
                                classAnimation_Frame cFrame = new classAnimation_Frame(ref cRetVal);
                                cAnimation.lstFrames.Add(cFrame);
                                cFrame.Animation = cAnimation;

                                cFrame.Vertical_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Vertical mirror:" + cFrame.Vertical_Mirror.ToString());

                                cFrame.Horizontal_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Horizontal mirror:" + cFrame.Horizontal_Mirror.ToString());

                                string strLimb_DrawRelativeTo = (string)formatter.Deserialize(fs);
                                cFrame.Limb_DrawRelativeTo = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf((classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strLimb_DrawRelativeTo));
                                debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                                int intNumLimbsToDraw = 0;

                                int intNumInDrawSequence = (int)formatter.Deserialize(fs);
                                debug("after NumInDrawSequence " + intNumInDrawSequence.ToString());

                                debug("forEAch LimbInDrawSequence");
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 2;
                                    string strDrawSequence_LimbName = ((string)formatter.Deserialize(fs)).Trim();
                                    debug("after DrawSequence LimbName " + strDrawSequence_LimbName);
                                    debug("-----------------------------Limb[" + intLimbCounter.ToString() + "]" + strDrawSequence_LimbName + "-------------------");
                                    classSprite_Limb cDrawSequenceLimb = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strDrawSequence_LimbName);
                                    int intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cDrawSequenceLimb);
                                    cFrame.lstDrawSequence.Add(intLimbIndex);
                                    if (cDrawSequenceLimb == null)
                                        intNumLimbsToDraw = cFrame.lstDrawSequence.Count;
                                }

                                debug("----------------------------------forEach LimbToDraw");
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                //eDebugOutput = enuDebugOutput.none;
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                cFrame.lstOverride.Clear();
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 3;
                                    classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrame);
                                    cFrame.lstData.Add(cData);

                                    string strName = ((string)formatter.Deserialize(fs)).Trim();                                // Name

                                    debug("-------------------LImbCounter(" + intLimbCounter.ToString() + ")" + strName + "--------------------");
                                    classSprite_Limb cLimbSearch = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strName);
                                    cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cLimbSearch);
                                    if (cData.intLimbIndex < 0)
                                    {
                                        cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cRetVal.cCostumeInfo_Default.cLimb_Master);
                                        debug("after Limbname : Null");
                                    }
                                    else debug("after LimbName " + cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                                    cData.Override = (bool)formatter.Deserialize(fs);                                           // override
                                    debug("after Override " + cData.Override.ToString());
                                    if (cData.Override)
                                        cFrame.lstOverride.Add(cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex]);

                                    cData.Angle = (double)formatter.Deserialize(fs);                                            // Angle
                                    debug("after Angle " + cData.Angle.ToString());

                                    long lngFsPosition = fs.Position;
                                    double dblSlaveContactMagnitude_Factor = (double)formatter.Deserialize(fs);                  // SlavecontactMagnitude_Factor

                                    cData.SlaveContactMagnitude_Factor = dblSlaveContactMagnitude_Factor;
                                    debug("after SCMag_Factor " + cData.SlaveContactMagnitude_Factor.ToString());

                                    cData.Opacity = (byte)formatter.Deserialize(fs);                                            // opacity
                                    debug("after opacity");

                                    cData.ColorFilter.Valid = (bool)formatter.Deserialize(fs);                                  // color filter - valid
                                    debug("after ColorFilter.Valid");

                                    byte bytR = (byte)formatter.Deserialize(fs);                                                 // color filter - R
                                    debug("after ColorFilter.R");

                                    byte bytG = (byte)formatter.Deserialize(fs);                                                 // color filter - G
                                    debug("after ColorFilter.G");

                                    byte bytB = (byte)formatter.Deserialize(fs);                                                 // color filter - B
                                    debug("after ColorFilter.B");

                                    cData.ColorFilter.clr = Color.FromArgb(bytR, bytG, bytB);
                                    debug("after ColorFilter");

                                    cData.ImageList_Name = (string)formatter.Deserialize(fs);
                                    debug("after LimbImageDrawList_Name " + cData.ImageList_Name);

                                }
                            }
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                            debug("End animation : " + cAnimation.Name);
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        }
                        catch (Exception err)
                        {
                            debug("err: " + err);
                            strDebugFilename = "rtf_Load";
                            eDebugOutput = enuDebugOutput.none;
                            debugSave();
                        }
                        object objAnimation = (object)cAnimation;
                        cRetVal.cBT_Animations.Insert(ref objAnimation, cAnimation.Name);
                    }
                    eDebugOutput = enuDebugOutput.none;
                    intDebugIndent = 0;
                    debug("end of load_g3");
                }
                catch (Exception e)
                {
                    if (classSprite.ShowErrorMessages)
                        MessageBox.Show("Error loading file(" + filename + "):" + e.Message, "Error");
                }

                if (fs != null) fs.Close();
                if (cRetVal != null)
                    cRetVal.AlphabetizeAnimations();

                debugSave();
                return cRetVal;
            }
            else
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("file \"" + filename + "\" not found.");
                return null;
            }
        }

        /// <summary>
        /// loads sprite sequentially from the harddrive
        /// </summary>
        /// <param name="filename">name of file to be loaded</param>
        /// <returns>the sprite requested</returns>
        public classSprite Load_SP5(string filename)
        {
            debugClear();
            eDebugOutput = enuDebugOutput.none;
            classSprite cRetVal = null;
            if (System.IO.File.Exists(filename))
            {
                try
                {
                    fs = new FileStream(filename, FileMode.Open);
                    fs.Position = 0;
                    intDebugIndent = 0;
                    debug("startLoad_G3");
                    string strSpriteName = ((string)formatter.Deserialize(fs)).Trim();
                    debug("before spriteName " + strSpriteName.ToString());
                    cRetVal = new classSprite(strSpriteName);
                    cRetVal.textSpriteInfo = TextSpriteInfo_Load(filename);

                    cRetVal.Animation_Delete(classSprite.conDefaultAnimationName);

                    cRetVal.NumImagesPerQuadrant = (int)formatter.Deserialize(fs);
                    debug("after intNUmImages " + cRetVal.NumImagesPerQuadrant.ToString());

                    cRetVal.UseRamCache = (bool)formatter.Deserialize(fs);
                    debug("after bool Use RAM Cache");

                    int intNumberLimbs = (int)formatter.Deserialize(fs);
                    debug("after intNumberLimibs " + intNumberLimbs.ToString());

                    debug("forEach Limb");
                    for (int intLimbCounter = 0; intLimbCounter < intNumberLimbs; intLimbCounter++)
                    {
                        intDebugIndent = 1;

                        classLoadLimbsInfo cCostume_LoadingInfo = new classLoadLimbsInfo();

                        cCostume_LoadingInfo.LimbName = (string)formatter.Deserialize(fs);
                        debug("after limbName " + cCostume_LoadingInfo.LimbName);

                        cCostume_LoadingInfo.MasterLimbName = ((string)formatter.Deserialize(fs)).Trim();
                        if (cCostume_LoadingInfo.MasterLimbName.Contains(classSprite.conMasterLimb_Name))
                        {
                            int intIndexMasterLimb = cCostume_LoadingInfo.MasterLimbName.IndexOf(classSprite.conMasterLimb_Name);
                            if (intIndexMasterLimb > 0)
                                cCostume_LoadingInfo.MasterLimbName = cCostume_LoadingInfo.MasterLimbName.Substring(intIndexMasterLimb);
                        }
                        debug("after MasterLimbName " + cCostume_LoadingInfo.MasterLimbName);

                        double dblMasterRad = (double)formatter.Deserialize(fs);
                        debug("after MasterRad " + dblMasterRad.ToString());

                        double dblMasterMag = (double)formatter.Deserialize(fs);
                        debug("after MasterMag " + dblMasterRad.ToString());

                        cCostume_LoadingInfo.cRad_ContactMaster = new classRadialCoordinate(dblMasterRad, dblMasterMag);

                        double dblSlaveRad = (double)formatter.Deserialize(fs);
                        debug("after SlaveRad " + dblSlaveRad.ToString());

                        double dblSlaveMag = (double)formatter.Deserialize(fs);
                        debug("after SlaveMag " + dblSlaveMag.ToString());

                        cCostume_LoadingInfo.cRad_ContactSlave = new classRadialCoordinate(dblSlaveRad, dblSlaveMag);

                        int intNumberLimbImageLists = (int)formatter.Deserialize(fs);
                        debug("after number of lists:" + intNumberLimbImageLists.ToString());

                        classSprite_Limb cLimbNew = null;
                        if (cCostume_LoadingInfo.LimbName.IndexOf("MasterLimb") < 0)
                        {
                            cLimbNew = classSprite_Limb.New(cCostume_LoadingInfo.LimbName, ref cRetVal, null);
                            cLimbNew.lstImages.Clear();
                        }

                        for (int intImageListCounter = 0; intImageListCounter < intNumberLimbImageLists; intImageListCounter++)
                        {
                            classSprite_Limb.classSprite_Limb_Images cImages = new classSprite_Limb.classSprite_Limb_Images();
                            cImages.Name = (string)formatter.Deserialize(fs);
                            if (cLimbNew != null && cLimbNew.lstImages != null)
                            {
                                cLimbNew.lstImages.Add(cImages);

                                object objLimbImages = (object)cImages;
                                cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                            }
                            debug("after Image list name:" + cImages.Name);

                            debug("forEach Bitmap");
                            for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                            {
                                intDebugIndent = 2;
                                Bitmap bmp = (Bitmap)formatter.Deserialize(fs);
                                debug("after Bmp ");
                                cCostume_LoadingInfo.lstBmp.Add(bmp);
                            }

                            if (cLimbNew != null)
                            {
                                cLimbNew.lstImages[intImageListCounter].bmpImages = new Bitmap[4 * cRetVal.NumImagesPerQuadrant];
                                for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                                    cLimbNew.lstImages[intImageListCounter].bmpImages[intImageCounter] = cCostume_LoadingInfo.lstBmp[intImageCounter];
                                cCostume_LoadingInfo.lstBmp.Clear();
                            }

                            if (intImageListCounter == 0)
                                if (cCostume_LoadingInfo.LimbName.IndexOf(classSprite.conMasterLimb_Name) < 0)
                                { // this is NOT the master limb -> build data trees for this limb/hinge
                                    classSprite_Limb cLimb_Master = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(cCostume_LoadingInfo.MasterLimbName);

                                    cLimbNew.Hinge = new classSprite_Hinge(ref cRetVal, ref cLimbNew, ref cLimb_Master);
                                    cLimb_Master.Slave_Add(ref cLimbNew);
                                    cLimbNew.Hinge.Contact.Master = cCostume_LoadingInfo.cRad_ContactMaster;
                                    cLimbNew.Hinge.Contact.Slave = cCostume_LoadingInfo.cRad_ContactSlave;
                                }
                        }
                    }

                    intDebugIndent = 0;
                    eDebugOutput = enuDebugOutput.none;
                    // load animations
                    int intNumberAnimations = (int)formatter.Deserialize(fs);
                    debug("after numAnimations " + intNumberAnimations.ToString());

                    debug("forEAch Animation");
                    cRetVal.cBT_Animations = new BinTree.classBinTree();
                    for (int intAnimationCounter = 0; intAnimationCounter < intNumberAnimations; intAnimationCounter++)
                    {
                        intDebugIndent = 1;
                        classAnimation cAnimation = new classAnimation(ref cRetVal);
                        debug("-------------------------start animation [" + intAnimationCounter.ToString() + "]" + cAnimation.Name + "--------------------");
                        cRetVal.lstAnimations.Add(cAnimation);

                        cAnimation.Name = ((string)formatter.Deserialize(fs)).Trim();
                        debug("after animation Name " + cAnimation.Name);

                        intDebugIndent = 1;
                        try
                        {
                            int intNumFrames = (int)formatter.Deserialize(fs);
                            debug("after numFrames " + intNumFrames.ToString());

                            debug("forEach Frame");
                            for (int intFrameCounter = 0; intFrameCounter < intNumFrames; intFrameCounter++)
                            {
                                debug("--------------------------------Framecounter:(" + intFrameCounter.ToString() + ")-----------------------------");
                                intDebugIndent = 2;
                                classAnimation_Frame cFrame = new classAnimation_Frame(ref cRetVal);
                                cAnimation.lstFrames.Add(cFrame);
                                cFrame.Animation = cAnimation;

                                cFrame.Vertical_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Vertical mirror:" + cFrame.Vertical_Mirror.ToString());

                                cFrame.Horizontal_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Horizontal mirror:" + cFrame.Horizontal_Mirror.ToString());

                                string strLimb_DrawRelativeTo = (string)formatter.Deserialize(fs);
                                cFrame.Limb_DrawRelativeTo = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf((classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strLimb_DrawRelativeTo));
                                debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                                int intNumLimbsToDraw = 0;

                                int intNumInDrawSequence = (int)formatter.Deserialize(fs);
                                debug("after NumInDrawSequence " + intNumInDrawSequence.ToString());

                                debug("forEAch LimbInDrawSequence");
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 2;
                                    string strDrawSequence_LimbName = ((string)formatter.Deserialize(fs)).Trim();
                                    debug("after DrawSequence LimbName " + strDrawSequence_LimbName);
                                    debug("-----------------------------Limb[" + intLimbCounter.ToString() + "]" + strDrawSequence_LimbName + "-------------------");
                                    classSprite_Limb cDrawSequenceLimb = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strDrawSequence_LimbName);
                                    int intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cDrawSequenceLimb);
                                    cFrame.lstDrawSequence.Add(intLimbIndex);
                                    if (cDrawSequenceLimb == null)
                                        intNumLimbsToDraw = cFrame.lstDrawSequence.Count;
                                }

                                debug("----------------------------------forEach LimbToDraw");
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                //eDebugOutput = enuDebugOutput.none;
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                cFrame.lstOverride.Clear();
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 3;
                                    classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrame);
                                    cFrame.lstData.Add(cData);

                                    string strName = ((string)formatter.Deserialize(fs)).Trim();                                // Name

                                    debug("-------------------LImbCounter(" + intLimbCounter.ToString() + ")" + strName + "--------------------");
                                    classSprite_Limb cLimbSearch = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strName);
                                    cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cLimbSearch);
                                    if (cData.intLimbIndex < 0)
                                    {
                                        cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cRetVal.cCostumeInfo_Default.cLimb_Master);
                                        debug("after Limbname : Null");
                                    }
                                    else debug("after LimbName " + cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                                    cData.Override = (bool)formatter.Deserialize(fs);                                           // override
                                    debug("after Override " + cData.Override.ToString());
                                    if (cData.Override)
                                        cFrame.lstOverride.Add(cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex]);

                                    cData.Angle = (double)formatter.Deserialize(fs);                                            // Angle
                                    debug("after Angle " + cData.Angle.ToString());

                                    long lngFsPosition = fs.Position;
                                    double dblSlaveContactMagnitude_Factor = (double)formatter.Deserialize(fs);                  // SlavecontactMagnitude_Factor

                                    cData.SlaveContactMagnitude_Factor = dblSlaveContactMagnitude_Factor;
                                    debug("after SCMag_Factor " + cData.SlaveContactMagnitude_Factor.ToString());

                                    debug("before LimbDrawList_Name");
                                    cData.ImageList_Name = (string)formatter.Deserialize(fs);
                                    debug("after LimbImageDrawList_Name " + cData.ImageList_Name);
                                }
                            }
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                            debug("End animation : " + cAnimation.Name);
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        }
                        catch (Exception err)
                        {
                            debug("err: " + err);
                            strDebugFilename = "rtf_Load";
                            eDebugOutput = enuDebugOutput.none;
                            debugSave();
                        }
                        object objAnimation = (object)cAnimation;
                        cRetVal.cBT_Animations.Insert(ref objAnimation, cAnimation.Name);
                    }
                    eDebugOutput = enuDebugOutput.none;
                    intDebugIndent = 0;
                    debug("end of load_g3");
                }
                catch (Exception e)
                {
                    if (classSprite.ShowErrorMessages)
                        MessageBox.Show("Error loading file(" + filename + "):" + e.Message, "Error");
                }

                if (fs != null) fs.Close();
                if (cRetVal != null)
                    cRetVal.AlphabetizeAnimations();

                debugSave();
                return cRetVal;
            }
            else
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("file \"" + filename + "\" not found.");
                return null;
            }
        }

        /// <summary>
        /// loads sprite sequentially from the harddrive
        /// </summary>
        /// <param name="filename">name of file to be loaded</param>
        /// <returns>the sprite requested</returns>
        public classSprite Load_SP4(string filename)
        {
            debugClear();
            eDebugOutput = enuDebugOutput.none;
            classSprite cRetVal = null;
            if (System.IO.File.Exists(filename))
            {
                try
                {
                    fs = new FileStream(filename, FileMode.Open);
                    fs.Position = 0;
                    intDebugIndent = 0;
                    debug("startLoad_G3");
                    string strSpriteName = ((string)formatter.Deserialize(fs)).Trim();
                    debug("before spriteName " + strSpriteName.ToString());
                    cRetVal = new classSprite(strSpriteName);
                    cRetVal.textSpriteInfo = TextSpriteInfo_Load(filename);

                    cRetVal.Animation_Delete(classSprite.conDefaultAnimationName);

                    cRetVal.NumImagesPerQuadrant = (int)formatter.Deserialize(fs);
                    debug("after intNUmImages " + cRetVal.NumImagesPerQuadrant.ToString());

                    cRetVal.UseRamCache = (bool)formatter.Deserialize(fs);
                    debug("after bool Use RAM Cache");

                    int intNumberLimbs = (int)formatter.Deserialize(fs);
                    debug("after intNumberLimibs " + intNumberLimbs.ToString());

                    debug("forEach Limb");
                    for (int intLimbCounter = 0; intLimbCounter < intNumberLimbs; intLimbCounter++)
                    {
                        intDebugIndent = 1;

                        classLoadLimbsInfo cCostume_LoadingInfo = new classLoadLimbsInfo();

                        cCostume_LoadingInfo.LimbName = (string)formatter.Deserialize(fs);
                        debug("after limbName " + cCostume_LoadingInfo.LimbName);

                        cCostume_LoadingInfo.MasterLimbName = ((string)formatter.Deserialize(fs)).Trim();
                        if (cCostume_LoadingInfo.MasterLimbName.Contains(classSprite.conMasterLimb_Name))
                        {
                            int intIndexMasterLimb = cCostume_LoadingInfo.MasterLimbName.IndexOf(classSprite.conMasterLimb_Name);
                            if (intIndexMasterLimb > 0)
                                cCostume_LoadingInfo.MasterLimbName = cCostume_LoadingInfo.MasterLimbName.Substring(intIndexMasterLimb);
                        }
                        debug("after MasterLimbName " + cCostume_LoadingInfo.MasterLimbName);

                        double dblMasterRad = (double)formatter.Deserialize(fs);
                        debug("after MasterRad " + dblMasterRad.ToString());

                        double dblMasterMag = (double)formatter.Deserialize(fs);
                        debug("after MasterMag " + dblMasterRad.ToString());

                        cCostume_LoadingInfo.cRad_ContactMaster = new classRadialCoordinate(dblMasterRad, dblMasterMag);

                        double dblSlaveRad = (double)formatter.Deserialize(fs);
                        debug("after SlaveRad " + dblSlaveRad.ToString());

                        double dblSlaveMag = (double)formatter.Deserialize(fs);
                        debug("after SlaveMag " + dblSlaveMag.ToString());

                        cCostume_LoadingInfo.cRad_ContactSlave = new classRadialCoordinate(dblSlaveRad, dblSlaveMag);

                        int intNumberLimbImageLists = (int)formatter.Deserialize(fs);
                        debug("after number of lists:" + intNumberLimbImageLists.ToString());

                        classSprite_Limb cLimbNew = null;
                        if (cCostume_LoadingInfo.LimbName.IndexOf("MasterLimb") < 0)
                        {
                            cLimbNew = classSprite_Limb.New(cCostume_LoadingInfo.LimbName, ref cRetVal, null);
                            cLimbNew.lstImages.Clear();
                        }

                        for (int intImageListCounter = 0; intImageListCounter < intNumberLimbImageLists; intImageListCounter++)
                        {
                            classSprite_Limb.classSprite_Limb_Images cImages = new classSprite_Limb.classSprite_Limb_Images();
                            cImages.Name = (string)formatter.Deserialize(fs);
                            if (cLimbNew != null && cLimbNew.lstImages != null)
                            {
                                cLimbNew.lstImages.Add(cImages);

                                object objLimbImages = (object)cImages;
                                cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                            }
                            debug("after Image list name:" + cImages.Name);

                            debug("forEach Bitmap");
                            for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                            {
                                intDebugIndent = 2;
                                Bitmap bmp = (Bitmap)formatter.Deserialize(fs);
                                debug("after Bmp ");
                                cCostume_LoadingInfo.lstBmp.Add(bmp);
                            }

                            if (cLimbNew != null)
                            {
                                cLimbNew.lstImages[intImageListCounter].bmpImages = new Bitmap[4 * cRetVal.NumImagesPerQuadrant];
                                for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                                    cLimbNew.lstImages[intImageListCounter].bmpImages[intImageCounter] = cCostume_LoadingInfo.lstBmp[intImageCounter];
                                cCostume_LoadingInfo.lstBmp.Clear();
                            }

                            if (intImageListCounter == 0)
                                if (cCostume_LoadingInfo.LimbName.IndexOf(classSprite.conMasterLimb_Name) < 0)
                                { // this is NOT the master limb -> build data trees for this limb/hinge
                                    classSprite_Limb cLimb_Master = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(cCostume_LoadingInfo.MasterLimbName);

                                    cLimbNew.Hinge = new classSprite_Hinge(ref cRetVal, ref cLimbNew, ref cLimb_Master);
                                    cLimb_Master.Slave_Add(ref cLimbNew);
                                    cLimbNew.Hinge.Contact.Master = cCostume_LoadingInfo.cRad_ContactMaster;
                                    cLimbNew.Hinge.Contact.Slave = cCostume_LoadingInfo.cRad_ContactSlave;
                                }
                        }
                    }

                    intDebugIndent = 0;
                    eDebugOutput = enuDebugOutput.none;
                    // load animations
                    int intNumberAnimations = (int)formatter.Deserialize(fs);
                    debug("after numAnimations " + intNumberAnimations.ToString());

                    debug("forEAch Animation");
                    cRetVal.cBT_Animations = new BinTree.classBinTree();
                    for (int intAnimationCounter = 0; intAnimationCounter < intNumberAnimations; intAnimationCounter++)
                    {
                        intDebugIndent = 1;
                        classAnimation cAnimation = new classAnimation(ref cRetVal);
                        debug("-------------------------start animation [" + intAnimationCounter.ToString() + "]" + cAnimation.Name + "--------------------");
                        cRetVal.lstAnimations.Add(cAnimation);

                        cAnimation.Name = ((string)formatter.Deserialize(fs)).Trim();
                        debug("after animation Name " + cAnimation.Name);

                        intDebugIndent = 1;
                        try
                        {
                            int intNumFrames = (int)formatter.Deserialize(fs);
                            debug("after numFrames " + intNumFrames.ToString());

                            debug("forEach Frame");
                            for (int intFrameCounter = 0; intFrameCounter < intNumFrames; intFrameCounter++)
                            {
                                debug("--------------------------------Framecounter:(" + intFrameCounter.ToString() + ")-----------------------------");
                                intDebugIndent = 2;
                                classAnimation_Frame cFrame = new classAnimation_Frame(ref cRetVal);
                                cAnimation.lstFrames.Add(cFrame);
                                cFrame.Animation = cAnimation;

                                cFrame.Vertical_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Vertical mirror:" + cFrame.Vertical_Mirror.ToString());

                                cFrame.Horizontal_Mirror = (bool)formatter.Deserialize(fs);
                                debug("after Horizontal mirror:" + cFrame.Horizontal_Mirror.ToString());

                                string strLimb_DrawRelativeTo = (string)formatter.Deserialize(fs);
                                cFrame.Limb_DrawRelativeTo = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf((classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strLimb_DrawRelativeTo));
                                debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                                int intNumLimbsToDraw = 0;

                                int intNumInDrawSequence = (int)formatter.Deserialize(fs);
                                debug("after NumInDrawSequence " + intNumInDrawSequence.ToString());

                                debug("forEAch LimbInDrawSequence");
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 2;
                                    string strDrawSequence_LimbName = ((string)formatter.Deserialize(fs)).Trim();
                                    debug("after DrawSequence LimbName " + strDrawSequence_LimbName);
                                    debug("-----------------------------Limb[" + intLimbCounter.ToString() + "]" + strDrawSequence_LimbName + "-------------------");
                                    classSprite_Limb cDrawSequenceLimb = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strDrawSequence_LimbName);
                                    int intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cDrawSequenceLimb);
                                    cFrame.lstDrawSequence.Add(intLimbIndex);
                                    if (cDrawSequenceLimb == null)
                                        intNumLimbsToDraw = cFrame.lstDrawSequence.Count;
                                }

                                debug("----------------------------------forEach LimbToDraw");
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                //eDebugOutput = enuDebugOutput.none;
                                //////////////////////////////////////////////////////////////////////////////////////////////////////////
                                for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                                {
                                    intDebugIndent = 3;
                                    classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrame);
                                    cFrame.lstData.Add(cData);

                                    string strName = ((string)formatter.Deserialize(fs)).Trim();                                // Name

                                    debug("-------------------LImbCounter(" + intLimbCounter.ToString() + ")" + strName + "--------------------");
                                    classSprite_Limb cLimbSearch = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strName);
                                    cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cLimbSearch);
                                    if (cData.intLimbIndex < 0)
                                    {
                                        cData.intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cRetVal.cCostumeInfo_Default.cLimb_Master);
                                        debug("after Limbname : Null");
                                    }
                                    else debug("after LimbName " + cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                                    cData.Angle = (double)formatter.Deserialize(fs);                                            // Angle
                                    debug("after Angle " + cData.Angle.ToString());

                                    long lngFsPosition = fs.Position;
                                    double dblSlaveContactMagnitude_Factor = (double)formatter.Deserialize(fs);                  // SlavecontactMagnitude_Factor

                                    cData.SlaveContactMagnitude_Factor = dblSlaveContactMagnitude_Factor;
                                    debug("after SCMag_Factor " + cData.SlaveContactMagnitude_Factor.ToString());

                                    debug("before LimbDrawList_Name");
                                    cData.ImageList_Name = (string)formatter.Deserialize(fs);
                                    debug("after LimbImageDrawList_Name " + cData.ImageList_Name);
                                }
                            }
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                            debug("End animation : " + cAnimation.Name);
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        }
                        catch (Exception err)
                        {
                            debug("err: " + err);
                            strDebugFilename = "rtf_Load";
                            eDebugOutput = enuDebugOutput.none;
                            debugSave();
                        }
                        object objAnimation = (object)cAnimation;
                        cRetVal.cBT_Animations.Insert(ref objAnimation, cAnimation.Name);
                    }
                    eDebugOutput = enuDebugOutput.none;
                    intDebugIndent = 0;
                    debug("end of load_g3");
                }
                catch (Exception e)
                {
                    if (classSprite.ShowErrorMessages)
                        MessageBox.Show("Error loading file(" + filename + "):" + e.Message, "Error");
                }

                if (fs != null) fs.Close();
                if (cRetVal != null)
                    cRetVal.AlphabetizeAnimations();

                debugSave();
                return cRetVal;
            }
            else
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("file \"" + filename + "\" not found.");
                return null;
            }
        }

        public classSprite Load_SP3(byte[] memorystream)
        {
            debugClear();
            eDebugOutput = enuDebugOutput.none;
            classSprite cRetVal = null;
            MemoryStream ms = new MemoryStream(memorystream);
            try
            {
                ms.Position = 0;
                intDebugIndent = 0;
                debug("startLoad_G3");
                string strSpriteName = ((string)formatter.Deserialize(ms)).Trim();
                debug("after spriteName " + strSpriteName.ToString());
                cRetVal = new classSprite(strSpriteName);
                cRetVal.Animation_Delete(classSprite.conDefaultAnimationName);

                cRetVal.NumImagesPerQuadrant = (int)formatter.Deserialize(ms);
                debug("after intNUmImages " + cRetVal.NumImagesPerQuadrant.ToString());

                cRetVal.UseRamCache = (bool)formatter.Deserialize(ms);
                debug("after bool Use RAM Cache");

                int intNumberLimbs = (int)formatter.Deserialize(ms);
                debug("after intNumberLimibs " + intNumberLimbs.ToString());

                debug("forEach Limb");
                for (int intLimbCounter = 0; intLimbCounter < intNumberLimbs; intLimbCounter++)
                {
                    intDebugIndent = 1;
                    classLoadLimbsInfo cCostume_LoadingInfo = new classLoadLimbsInfo();

                    cCostume_LoadingInfo.LimbName = (string)formatter.Deserialize(ms);
                    debug("after limbName " + cCostume_LoadingInfo.LimbName);

                    cCostume_LoadingInfo.MasterLimbName = ((string)formatter.Deserialize(ms)).Trim();
                    if (cCostume_LoadingInfo.MasterLimbName.Contains(classSprite.conMasterLimb_Name))
                    {
                        int intIndexMasterLimb = cCostume_LoadingInfo.MasterLimbName.IndexOf(classSprite.conMasterLimb_Name);
                        if (intIndexMasterLimb > 0)
                            cCostume_LoadingInfo.MasterLimbName = cCostume_LoadingInfo.MasterLimbName.Substring(intIndexMasterLimb);
                    }
                    debug("after MasterLimbName " + cCostume_LoadingInfo.MasterLimbName);

                    double dblMasterRad = (double)formatter.Deserialize(ms);
                    debug("after MasterRad " + dblMasterRad.ToString());

                    double dblMasterMag = (double)formatter.Deserialize(ms);
                    debug("after MasterMag " + dblMasterRad.ToString());

                    cCostume_LoadingInfo.cRad_ContactMaster = new classRadialCoordinate(dblMasterRad, dblMasterMag);

                    double dblSlaveRad = (double)formatter.Deserialize(ms);
                    debug("after SlaveRad " + dblSlaveRad.ToString());

                    debug("before SlaveMag");
                    double dblSlaveMag = (double)formatter.Deserialize(ms);
                    debug("after SlaveMag " + dblSlaveMag.ToString());

                    cCostume_LoadingInfo.cRad_ContactSlave = new classRadialCoordinate(dblSlaveRad, dblSlaveMag);

                    int intNumberLimbImageLists = (int)formatter.Deserialize(ms);
                    debug("after number of lists:" + intNumberLimbImageLists.ToString());

                    classSprite_Limb cLimbNew = null;
                    if (cCostume_LoadingInfo.LimbName.IndexOf("MasterLimb") < 0)
                    {
                        cLimbNew = classSprite_Limb.New(cCostume_LoadingInfo.LimbName, ref cRetVal, null);
                        cLimbNew.lstImages.Clear();
                    }

                    for (int intImageListCounter = 0; intImageListCounter < intNumberLimbImageLists; intImageListCounter++)
                    {
                        classSprite_Limb.classSprite_Limb_Images cImages = new classSprite_Limb.classSprite_Limb_Images();
                        cImages.Name = (string)formatter.Deserialize(ms);
                        if (cLimbNew != null && cLimbNew.lstImages != null)
                        {
                            cLimbNew.lstImages.Add(cImages);

                            object objLimbImages = (object)cImages;
                            cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                        }
                        debug("after Image list name:" + cImages.Name);

                        debug("forEach Bitmap");
                        for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                        {
                            intDebugIndent = 2;
                            debug("before BMP");
                            Bitmap bmp = (Bitmap)formatter.Deserialize(ms);
                            debug("after Bmp ");
                            cCostume_LoadingInfo.lstBmp.Add(bmp);
                        }

                        if (cLimbNew != null)
                        {
                            cLimbNew.lstImages[intImageListCounter].bmpImages = new Bitmap[4 * cRetVal.NumImagesPerQuadrant];
                            for (int intImageCounter = 0; intImageCounter < cRetVal.NumImagesPerQuadrant; intImageCounter++)
                                cLimbNew.lstImages[intImageListCounter].bmpImages[intImageCounter] = cCostume_LoadingInfo.lstBmp[intImageCounter];
                            cCostume_LoadingInfo.lstBmp.Clear();
                        }

                        if (intImageListCounter == 0)
                            if (cCostume_LoadingInfo.LimbName.IndexOf(classSprite.conMasterLimb_Name) < 0)
                            { // this is NOT the master limb -> build data trees for this limb/hinge
                                classSprite_Limb cLimb_Master = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(cCostume_LoadingInfo.MasterLimbName);

                                cLimbNew.Hinge = new classSprite_Hinge(ref cRetVal, ref cLimbNew, ref cLimb_Master);
                                cLimb_Master.Slave_Add(ref cLimbNew);
                                cLimbNew.Hinge.Contact.Master = cCostume_LoadingInfo.cRad_ContactMaster;
                                cLimbNew.Hinge.Contact.Slave = cCostume_LoadingInfo.cRad_ContactSlave;
                            }
                    }
                }

                intDebugIndent = 0;
                eDebugOutput = enuDebugOutput.none;
                // load animations
                int intNumberAnimations = (int)formatter.Deserialize(ms);
                debug("after numAnimations " + intNumberAnimations.ToString());

                debug("forEAch Animation");
                cRetVal.cBT_Animations = new BinTree.classBinTree();
                for (int intAnimationCounter = 0; intAnimationCounter < intNumberAnimations; intAnimationCounter++)
                {
                    intDebugIndent = 1;
                    classAnimation cAnimation = new classAnimation(ref cRetVal);
                    debug("-------------------------start animation [" + intAnimationCounter.ToString() + "]" + cAnimation.Name + "--------------------");
                    cRetVal.lstAnimations.Add(cAnimation);

                    cAnimation.Name = ((string)formatter.Deserialize(ms)).Trim();
                    debug("after animation Name " + cAnimation.Name);

                    intDebugIndent = 1;
                    try
                    {
                        int intNumFrames = (int)formatter.Deserialize(ms);
                        debug("after numFrames " + intNumFrames.ToString());
                        debug("forEach Frame");
                        for (int intFrameCounter = 0; intFrameCounter < intNumFrames; intFrameCounter++)
                        {
                            debug("--------------------------------Framecounter:(" + intFrameCounter.ToString() + ")-----------------------------");
                            intDebugIndent = 2;
                            classAnimation_Frame cFrame = new classAnimation_Frame(ref cRetVal);
                            cAnimation.lstFrames.Add(cFrame);
                            cFrame.Animation = cAnimation;
                            cFrame.ptTL.X = (int)formatter.Deserialize(ms);
                            debug("after FramePtTL.x " + cFrame.ptTL.X.ToString());

                            cFrame.ptTL.Y = (int)formatter.Deserialize(ms);
                            debug("after FramePtTL.y " + cFrame.ptTL.Y.ToString());

                            cFrame.Vertical_Mirror = (bool)formatter.Deserialize(ms);
                            debug("after Vertical mirror:" + cFrame.Vertical_Mirror.ToString());

                            cFrame.Horizontal_Mirror = (bool)formatter.Deserialize(ms);
                            debug("after Horizontal mirror:" + cFrame.Horizontal_Mirror.ToString());

                            string strLimb_DrawRelativeTo = (string)formatter.Deserialize(ms);
                            cFrame.Limb_DrawRelativeTo = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf((classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strLimb_DrawRelativeTo));
                            debug("after Limb_DrawRelativeTo " + cFrame.ptTL.Y.ToString());

                            int intNumLimbsToDraw = 0;

                            int intNumInDrawSequence = (int)formatter.Deserialize(ms);
                            debug("after NumInDrawSequence " + intNumInDrawSequence.ToString());

                            debug("forEAch LimbInDrawSequence");
                            for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                            {
                                intDebugIndent = 2;
                                string strDrawSequence_LimbName = ((string)formatter.Deserialize(ms)).Trim();
                                debug("after DrawSequence LimbName " + strDrawSequence_LimbName);
                                debug("-----------------------------Limb[" + intLimbCounter.ToString() + "]" + strDrawSequence_LimbName + "-------------------");
                                classSprite_Limb cDrawSequenceLimb = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strDrawSequence_LimbName);
                                int intLimbIndex = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cDrawSequenceLimb);
                                cFrame.lstDrawSequence.Add(intLimbIndex);
                                if (cDrawSequenceLimb == null)
                                    intNumLimbsToDraw = cFrame.lstDrawSequence.Count;
                            }

                            debug("----------------------------------forEach LimbToDraw");
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                            //eDebugOutput = enuDebugOutput.none;
                            //////////////////////////////////////////////////////////////////////////////////////////////////////////
                            for (int intLimbCounter = 0; intLimbCounter < intNumInDrawSequence; intLimbCounter++)
                            {
                                intDebugIndent = 3;
                                classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrame);
                                cFrame.lstData.Add(cData);

                                string strName = ((string)formatter.Deserialize(ms)).Trim();                                // Name
                                debug("after LimbName" + strName);

                                debug("-------------------LImbCounter(" + intLimbCounter.ToString() + ")" + strName + "--------------------");
                                classSprite_Limb cLimbSearch = (classSprite_Limb)cRetVal.cCostumeInfo_Default.cBT_Limbs.Search(strName);
                                cData.intLimbIndex
                                    = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cLimbSearch);
                                if (cData.intLimbIndex < 0)
                                {
                                    cData.intLimbIndex
                                        = cRetVal.cCostumeInfo_Default.lstLimbs.IndexOf(cRetVal.cCostumeInfo_Default.cLimb_Master);
                                    debug("after Limbname : Null");
                                }
                                else debug("after LimbName " + cRetVal.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Name);

                                cData.Angle
                                    = (double)formatter.Deserialize(ms);                                            // Angle
                                debug("after Angle " + cData.Angle.ToString());

                                long lngmsPosition = ms.Position;
                                double dblSlaveContactMagnitude_Factor = (double)formatter.Deserialize(ms);                  // SlavecontactMagnitude_Factor

                                cData.SlaveContactMagnitude_Factor = dblSlaveContactMagnitude_Factor;
                                debug("after SCMag_Factor " + cData.SlaveContactMagnitude_Factor.ToString());

                                int intX = (int)formatter.Deserialize(ms);                                      // DrawTL.x
                                debug("after ptDrawCenter.x " + cData.ptDrawCenter.X.ToString());

                                int intY = (int)formatter.Deserialize(ms);                                    // DrawTL.y
                                debug("after ptDrawCenter.y " + cData.ptDrawCenter.Y.ToString());

                                cData.ptDrawCenter = new Point(intX, intY);
                                cData.ImageList_Name
                                    = (string)formatter.Deserialize(ms);
                                debug("after LimbImageDrawList_Name " + cData.ImageList_Name);
                            }
                        }
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                        debug("End animation : " + cAnimation.Name);
                        //////////////////////////////////////////////////////////////////////////////////////////////////////////
                    }
                    catch (Exception err)
                    {
                        debug("err: " + err);
                        strDebugFilename = "rtf_Load";
                        eDebugOutput = enuDebugOutput.none;
                        debugSave();
                    }
                    object objAnimation = (object)cAnimation;
                    cRetVal.cBT_Animations.Insert(ref objAnimation, cAnimation.Name);
                }
                eDebugOutput = enuDebugOutput.none;
                intDebugIndent = 0;
                debug("end of load_g3");
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Print("SpriteMaker.Load(byte[] memoryStream) Error:" + e.Message);
            }

            if (ms != null) ms.Close();
            if (cRetVal != null)
                cRetVal.AlphabetizeAnimations();

            debugSave();
            return cRetVal;
        }

        public classSprite_CostumeInfo Load_CostumeInfo(ref classSprite cSprite, string filename)
        {
            debugClear();
            eDebugOutput = enuDebugOutput.none;
            classSprite_CostumeInfo cRetVal = null;

            classSprite_CostumeInfo cLoad_LimbInfo_Source = cSprite.cCostumeInfo_Default;

            if (System.IO.File.Exists(filename))
            {
                try
                {
                    fs = new FileStream(filename, FileMode.Open);
                    fs.Position = 0;
                    intDebugIndent = 0;
                    debug("startLoad_G3");
                    string strCostumeInfo_SpriteName = ((string)formatter.Deserialize(fs)).Trim();
                    debug("after spriteName " + strCostumeInfo_SpriteName.ToString());
                    if (string.Compare(strCostumeInfo_SpriteName.ToUpper(), cSprite.Name.ToUpper()) != 0)
                    {
                        MessageBox.Show("sprite name and CostumeInfo-SpriteName do not match");
                        return null;
                    }

                    debug("startLoad_G3");
                    string strCostumeInfo_Name = ((string)formatter.Deserialize(fs)).Trim();
                    debug("before spriteName " + strCostumeInfo_Name.ToString());

                    cRetVal = new classSprite_CostumeInfo(cSprite.Name);
                    cRetVal.Name = strCostumeInfo_Name;

                    int intNumLimbs = cSprite.cCostumeInfo_Default.lstLimbs.Count;

                    cRetVal.lstLimbs.AddRange(cSprite.cCostumeInfo_Default.lstLimbs);

                    debug("forEach Limb");
                    for (int intLimbCounter = 0; fs.Position < fs.Length; intLimbCounter++)
                    {
                        intDebugIndent = 1;

                        classLoadLimbsInfo cLoad_LimbInfo = new classLoadLimbsInfo();
                        cLoad_LimbInfo.LimbName = (string)formatter.Deserialize(fs);
                        debug("after limbName " + cLoad_LimbInfo.LimbName);

                        cLoad_LimbInfo.MasterLimbName = ((string)formatter.Deserialize(fs)).Trim();
                        debug("after MasterLimbName " + cLoad_LimbInfo.MasterLimbName);

                        double dblMasterRad = (double)formatter.Deserialize(fs);
                        debug("after MasterRad " + dblMasterRad.ToString());

                        double dblMasterMag = (double)formatter.Deserialize(fs);
                        debug("after MasterMag " + dblMasterRad.ToString());

                        cLoad_LimbInfo.cRad_ContactMaster = new classRadialCoordinate(dblMasterRad, dblMasterMag);

                        double dblSlaveRad = (double)formatter.Deserialize(fs);
                        debug("after SlaveRad " + dblSlaveRad.ToString());

                        double dblSlaveMag = (double)formatter.Deserialize(fs);
                        debug("after SlaveMag " + dblSlaveMag.ToString());

                        cLoad_LimbInfo.cRad_ContactSlave = new classRadialCoordinate(dblSlaveRad, dblSlaveMag);

                        int intNumberLimbImageLists = (int)formatter.Deserialize(fs);
                        debug("after number of lists:" + intNumberLimbImageLists.ToString());

                        classSprite_Limb cLimbNew = null;
                        cLimbNew = new classSprite_Limb();
                        cLimbNew.cSprite = cSprite;

                        cLimbNew.cCostumeInfo = cRetVal;
                        cLimbNew.cLoadInfo = cLoad_LimbInfo;

                        cLimbNew.Name = cLoad_LimbInfo.LimbName;

                        if (cLoad_LimbInfo.LimbName.IndexOf("MasterLimb") > 0)
                            cRetVal.cLimb_Master = cLimbNew;

                        classSprite_Limb cLimb_Original = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cLimbNew.Name);

                        // create list of appropriate size to match the default list of images for this limb
                        classSprite_Limb.classSprite_Limb_Images[] cLimbImageCount = new classSprite_Limb.classSprite_Limb_Images[cLimb_Original != null
                                                                                                                                                  ? cLimb_Original.lstImages.Count
                                                                                                                                                  : intNumberLimbImageLists];
                        cLimbNew.lstImages.AddRange(cLimbImageCount.ToList<classSprite_Limb.classSprite_Limb_Images>());

                        bool bolImageListLoop = true;
                        for (int intImageListCounter = 0; bolImageListLoop && intImageListCounter < intNumberLimbImageLists; intImageListCounter++)
                        {
                            classSprite_Limb.classSprite_Limb_Images cImages = new classSprite_Limb.classSprite_Limb_Images();
                            debug("before Image List Name:");
                            try
                            {
                                cImages.Name = (string)formatter.Deserialize(fs);
                            }
                            catch (Exception)
                            {
                                bolImageListLoop = false;
                            }
                            classSprite_Limb.classSprite_Limb_Images cLimbImage_Original = null;

                            if (cLimb_Original != null && cImages.Name.Length > 0)
                                cLimbImage_Original = (classSprite_Limb.classSprite_Limb_Images)cLimb_Original.cBT_LimbImages.Search(cImages.Name);
                            int intImageIndex = 0;
                            if (cLimb_Original != null)
                            {

                                if (cLimbNew != null && cLimbNew.lstImages != null)
                                {
                                    if (cLimbImage_Original != null)
                                    {
                                        //cLimbNew.lstImages.Add(cImages);
                                        intImageIndex = cLimb_Original.lstImages.IndexOf(cLimbImage_Original);
                                        if (intImageIndex >= 0 && intImageIndex < cLimbNew.lstImages.Count)
                                        {
                                            cLimbNew.lstImages[intImageIndex] = cImages;

                                            object objLimbImages = (object)cImages;
                                            cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                                        }
                                    }
                                    else
                                    {
                                        cLimbNew.lstImages[0] = cImages;
                                        object objLimbImages = (object)cImages;
                                        cLimbNew.cBT_LimbImages.Insert(ref objLimbImages, cImages.Name);
                                    }
                                }
                                debug("after Image list name:" + cImages.Name);
                            }

                            for (int intImageCounter = 0; intImageCounter < cSprite.NumImagesPerQuadrant; intImageCounter++)
                            {
                                intDebugIndent = 2;
                                Bitmap bmp = (Bitmap)formatter.Deserialize(fs);
                                debug("after Bmp ");
                                cLoad_LimbInfo.lstBmp.Add(bmp);
                            }

                            if (cLimb_Original != null)
                            {
                                if (cLimbNew != null)
                                {
                                    cLimbNew.lstImages[intImageIndex].bmpImages = new Bitmap[4 * cSprite.NumImagesPerQuadrant];
                                    for (int intImageCounter = 0; intImageCounter < cSprite.NumImagesPerQuadrant; intImageCounter++)
                                        cLimbNew.lstImages[intImageIndex].bmpImages[intImageCounter] = cLoad_LimbInfo.lstBmp[intImageCounter];
                                    cLoad_LimbInfo.lstBmp.Clear();
                                }


                                // test to see if each limb-image is accounted for
                                for (int intLimbImageCounter = 0; intLimbImageCounter < cLimb_Original.lstImages.Count; intLimbImageCounter++)
                                {
                                    if (cLimbNew.lstImages[intLimbImageCounter] == null)
                                    { // this limb-image is missing needs to reference the original default image
                                        classSprite_Limb.classSprite_Limb_Images cLimbImage_original = cLimb_Original.lstImages[intLimbImageCounter];
                                        cLimbNew.lstImages[intLimbImageCounter] = cLimbImage_original;
                                    }
                                }

                                int intLimbIndex = cSprite.cCostumeInfo_Default.lstLimbs.IndexOf(cLimb_Original);

                                object objThis = (object)cLimbNew;
                                if (cSprite != null)
                                {
                                    cRetVal.cBT_Limbs.Insert(ref objThis, cLoad_LimbInfo.LimbName);
                                    cRetVal.lstLimbs[intLimbIndex] = cLimbNew;
                                }
                            }
                        }
                    }

                    // count all the CostumeInfo's limbs to match default CostumeInfo Limb count
                    {
                        List<object> lstcBT_Original_Traversal = cSprite.cCostumeInfo_Default.cBT_Limbs.Traverse();
                        for (int intLimbCounter = 0; intLimbCounter < lstcBT_Original_Traversal.Count; intLimbCounter++)
                        {
                            classSprite_Limb cLimbOriginal = (classSprite_Limb)lstcBT_Original_Traversal[intLimbCounter];

                            classSprite_Limb cLimbNew = (classSprite_Limb)cRetVal.cBT_Limbs.Search(cLimbOriginal.Name);
                            if (cLimbNew == null)
                            {  // this limb is missing from the new list
                                int intLimbIndex = cSprite.cCostumeInfo_Default.lstLimbs.IndexOf(cLimbOriginal);
                                if (intLimbIndex >= 0 && intLimbIndex < cSprite.cCostumeInfo_Default.lstLimbs.Count)
                                {
                                    classSprite_Limb cLimb_Copy = cLimbOriginal.Copy();
                                    cLimb_Copy.cCostumeInfo = cRetVal;

                                    cRetVal.lstLimbs[intLimbIndex] = cLimb_Copy;
                                    object objLimbCopy = (object)cLimb_Copy;
                                    cRetVal.cBT_Limbs.Insert(ref objLimbCopy, cLimb_Copy.Name);
                                }
                            }
                        }
                        // make certain all costume limbs are attached in same way the Default limbs are attached
                        for (int intLimbCounter = 0; intLimbCounter < lstcBT_Original_Traversal.Count; intLimbCounter++)
                        {
                            classSprite_Limb cLimbOriginal = (classSprite_Limb)lstcBT_Original_Traversal[intLimbCounter];

                            classSprite_Limb cLimbNew = (classSprite_Limb)cRetVal.cBT_Limbs.Search(cLimbOriginal.Name);

                            // this limb's hinge connections must match Sprite's Default Costume limb connections
                            classSprite_Limb cLimb_DefaultCostume = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cLimbOriginal.Name);
                            if (cLimb_DefaultCostume.Hinge != null)
                            {// this is NOT the master limb -> build data trees for this limb/hinge
                                classSprite_Limb cLimb_Master_DefaultCostume = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cLimb_DefaultCostume.Hinge.Limb_Master.Name);
                                classSprite_Limb cLimb_Master = (classSprite_Limb)cRetVal.cBT_Limbs.Search(cLimb_Master_DefaultCostume.Name);

                                cLimbNew.Hinge = new classSprite_Hinge(ref cSprite, ref cLimbNew, ref cLimb_Master);
                                cLimb_Master.Slave_Add(ref cLimbNew);
                                cLimbNew.Hinge.Contact.Master = cLimbNew.cLoadInfo != null
                                                                                    ? cLimbNew.cLoadInfo.cRad_ContactMaster
                                                                                    : cLimbOriginal.Hinge.Contact.Master.Copy();
                                cLimbNew.Hinge.Contact.Slave = cLimbNew.cLoadInfo != null
                                                                                   ? cLimbNew.cLoadInfo.cRad_ContactSlave
                                                                                   : cLimbOriginal.Hinge.Contact.Slave.Copy();
                            }
                        }
                    }

                    intDebugIndent = 0;
                    eDebugOutput = enuDebugOutput.none;
                    intDebugIndent = 0;
                    debug("end of load_g3");
                }
                catch (Exception e)
                {
                    if (fs != null)
                        fs.Close();
                    if (classSprite.ShowErrorMessages)
                        MessageBox.Show("Error loading file(" + filename + "):" + e.Message, "Error");
                }

                if (fs != null) fs.Close();

                debugSave();

                cSprite.lstCostumeInfo.Add(cRetVal);

                return cRetVal;
            }
            else
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("file \"" + filename + "\" not found.");
                return null;
            }
        }

        #endregion
    }

    /// <summary>
    /// developper information to control the sprites in an application
    /// </summary>
    public class classSpriteData
    {
        /// <summary>
        ///data used by classSprite.Draw_Animation_Frame() consisting of animation, frame and details to be drawn 
        /// </summary>
        public classAnimationData cAnimationData = new classAnimationData();

        classSprite_CostumeInfo _cCostumeInfo = null;
        public classSprite_CostumeInfo cCostumeInfo
        {
            get
            {
                if (_cCostumeInfo == null)
                    return cAnimationData.cSprite.cCostumeInfo_Default;
                else
                    return _cCostumeInfo;
            }
            set
            {
                _cCostumeInfo = value;
            }
        }

        public List<classLimbInfo> lstLimbData = new List<classLimbInfo>();
        List<Bitmap> _lstImages = new List<Bitmap>();
        public List<Bitmap> lstImages
        {
            get { return _lstImages; }
            set
            {
                _lstImages = value;
            }
        }

        Bitmap _bmpImage = null;
        public Bitmap bmpImage
        {
            get { return _bmpImage; }
            set
            {

                _bmpImage = value;
            }
        }

        public List<Bitmap> Draw()
        {
            List<classSprite_Limb> lstLimbSources = new List<classSprite_Limb>();
            lstLimbSources.Add(cAnimationData.cSprite.cCostumeInfo_Default.cLimb_Master);
            return Draw(lstLimbSources);
        }

        public List<Bitmap> Draw(List<classSprite_Limb> lstLimbSources)
        {
            classSpriteData cMyRef = this;
            cAnimationData.intFrameIndex = (cAnimationData.intFrameIndex + cAnimationData.cAnimation.lstFrames.Count) % cAnimationData.cAnimation.lstFrames.Count;

            classAnimation_Frame cFrame = cAnimationData.cAnimation.lstFrames[cAnimationData.intFrameIndex];
            bool bolMirrorH = cFrame.Horizontal_Mirror;
            bool bolMirrorV = cFrame.Vertical_Mirror;
            switch (cAnimationData.eMirror)
            {
                case classAnimation_Frame.enuFrameMirror.Both:
                    cFrame.Horizontal_Mirror = true;
                    cFrame.Vertical_Mirror = true;
                    break;

                case classAnimation_Frame.enuFrameMirror.Horizontal:
                    cFrame.Horizontal_Mirror = true;
                    cFrame.Vertical_Mirror = false;
                    break;

                case classAnimation_Frame.enuFrameMirror.Vertical:
                    cFrame.Horizontal_Mirror = false;
                    cFrame.Vertical_Mirror = true;
                    break;

                case classAnimation_Frame.enuFrameMirror.none:
                    cFrame.Horizontal_Mirror = false;
                    cFrame.Vertical_Mirror = false;
                    break;

                case classAnimation_Frame.enuFrameMirror.ignore:
                    break;
            }
            lstImages = cAnimationData.cSprite.draw_Animation_Frame(ref cMyRef, lstLimbSources);
            bmpImage = lstImages.Count > 0
                                       ? lstImages[0]
                                       : null;

            List<classAnimation_Frame_LimbData> lstData_Source = cFrame.lstData;
            while (lstLimbData.Count > lstData_Source.Count)
                lstLimbData.RemoveAt(0);
            while (lstLimbData.Count < lstData_Source.Count)
            {
                classSprite_Limb cLimbRef = cAnimationData.cSprite.cCostumeInfo_Default.lstLimbs[lstLimbData.Count];
                lstLimbData.Add(new classLimbInfo(ref cMyRef, ref cLimbRef));
            }

            for (int intLimbCounter = 0; intLimbCounter < lstLimbData.Count; intLimbCounter++)
            {
                lstLimbData[intLimbCounter].ptDrawCenter = lstData_Source[intLimbCounter].ptDrawCenter;
                lstLimbData[intLimbCounter].ptDrawHinge = lstData_Source[intLimbCounter].ptDrawHinge;
                lstLimbData[intLimbCounter].cLimb = cAnimationData.cSprite.cCostumeInfo_Default.lstLimbs[intLimbCounter];
            }

            cFrame.Horizontal_Mirror = bolMirrorH;
            cFrame.Vertical_Mirror = bolMirrorV;
            return lstImages;
        }


        /// <summary>
        /// the sprite's location on the screen changes internally during animation and is described by pt
        /// </summary>
        Point _pt;
        public Point pt
        {
            get { return _pt; }
            set
            {
                if (_pt.X != value.X || _pt.Y != value.Y)
                {
                    _pt = value;
                    //System.Diagnostics.Debug.Print("sprite.pt (" + pt.X.ToString() + ", " + pt.Y.ToString() + ")");
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public classSpriteData()
        {
        }

        public classSpriteData Copy()
        {
            classSpriteData cRetVal = new classSpriteData();
            cRetVal.bmpImage = new Bitmap(bmpImage);
            cRetVal.cAnimationData = cAnimationData.Copy();
            cRetVal.cCostumeInfo = cCostumeInfo.Copy();
            cRetVal.lstImages = new List<Bitmap>();
            cRetVal.lstImages.AddRange(lstImages);
            cRetVal.lstLimbData = new List<classLimbInfo>();
            cRetVal.lstLimbData.AddRange(lstLimbData);
            cRetVal.pt = pt;

            return cRetVal;
        }


        #region classes
        public class classLimbInfo
        {
            classSpriteData cSpriteData = null;
            public classSprite_Limb cLimb = null;

            public classLimbInfo(ref classSpriteData cSpriteData, ref classSprite_Limb cLimb)
            {
                this.cSpriteData = cSpriteData;
                this.cLimb = cLimb;
            }

            /// <summary>
            /// position of this limb relative to the MasterLimb on the Animation Frame's output Bitmap
            /// four quadrants around the MasterLimb follow pixel screen orientation
            /// (-,-) (+,-)
            /// (-,+) (+,+)
            /// </summary>
            Point _ptDrawCenter = new Point();
            public Point ptDrawCenter
            {
                get { return _ptDrawCenter; }
                set { _ptDrawCenter = value; }
            }

            /// <summary>
            /// position of this limb relative to the MasterLimb on the Animation Frame's output Bitmap
            /// four quadrants around the MasterLimb follow pixel screen orientation
            /// (-,-) (+,-)
            /// (-,+) (+,+)
            /// </summary>
            Point _ptDrawHinge = new Point();
            public Point ptDrawHinge
            {
                get { return _ptDrawHinge; }
                set { _ptDrawHinge = value; }
            }
        }



        /// <summary>
        /// developer information to control the sprites in an application
        /// </summary>
        public class classAnimationData
        {
            public string filename;

            /// <summary>
            /// sprite this classSpriteData instantiation uses to generate Animation_Frame bitmaps
            /// </summary>
            public classSprite cSprite;

            /// <summary>
            /// the animation to be drawn by the Sprite in a call to Draw_Animation_Frame()
            /// </summary>
            public classAnimation cAnimation = null;

            /// <summary>
            /// override animations that alter the main animation's limb positions for limbs specified in each AnimationOverride
            /// </summary>
            public List<classAnimation_Override> lstAnimation_Overrides = new List<classAnimation_Override>();
            
            /// <summary>
            /// the FrameIndex of the image to be drawn by the sprite in a call to Draw_Animation_Frame()
            /// </summary>
            public int intFrameIndex = 0;

            /// <summary>
            /// the DrawSizeFactor of the image to be drawn by the sprite in a call to Draw_Animation_Frame()
            /// </summary>
            public double dblDrawSizeFactor = 1.0;

            /// <summary>
            /// the angle of image to be drawn by the sprite in a call to Draw_Animation_Frame()
            /// </summary>
            public double dblDrawAngle = 0;

            /// <summary>
            /// mirror value which overrides frame's natural mirror state when drawn through cSpriteData.Draw()
            /// </summary>
            public classAnimation_Frame.enuFrameMirror eMirror = classAnimation_Frame.enuFrameMirror.ignore;

            /// <summary>
            /// makes a copy of itself and sends it to the calling function
            /// </summary>
            /// <returns>returns a copy of this instance of classAnimationData</returns>
            public classSpriteData.classAnimationData Copy()
            {
                classSpriteData.classAnimationData cRetVal = new classAnimationData();

                cRetVal.cAnimation = cAnimation;
                cRetVal.cSprite = cSprite;
                cRetVal.dblDrawAngle = dblDrawAngle;
                cRetVal.dblDrawSizeFactor = dblDrawSizeFactor;
                cRetVal.filename = filename;
                cRetVal.intFrameIndex = intFrameIndex;

                return cRetVal;
            }
        }
        #endregion
    }

    /// <summary>
    /// item in list of information used by the sprite to position limbs according to an animation's frame before placing images together 
    /// as a completed sprite image
    /// </summary>
    public class classAnimation_Frame_LimbData
    {
        public classAnimation_Frame cFrame = null;
        static int intIDCounter =0 ;
        int _ID = intIDCounter++;
        public int ID
        {
            get { return _ID; }
        }

        public classAnimation_Frame_LimbData(ref classAnimation_Frame _cFrame)
        {
            cFrame = _cFrame;
        }

        double dblSlaveContactMagnitude_Factor = 1.0;
        /// <summary>
        /// multiplied with the Limb's Hinge's SLAVE contact magnitude to adjust the limb's position relative to its master in an animation frame
        /// value is set by the SpriteEditor during animation frame design phase
        /// </summary>
        public double SlaveContactMagnitude_Factor
        {
            get { return dblSlaveContactMagnitude_Factor; }
            set
            {
                dblSlaveContactMagnitude_Factor = value;
            }
        }

        double dblAngle = 0;
        /// <summary>
        /// angle between a slave limb and its master. 
        /// value is set by the SpriteEditor during animation frame design phase
        /// </summary>
        public double Angle
        {
            get { return dblAngle; }
            set
            {
                dblAngle = value;
            }
        }

        double dblDrawAngle = 0;
        /// <summary>
        /// DrawAngle between a slave limb and its master. 
        /// value is set by the SpriteEditor during animation frame design phase
        /// </summary>
        public double DrawAngle
        {
            get { return dblDrawAngle; }
            set
            {
                dblDrawAngle = value;
            }
        }

        bool bolValid = false;
        public bool Valid
        {
            get { return bolValid; }
        }

        bool bolOverride = false;
        public bool Override
        {
            get { return bolOverride; }
            set { bolOverride = value; }
        }

        /// <summary>
        /// position of this limb relative to the MasterLimb on the Animation Frame's output Bitmap
        /// four quadrants around the MasterLimb follow pixel screen orientation
        /// (-,-) (+,-)
        /// (-,+) (+,+)
        /// </summary>
        Point _ptDrawCenter = new Point();
        public Point ptDrawCenter
        {
            get { return _ptDrawCenter; }
            set
            {
                _ptDrawCenter = value;
                bolValid = true;
            }
        }

        /// <summary>
        /// position of this limb relative to the MasterLimb on the Animation Frame's output Bitmap
        /// four quadrants around the MasterLimb follow pixel screen orientation
        /// (-,-) (+,-)
        /// (-,+) (+,+)
        /// </summary>
        Point _ptDrawHinge = new Point();
        public Point ptDrawHinge
        {
            get { return _ptDrawHinge; }
            set { _ptDrawHinge = value; }
        }

        /// <summary>
        /// pointer to limb this data describes
        /// </summary>
        int _intLimbIndex;
        public int intLimbIndex
        {
            get { return _intLimbIndex; }
            set
            {
                _intLimbIndex = value;
            }
        }

        int intImageList_Index = 0;
        /// <summary>
        /// index of limb image to be drawn in this animation frame
        /// </summary>
        public int ImageList_Index
        {
            get
            {
                if (intImageList_Index_Override < 0)  // use image index defined in animation frame
                    return intImageList_Index;
                else
                    return intImageList_Index_Override; // use image index override value
            }
            set
            {
                if (intImageList_Index != value)
                {
                    if (value >= cFrame.cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].lstImages.Count)
                    {
                        //MessageBox.Show("error");
                    }
                    else
                    {
                        intImageList_Index = value % cFrame.cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].lstImages.Count;
                        strImageList_Name = cFrame.cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].lstImages[intImageList_Index].Name;
                    }
                }
            }
        }

        int _intImageList_Index_Override = -1;
        /// <summary>
        /// used outside sprite class to change this limb's image in an animation frame
        /// </summary>
        int intImageList_Index_Override
        {
            get { return _intImageList_Index_Override; }
            set { _intImageList_Index_Override = value; }
        }

        public void ImageList_Index_Override(int intImageListIndex_New)
        {
            if (intImageListIndex_New >= 0 && intImageListIndex_New < cFrame.cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].lstImages.Count)
                intImageList_Index_Override = intImageListIndex_New;
        }

        public void ImageList_Index_Override_Reset()
        {
            intImageList_Index_Override = -1;
        }

        string strImageList_Name = classSprite_Limb.conDefaultLimbImageName;
        /// <summary>
        /// name of limb image to be drawn in this animation frame
        /// </summary>
        public string ImageList_Name
        {
            get { return strImageList_Name; }
            set
            {
                if (string.Compare(strImageList_Name, value) != 0)
                {
                    strImageList_Name = value;
                    resetImageListIndex_byName();
                }
            }
        }

        classColorFilter _colorFilter = new classColorFilter();
        public classColorFilter ColorFilter
        {
            get { return _colorFilter; }
            set { _colorFilter = value; }
        }


        byte bytOpacity = (byte)255;
        public byte Opacity
        {
            get { return bytOpacity; }
            set { bytOpacity = value; }
        }

        /// <summary>
        /// ensures a renamed limb images matches its index value
        /// </summary>
        public void resetImageListIndex_byName()
        {
            for (int intListCounter = 0; intListCounter < cFrame.cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].lstImages.Count; intListCounter++)
            {
                if (string.Compare(strImageList_Name, cFrame.cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].lstImages[intListCounter].Name) == 0)
                {
                    intImageList_Index = intListCounter;
                    break;
                }
            }
        }

        /// <summary>
        /// used to copy/insert a frame during SpriteEditor's animation building phase
        /// </summary>
        /// <returns></returns>
        public classAnimation_Frame_LimbData Copy()
        {
            classAnimation_Frame_LimbData cRetVal = new classAnimation_Frame_LimbData(ref cFrame);

            cRetVal.Angle = Angle;
            cRetVal.bolOverride = bolOverride;
            cRetVal.bolValid = Valid;
            cRetVal.cFrame = cFrame;
            cRetVal.DrawAngle = DrawAngle;
            cRetVal.intLimbIndex = intLimbIndex;
            cRetVal.ImageList_Index = ImageList_Index;
            cRetVal.strImageList_Name = strImageList_Name;
            cRetVal._intImageList_Index_Override = intImageList_Index_Override;
            cRetVal.Override = Override;
            cRetVal.ptDrawCenter = ptDrawCenter;
            cRetVal.ptDrawHinge = ptDrawHinge;
            cRetVal.SlaveContactMagnitude_Factor = SlaveContactMagnitude_Factor;
            cRetVal.ColorFilter = ColorFilter.Copy();
            cRetVal.Opacity = Opacity;
            cRetVal.bolValid = Valid;

            return cRetVal;
        }

        public class classColorFilter
        {
            static int intIDCounter = 0;
            int _ID = intIDCounter++;
            public int ID
            {
                get { return _ID; }
            }

            public classColorFilter() 
            {
            }

            public bool Valid = false;
            public Color clr = Color.FromArgb(255, 255, 255);
            public classSprite_Limb cLimb = null;
            public classColorFilter Copy ()
            {
                classColorFilter cRetVal = new classColorFilter();
                cRetVal.Valid = Valid;
                cRetVal.clr = clr;
                return cRetVal;
            }
        }
    }

    /// <summary>
    /// data pertaining to a single frame of a sprite's animation
    /// </summary>
    public class classAnimation_Frame
    {
        public enum enuFrameMirror { ignore, none, Horizontal, Vertical, Both, _numPixieFrameMirror };

        public static classAnimation_Frame.enuFrameMirror eMirrorFromString(string strMirror)
        {
            //        public enum enuFrameMirror { none, Horizontal, Vertical, Both, _numPixieFrameMirror };
            if (strMirror.Length == 0) return classAnimation_Frame.enuFrameMirror.none;
            char chrTest = strMirror[0];
            int intIndex = "inHVB".IndexOf(chrTest);
            if (intIndex >= 0 && intIndex < (int)classAnimation_Frame.enuFrameMirror._numPixieFrameMirror)
                return (classAnimation_Frame.enuFrameMirror)intIndex;
            else return classAnimation_Frame.enuFrameMirror.none;
        }

        /// <summary>
        /// sequence in which limb images are placed on a bitmap
        /// </summary>
        List<int> _lstDrawSequence = new List<int>();
        public List<int> lstDrawSequence
        {
            get { return _lstDrawSequence; }
            set { _lstDrawSequence = value; }
        }

        /// <summary>
        /// sequence in which limb images are placed on a bitmap
        /// </summary>
        List<classSprite_Limb> _lstOverride = new List<classSprite_Limb>();
        public List<classSprite_Limb> lstOverride
        {
            get { return _lstOverride; }
            set { _lstOverride = value; }
        }

        public classSprite cSprite = null;
        static int intIDCounter = 0;
        int _intMyID = intIDCounter++;
        public int intMyId
        {
            get { return _intMyID; }
        }

        public int Index
        {
            get
            {
                return cAnimation.lstFrames.IndexOf(this);
            }
        }

        public classAnimation_Frame(ref classSprite Sprite)
        {
            cSprite = Sprite;
        }

        classAnimation cAnimation = null;
        public classAnimation Animation
        {
            get { return cAnimation; }
            set { cAnimation = value; }
        }

        /// <summary>
        /// TopLeft and BottomRight points diverging away from the MasterLimb during draw phase 
        /// define size of output Bitmap
        /// </summary>
        public Point ptTL, ptBR;
        public Point ptTL_StandardSize, ptBR_StandardSize;

        int intLimb_DrawRelativeTo;
        /// <summary>
        /// limb around which the classSpriteData information bases its positioning variables to allow the sprite to
        /// be drawn onto the screen.  
        /// Limb_DrawRelativeTo is set by developper in the SpriteEditor during animation design
        /// </summary>
        public int Limb_DrawRelativeTo
        {
            get
            {
                return intLimb_DrawRelativeTo;
            }
            set
            {
                if (intLimb_DrawRelativeTo != value)
                {
                    intLimb_DrawRelativeTo = value;
                }
            }
        }

        bool bolVertical_Mirror = false;
        /// <summary>
        /// determines whether the completed Sprite's Animation Frame bitmap will be inverted vertically
        /// information pertaining to output bitmap will reflect Vertical_Mirror status
        /// </summary>
        public bool Vertical_Mirror
        {
            get { return bolVertical_Mirror; }

            set { bolVertical_Mirror = value; }
        }

        bool _bolHorizontal_Mirror = false;
        /// <summary>
        /// determines whether the completed Sprite's Animation Frame bitmap will be inverted horizontally
        /// information pertaining to output bitmap will reflect Horizontal_Mirror status
        /// </summary>
        public bool Horizontal_Mirror
        {
            get { return _bolHorizontal_Mirror; }

            set { _bolHorizontal_Mirror = value; }
        }

        /// <summary>
        /// resets values of ptTL & ptBR at start of Draw_Animation_Frame()
        /// </summary>
        public void resetTLBR()
        {
            ptTL = new Point(0, 0);
            ptBR = new Point(0, 0);
            ptTL_StandardSize = new Point();
            ptBR_StandardSize = new Point();
        }

        public classAnimation_Frame_LimbData getData(string strLimbName)
        { // debug - improve this with an AlphTree for each frame
            classSprite_Limb cLimb = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(strLimbName);

            for (int intCounter = 0; intCounter < lstData.Count; intCounter++)
            {
                classAnimation_Frame_LimbData cData = lstData[intCounter];
                if (cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex] == cLimb)
                    return cData;
            }

            return null;
        }
        
        public classAnimation_Frame_LimbData getOverrideData(string strLimbName)
        { // debug - improve this with an AlphTree for each frame

            classSprite_Limb cLimb = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(strLimbName);

            for (int intCounter = 0; intCounter < lstDataOverride.Count; intCounter++)
            {
                classAnimation_Frame_LimbData cData = lstDataOverride[intCounter];
                if (cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex] == cLimb)
                    return cData;
            }

            return null;
        }

        /// <summary>
        /// list of limb information describing their positions relative to their respective master limbs
        /// </summary>
        public List<classAnimation_Frame_LimbData> lstData = new List<classAnimation_Frame_LimbData>();
        public List<classAnimation_Frame_LimbData> lstDataOverride = new List<classAnimation_Frame_LimbData>();

        bool bolInitialized = false;
        public bool StandardSizeInitialized
        {
            get { return bolInitialized; }
            set { bolInitialized = value; }
        }

        double dblDrawAngle = 0;
        public double DrawAngle
        {
            get { return dblDrawAngle; }
            set
            {
                if (dblDrawAngle != value)
                {
                    dblDrawAngle = value;
                    bolInitialized = false;
                }
            }
        }
        /*
        public classAnimation_Frame_LimbData getData_StandardSize(string strLimbName)
        { // debug - improve this with an AlphTree for each frame
            classSprite_Limb cLimb = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(strLimbName);

            for (int intCounter = 0; intCounter < lstData.Count; intCounter++)
            {
                classAnimation_Frame_LimbData cData = lstData[intCounter];
                if (cSprite.cCostumeInfo_Default.lstLimbs[  cData.intLimbIndex] == cLimb)
                    return cData;
            }

            return null;
        }

        /// <summary>
        /// list of limb information describing their positions relative to their respective master limbs
        /// </summary>
        public List<classAnimation_Frame_LimbData> lstData = new List<classAnimation_Frame_LimbData>();

        */

        public class classCache
        {
            Bitmap _bmp;
            public Bitmap bmp
            {
                get { return _bmp; }
                set
                {
                    _bmp = value;
                }
            }

            public double DrawAngle;
            public double DrawSizeFactor;
            public string strLimbDrawIndex = "";
            public classSprite_CostumeInfo.classDrawData cDrawData = new classSprite_CostumeInfo.classDrawData();
        }

        public classCache cCache = new classCache();
        public string strLimbDrawIndex_CacheTest = "";


        /// <summary>
        /// returns a clone copy of original
        /// </summary>
        /// <returns></returns>
        public classAnimation_Frame Copy()
        {
            classAnimation_Frame cRetVal = new classAnimation_Frame(ref cSprite);
            cRetVal.ptTL = new Point(ptTL.X, ptTL.Y);
            cRetVal.ptBR = new Point(ptBR.X, ptBR.Y);
            cRetVal.ptTL_StandardSize = new Point(ptTL_StandardSize.X, ptTL_StandardSize.Y);
            cRetVal.ptBR_StandardSize = new Point(ptBR_StandardSize.X, ptBR_StandardSize.Y);

            for (int intDataCounter = 0; intDataCounter < lstData.Count; intDataCounter++)
            {
                cRetVal.lstData.Add(lstData[intDataCounter].Copy());
                //if (cRetVal.lstData.Count > intDataCounter)
                //    cRetVal.lstData.Add(lstData[intDataCounter].Copy());
            }
            int[] arrDrawSequence = new int[lstDrawSequence.Count];
            lstDrawSequence.CopyTo(arrDrawSequence);
            cRetVal.lstDrawSequence.AddRange(arrDrawSequence.ToList<int>());
            return cRetVal;
        }
    }

    /// <summary>
    /// sequence of images called Frames designed by a developper using the SpriteEditor to animate a sprite
    /// </summary>
    public class classAnimation
    {
        /// <summary>
        /// animation's name must be unique to the Sprite
        /// </summary>
        public string Name;

        public object tag;

        /// <summary>
        /// list of Frames that constitute this animation
        /// </summary>
        public List<classAnimation_Frame> lstFrames = new List<classAnimation_Frame>();

        /// <summary>
        /// pointer back to sprite of which this animation is a part
        /// </summary>
        public classSprite cSprite = null;

        /// <summary>
        /// animation instantiations must point back to their calling sprite
        /// </summary>
        /// <param name="Sprite">Sprite to which this animation belongs</param>
        public classAnimation(ref classSprite Sprite)
        {
            cSprite = Sprite;
        }

        /// <summary>
        /// changes the name of the animation.  All animations must have a name unique for that sprite.
        /// </summary>
        /// <param name="NewName"></param>
        public void ChangeName(string NewName)
        {
            classAnimation cMyReference = this;
            Name = NewName;
            List<object> lstTraversalReport = cSprite.cBT_Animations.Traverse();
            if (cSprite.cBT_Animations != null)
                cSprite.cBT_Animations = null;
            cSprite.cBT_Animations = new BinTree.classBinTree();

            for (int intAnimationCounter = 0; intAnimationCounter < lstTraversalReport.Count; intAnimationCounter++)
            {
                classAnimation cAnimation = (classAnimation)lstTraversalReport[intAnimationCounter];
                object objTemp = lstTraversalReport[intAnimationCounter];
                cSprite.cBT_Animations.Insert(ref objTemp, cAnimation.Name);
            }

        }

        /// <summary>
        /// removes a frame from an animation
        /// </summary>
        /// <param name="intFrame">index of frame to be removed</param>
        public void Frame_Sub(int intFrame)
        {
            if (lstFrames.Count > 0)
            {
                for (int intFrameCounter = intFrame; intFrameCounter < lstFrames.Count - 1; intFrameCounter++)
                    lstFrames[intFrameCounter] = lstFrames[intFrameCounter + 1];
                lstFrames.Remove(lstFrames[lstFrames.Count - 1]);
            }
        }

        /// <summary>
        /// creates a new frame and inserts it at specified index
        /// </summary>
        /// <param name="intFrame">index of frame after which the new frame is to be inserted</param>
        /// <returns>returns a newly created frame</returns>
        public classAnimation_Frame Frame_Add(int intFrame)
        {
            classAnimation_Frame cFrameNew = new classAnimation_Frame(ref cSprite);
            return Frame_Add(intFrame, ref cFrameNew);
        }

        /// <summary>
        /// inserts an existing frame into the animation at specified index location
        /// </summary>
        /// <param name="intFrame">index of frame after which the frame is to be inserted</param>
        /// <param name="cFrameNew">existing frame passed by reference to be inserted into the animation</param>
        /// <returns></returns>
        public classAnimation_Frame Frame_Add(int intFrame, ref classAnimation_Frame cFrameNew)
        {
            return Frame_Add(intFrame, ref cFrameNew, true);
        }


        /// <summary>
        /// inserts an existing frame into an animation at specified index
        /// </summary>
        /// <param name="intFrame">index after which the frame is to be inserted</param>
        /// <param name="cFrameNew">an existing frame passed by reference to be inserted into the animation</param>
        /// <param name="bolCopyPrecedingFrame">when set: the data of the frame being inserted into the animation is overwritten and made into a copy of the the frame it follows</param>
        /// <returns></returns>
        public classAnimation_Frame Frame_Add(int intFrame, ref classAnimation_Frame cFrameNew, bool bolCopyPrecedingFrame)
        {
            lstFrames.Add(null);
            if (lstFrames.Count > 1)
            {
                for (int intFrameCounter = (int)lstFrames.Count - 2; intFrameCounter > intFrame; intFrameCounter--)
                    lstFrames[intFrameCounter + 1] = lstFrames[intFrameCounter];

                classAnimation_Frame cFrameOld = lstFrames[intFrame];
                lstFrames[++intFrame] = cFrameNew;
                cFrameNew.ptTL.X = cFrameOld.ptTL.X;
                cFrameOld.ptTL.Y = cFrameOld.ptTL.Y;
                if (bolCopyPrecedingFrame)
                {
                    for (int intLimbCounter = 0; intLimbCounter < cFrameOld.lstData.Count; intLimbCounter++)
                    {
                        classAnimation_Frame_LimbData cData_Old = cFrameOld.lstData[intLimbCounter];
                        classAnimation_Frame_LimbData cData_New = new classAnimation_Frame_LimbData(ref cFrameNew);
                        cData_New.Angle = cData_Old.Angle;
                        cData_New.intLimbIndex = cData_Old.intLimbIndex;
                        cData_New.ptDrawCenter = new Point(cData_Old.ptDrawCenter.X, cData_Old.ptDrawCenter.Y);
                        cData_New.SlaveContactMagnitude_Factor = cData_Old.SlaveContactMagnitude_Factor;
                        cData_New.ImageList_Index = cData_Old.ImageList_Index;
                        int[] intDrawSequence = new int[cFrameOld.lstDrawSequence.Count];
                        cFrameOld.lstDrawSequence.CopyTo(intDrawSequence);
                        cFrameNew.lstDrawSequence = intDrawSequence.ToList<int>();
                        cFrameNew.lstData.Add(cData_New);

                        classAnimation_Frame_LimbData cDataStandardSize_New = new classAnimation_Frame_LimbData(ref cFrameNew);
                        cDataStandardSize_New.Angle = cData_Old.Angle;
                        cDataStandardSize_New.intLimbIndex = cData_Old.intLimbIndex;
                        cDataStandardSize_New.ptDrawCenter = new Point(cData_Old.ptDrawCenter.X, cData_Old.ptDrawCenter.Y);
                        cDataStandardSize_New.SlaveContactMagnitude_Factor = cData_Old.SlaveContactMagnitude_Factor;
                        cDataStandardSize_New.ImageList_Index = cData_Old.ImageList_Index;
                        cFrameOld.lstDrawSequence.CopyTo(intDrawSequence);
                        cFrameNew.lstDrawSequence = intDrawSequence.ToList<int>();
                    }
                }
                cFrameNew.Animation = this;
                return cFrameNew;
            }
            else
            {
                cFrameNew.lstDrawSequence.Clear();
                for (int intLimbCounter = 1; intLimbCounter < cSprite.cCostumeInfo_Default.lstLimbs.Count; intLimbCounter++)
                {
                    classSprite_Limb cLimb = cSprite.cCostumeInfo_Default.lstLimbs[intLimbCounter];
                    if (cLimb != null)
                    {
                        int intLimbIndex = cSprite.cCostumeInfo_Default.lstLimbs.IndexOf(cLimb);
                        cFrameNew.lstDrawSequence.Add(intLimbIndex);
                    }
                }
                cFrameNew.lstDrawSequence.Add(classSpriteMaker.cLimb_DoNotDraw);

                for (int intLimbCounter = 0; intLimbCounter < cFrameNew.lstDrawSequence.Count; intLimbCounter++)
                {
                    classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrameNew);
                    cData.intLimbIndex = intLimbCounter; //cFrameNew.lstDrawSequence[intLimbCounter];
                    cFrameNew.lstData.Add(cData);
                }
                Frame_Capture(ref cFrameNew);
                intFrame = 0;
                lstFrames[intFrame] = cFrameNew;
                cFrameNew.Animation = this;
                return cFrameNew;
            }
        }

        /// <summary>
        /// overwrites data of the Frame passed by reference with the SpriteEditor's current frame screen values
        /// </summary>
        /// <param name="cFrame"></param>
        public void Frame_Capture(ref classAnimation_Frame cFrame)
        {
            for (int intLimbCounter = 0; intLimbCounter < cFrame.lstData.Count; intLimbCounter++)
            {
                classAnimation_Frame_LimbData cData = cFrame.lstData[intLimbCounter];
                if (cData != null
                    && cData.intLimbIndex >= 0
                    && cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Hinge != null)
                {
                    cData.Angle = cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Hinge.Angle;
                    cData.SlaveContactMagnitude_Factor = cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].Hinge.SlaveContact_MagnitudeFactor;
                    cData.ptDrawCenter = new Point(cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].ptDrawCenter.X,
                                                   cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].ptDrawCenter.Y);
                    cData.ImageList_Index = cSprite.cCostumeInfo_Default.lstLimbs[cData.intLimbIndex].intImageList_Index;
                }
            }
        }

        /// <summary>
        /// adds a new limb to all of this animation's frames's lstDrawSequence lists
        /// </summary>
        /// <param name="cLimb">limb to be added to drawSequence lists</param>
        /// <param name="bolDoNotDraw">when set: limb is appended to the end of drawSequence and is not drawn in any of the existing frames</param>
        public void DrawList_Add(ref classSprite_Limb cLimb, bool bolDoNotDraw)
        {
            int intLimbIndex = cSprite.cCostumeInfo_Default.lstLimbs.IndexOf(cLimb);
            for (int intFrameCounter = 0; intFrameCounter < lstFrames.Count; intFrameCounter++)
            {
                classAnimation_Frame cFrame = lstFrames[intFrameCounter];
                if (bolDoNotDraw)
                {
                    cFrame.lstDrawSequence.Add(intLimbIndex);
                }
                else
                {
                    cFrame.lstDrawSequence.Add(-1);
                    for (int intLimbCounter = cFrame.lstDrawSequence.Count - 2; intLimbCounter >= 0; intLimbCounter--)
                    {
                        cFrame.lstDrawSequence[intLimbCounter + 1] = cFrame.lstDrawSequence[intLimbCounter];
                    }
                    cFrame.lstDrawSequence[0] = intLimbIndex;
                }
            }
        }

        public Point LimbPos(string strLimbName, int intFrame)
        {
            if (intFrame < 0 || intFrame >= lstFrames.Count)
            {
                return new Point();
            }

            classAnimation_Frame cFrame = lstFrames[intFrame];
            if (!cFrame.StandardSizeInitialized)
            {
                classSpriteData cSpriteDataTemp = new classSpriteData();
                cSpriteDataTemp.cAnimationData.cSprite = cFrame.cSprite;
                cSpriteDataTemp.cAnimationData.cAnimation = cFrame.Animation;
                cSpriteDataTemp.cAnimationData.intFrameIndex = intFrame;
                cSpriteDataTemp.cAnimationData.dblDrawAngle = 0;
                cSpriteDataTemp.cAnimationData.dblDrawSizeFactor = 1;

                cSprite.draw_Animation_Frame(ref cSpriteDataTemp);
            }
            classAnimation_Frame_LimbData cFrameData = cFrame.getData(strLimbName);
            if (cFrameData == null)
                return cFrame.ptTL_StandardSize;
            else
                return cFrameData.ptDrawCenter;
        }

        public Point LimbPos(ref classSprite_Limb cLimb, int intFrame)
        {
            if (cLimb == null) return new Point();
            return LimbPos(cLimb.Name, intFrame);
        }
        public Point LimbPos(int intLimbIndex, int intFrame)
        {
            if (intLimbIndex < 0 || intLimbIndex >= cSprite.cCostumeInfo_Default.lstLimbs.Count) return new Point();

            return LimbPos(cSprite.cCostumeInfo_Default.lstLimbs[intLimbIndex].Name, intFrame);
        }
    }


    public class classTextSpriteInfo
    {
        public bool Valid = false;
        public Font fnt;
        public Color Color_Fore;
        public Color Color_Transparent;
    }

    /// <summary>
    /// articulating limbed character image used to generate animations
    /// </summary>
    public class classSprite
    {
        static int intIDCounter = 0;
        int intID = intIDCounter++;
        public int ID { get { return intID; } }

        public bool TextSprite
        {
            get
            {
                return textSpriteInfo.Valid;
            }
            set
            {
                textSpriteInfo.Valid = value;
            }
        }

        public classTextSpriteInfo textSpriteInfo = new classTextSpriteInfo();

        static Point ptZero = new Point();
        /// <summary>
        /// determines whether runTime errorMessages are displayed in messageBox()
        /// </summary>
        public static bool ShowErrorMessages = false;

        /// <summary>
        /// math class used by SpriteEditor_2017 and classSprite as well as all associated classes
        /// </summary>
        public static classMath3 classMath3 = new classMath3();

        /// <summary>
        /// constant used to determine end of enuFSM.Celebrate Draw Sequence
        /// </summary>
        public const string conDrawSequenceDoNotDraw = "-do-not-draw-";

        /// <summary>
        /// default name of all new animations
        /// </summary>
        public const string conDefaultAnimationName = "New Animation";

        /// <summary>
        /// all sprites have a MasterLimb with this identifying name
        /// </summary>
        public const string conMasterLimb_Name = "MasterLimb";

        /// <summary>
        /// semaphore used to limit access to DrawAnimation_Frame()
        /// </summary>
        System.Threading.Semaphore semDrawAnimation_Frame = new System.Threading.Semaphore(0, 1);

        static Bitmap bmpMasterLimb = null;

        public List<classSprite_CostumeInfo> lstCostumeInfo = new List<classSprite_CostumeInfo>();

        public object tag = null;


        bool bolDoNotDraw = false;
        public bool DoNotDraw
        {
            get { return bolDoNotDraw; }
            set { bolDoNotDraw = value; }
        }

        classSprite_CostumeInfo _cCostumeInfo_Default = null;
        public classSprite_CostumeInfo cCostumeInfo_Default
        {
            get { return _cCostumeInfo_Default; }
        }


        /// <summary>
        /// alpha tree used to store and retrieve animations by name
        /// </summary>
        public BinTree.classBinTree cBT_Animations = new BinTree.classBinTree();

        /// <summary>
        /// list of animations redundant to cBT_Animations.
        /// used to quickly assess the number of animations this sprite currently has
        /// </summary>
        public List<classAnimation> lstAnimations = new List<classAnimation>();

        double _dblDrawSizeFactor = 1.0;

        /// <summary>
        /// factor by which output image is measured compared to original sprite size
        /// </summary>
        public double DrawSizeFactor
        {
            get { return _dblDrawSizeFactor; }
            set
            {
                if (value > 0)
                {
                    _dblDrawSizeFactor = value;
                }
            }
        }

        /// <summary>
        /// </summary>
        int intNumImagesPerQuadrant = classSpriteMaker.conNumImagesPerQuadrant;
        /// <summary>
        /// number of images used to draw the limbs in one full rotation
        /// </summary>
        public int NumImagesPerQuadrant
        {
            get { return intNumImagesPerQuadrant; }
            set
            {
                if (intNumImagesPerQuadrant != value)
                {
                    intNumImagesPerQuadrant = value;
                    for (int intLimbCounter = 0; intLimbCounter < cCostumeInfo_Default.lstLimbs.Count; intLimbCounter++)
                    {
                        classSprite_Limb cLimb = cCostumeInfo_Default.lstLimbs[intLimbCounter];
                        for (int intLimbImageCounter = 0; intLimbImageCounter < cLimb.lstImages.Count; intLimbImageCounter++)
                        {
                            classSprite_Limb.classSprite_Limb_Images cLimbImage = cLimb.lstImages[intLimbImageCounter];
                            Bitmap bmp = cLimbImage.bmpImages[0];
                            cLimbImage.bmpImages = new Bitmap[intNumImagesPerQuadrant * 4];
                            cLimbImage.bmpImages[0] = bmp;
                            classSprite_Limb.GenerateFirstQuadrantImages(ref cLimbImage, intNumImagesPerQuadrant);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// ------------ USED BY SPRITEMAKER ------------  to instantiate a new sprite
        /// </summary>
        /// <param name="name">name of new sprite to be instantiated</param>
        public classSprite(string name) 
        {
            semDrawAnimation_Frame.Release();
            if (bmpMasterLimb == null)
            {
                string strM = "M";
                Font fnt = new Font("courier", 12, FontStyle.Regular);
                Size szM = TextRenderer.MeasureText(strM, fnt);
                bmpMasterLimb = new Bitmap(szM.Width, szM.Height);
                using (Graphics g = Graphics.FromImage(bmpMasterLimb))
                {
                    g.FillRectangle(Brushes.White, new Rectangle(ptZero, szM));
                    g.DrawString(strM, fnt, Brushes.Black, ptZero);
                }
            }

            strSpriteName = name;
            classSprite cThisRef = this;
            _cCostumeInfo_Default = new classSprite_CostumeInfo(name);
            lstCostumeInfo.Add(_cCostumeInfo_Default);
            if (cCostumeInfo_Default.cBT_Limbs != null)
                cCostumeInfo_Default.cBT_Limbs = null;
            cCostumeInfo_Default.cBT_Limbs = new classBinTree();
            cCostumeInfo_Default.cLimb_Master = classSprite_Limb.New(conMasterLimb_Name, ref cThisRef, bmpMasterLimb);

            Animation_New(conDefaultAnimationName);
        }

        /// <summary>
        /// deletes a limb and all slave limbs attached to it
        /// </summary>
        /// <param name="strLimbName">name of limb to be deleted</param>
        public void Limb_Delete(string strLimbName)
        {
            classSprite_Limb cLimb_Delete = (classSprite_Limb)cCostumeInfo_Default.cBT_Limbs.Search(strLimbName);
            Limb_Delete(ref cLimb_Delete);
            if (cCostumeInfo_Default.cBT_Limbs != null)
                cCostumeInfo_Default.cBT_Limbs = null;
            cCostumeInfo_Default.cBT_Limbs = new classBinTree();
            for (int intCounter = 0; intCounter < cCostumeInfo_Default.lstLimbs.Count; intCounter++)
            {
                classSprite_Limb cLimb = cCostumeInfo_Default.lstLimbs[intCounter];
                object objLimbInTree = (object)cLimb;
                cCostumeInfo_Default.cBT_Limbs.Insert(ref objLimbInTree, cLimb.Name);
            }
        }

        /// <summary>
        /// deletes a limb and all its attached slave limbs
        /// </summary>
        /// <param name="cLimb_Delete">limb to be deleted</param>
        public void Limb_Delete(ref classSprite_Limb cLimb_Delete)
        {
            if (cLimb_Delete == null) return;
            for (int intLimbCounter = 0; intLimbCounter < cLimb_Delete.lstHinge_Slaves.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb_Slave = cLimb_Delete.lstHinge_Slaves[intLimbCounter].Limb_Slave;
                //Limb_Delete(ref cLimb_Slave);
                Limb_Delete(cLimb_Slave.Name);
            }

            int intLimbDeleteIndex = cCostumeInfo_Default.lstLimbs.IndexOf(cLimb_Delete);
            cCostumeInfo_Default.lstLimbs.Remove(cLimb_Delete);

            for (int intAnimationCounter = 0; intAnimationCounter < lstAnimations.Count; intAnimationCounter++)
            {
                classAnimation cAnimation = lstAnimations[intAnimationCounter];

                for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                {
                    classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];
                    if (cFrame.Limb_DrawRelativeTo > intLimbDeleteIndex)
                        cFrame.Limb_DrawRelativeTo--;

                    cFrame.lstDrawSequence.Remove(intLimbDeleteIndex);
                    for (int intDSCounter = 0; intDSCounter < cFrame.lstDrawSequence.Count; intDSCounter++)
                        if (cFrame.lstDrawSequence[intDSCounter] > intLimbDeleteIndex)
                            cFrame.lstDrawSequence[intDSCounter]--;

                    for (int intDataCounter = 0; intDataCounter < cFrame.lstData.Count; intDataCounter++)
                    {
                        classAnimation_Frame_LimbData cData = cFrame.lstData[intDataCounter];
                        if (cData.intLimbIndex == intLimbDeleteIndex)
                            cFrame.lstData.Remove(cData);
                    }
                    for (int intDataCounter = 0; intDataCounter < cFrame.lstData.Count; intDataCounter++)
                    {
                        classAnimation_Frame_LimbData cData = cFrame.lstData[intDataCounter];
                        if (cData.intLimbIndex > intLimbDeleteIndex)
                            cData.intLimbIndex--;
                    }
                }
            }

            for (int intMaster_Slave_Counter = 0; intMaster_Slave_Counter < cLimb_Delete.Hinge.Limb_Master.lstHinge_Slaves.Count; intMaster_Slave_Counter++)
            {
                if (cLimb_Delete.Hinge.Limb_Master.lstHinge_Slaves[intMaster_Slave_Counter].Limb_Slave == cLimb_Delete)
                {
                    classSprite_Hinge cHinge = cLimb_Delete.Hinge.Limb_Master.lstHinge_Slaves[intMaster_Slave_Counter];
                    cLimb_Delete.Hinge.Limb_Master.lstHinge_Slaves.Remove(cHinge);
                    break;
                }
            }
            if (cLimb_Delete != cCostumeInfo_Default.cLimb_Master)
                cCostumeInfo_Default.lstLimbs.Remove(cLimb_Delete);
        }


        List<classSprite_Limb> lstLimbSlavesGetRetVal = null;
        /// <summary>
        /// uses a recursion function to return all slave limbs attached to a specified limb
        /// </summary>
        /// <param name="strLimbName">name of limb whose slave limbs are to be listed</param>
        /// <returns></returns>
        public List<string> Limb_Slaves_Get(string strLimbName)
        {
            List<string> lstRetVal = new List<string>();

            classSprite_Limb cLimb = (classSprite_Limb)cCostumeInfo_Default.cBT_Limbs.Search(strLimbName);

            if (cLimb == null) return lstRetVal;


            lstLimbSlavesGetRetVal = new List<classSprite_Limb>();
            Limb_Slaves_Get_Recursion(ref cLimb);

            IEnumerable<classSprite_Limb> query = lstLimbSlavesGetRetVal.OrderBy(limb => limb.Name);
            lstLimbSlavesGetRetVal = (List<classSprite_Limb>)query.ToList();


            for (int intCounter = 0; intCounter < lstLimbSlavesGetRetVal.Count; intCounter++)
                lstRetVal.Add(lstLimbSlavesGetRetVal[intCounter].Name);

            return lstRetVal;
        }

        /// <summary>
        /// recursion function used to list a limb's slaves
        /// </summary>
        /// <param name="cLimb"></param>
        void Limb_Slaves_Get_Recursion(ref classSprite_Limb cLimb)
        {
            for (int intCounter = 0; intCounter < cLimb.lstHinge_Slaves.Count; intCounter++)
            {
                classSprite_Limb cLimb_Slave = cLimb.lstHinge_Slaves[intCounter].Limb_Slave;
                lstLimbSlavesGetRetVal.Add(cLimb_Slave);
                Limb_Slaves_Get_Recursion(ref cLimb_Slave);
            }
        }

        /// <summary>
        /// creates and returns a new limb
        /// </summary>
        /// <param name="strLimbName">name of limb to be created</param>
        /// <param name="bmp">base image used to generate the 128(default value) images for a full rotation.  base image is image drawn at 0 radians(</param>
        /// <param name="cMaster">the intended master of this new limb will include this limb in its list of slaveLimbs</param>
        /// <param name="strHingeName">name of the hinge that binds this new limb to its master</param>
        /// <param name="eventProgressReportHandler">event handler to call for UI progress reports</param>
        public void Limb_New(string strLimbName, Bitmap bmp, ref classSprite_Limb cMaster)
        {
            if (bmp == null)
            {
                if (ShowErrorMessages)
                    MessageBox.Show("a bitmap is needed", "bitmap null");
                return;
            }
            if (cCostumeInfo_Default.cBT_Limbs.Search(strLimbName) != null)
            {
                if (ShowErrorMessages)
                    MessageBox.Show("Limb " + strLimbName + " is already exists in sprite.  Name of limb must be unique for this sprite.", "name already used");
                return;
            }

            classSprite_Limb cLimbMaster_AT = (classSprite_Limb)cCostumeInfo_Default.cBT_Limbs.Search(cMaster.Name);
            if (cMaster != cLimbMaster_AT)
            {
                if (ShowErrorMessages)
                    MessageBox.Show("Master limb :" + cMaster.Name + " not found.");
                return;
            }

            // add new limb
            classSprite cRefThis = this;
            classSprite_Limb cLimb_new = classSprite_Limb.New(strLimbName, ref cRefThis, bmp);
            cLimb_new.Hinge = new classSprite_Hinge(ref cRefThis, ref cLimb_new, ref cMaster);
            cLimb_new.Hinge.SlaveContact_MagnitudeFactor = 1.0;
            cLimb_new.Hinge.Limb_Master = cMaster;
            cLimb_new.Hinge.Limb_Slave = cLimb_new;
            cLimb_new.Hinge.Limb_Master.Slave_Add(ref cLimb_new);
            for (int intAnimationCounter = 0; intAnimationCounter < lstAnimations.Count; intAnimationCounter++)
            {
                classAnimation cAnimation = lstAnimations[intAnimationCounter];

                cAnimation.DrawList_Add(ref cLimb_new, true);// cAnimation != Animation_Current);
                for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                {
                    classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];
                    classAnimation_Frame_LimbData cData_New = new classAnimation_Frame_LimbData(ref cFrame);
                    cData_New.Angle = 0;
                    cData_New.intLimbIndex = cCostumeInfo_Default.lstLimbs.IndexOf(cLimb_new);
                    cData_New.ptDrawCenter = new Point();
                    cData_New.SlaveContactMagnitude_Factor = 1;
                    cFrame.lstData.Add(cData_New);
                }
            }
        }

        /// <summary>
        /// create a Text Limb by specifying the text to be drawn, font and color
        /// </summary>
        /// <param name="strText">text image of limb</param>
        /// <param name="fnt">font of text drawn for this limb</param>
        /// <param name="clrForeColor">color of the text of this limb</param>
        public void Limb_New(string strText, Font fnt, Color clrForeColor)
        {
            EventHandler eventhandler_ProgressReport = null;
            Limb_New(strText, fnt, clrForeColor, Color.Black);
        }

        /// <summary>
        /// create a Text Limb by specifying the text to be drawn, font and color
        /// </summary>
        /// <param name="strText">text image of limb</param>
        /// <param name="fnt">font of text drawn for this limb</param>
        /// <param name="clrForeColor">color of the text of this limb</param> 
        /// <param name="clrTransparentColor">color that will be made transparent for this limb = not visible</param>
        public void Limb_New(string strText, Font fnt, Color clrForeColor, Color clrTransparentColor)
        {
            if (cCostumeInfo_Default.cBT_Limbs.Search(strText) != null)
            {
                if (ShowErrorMessages)
                    MessageBox.Show("Limb " + strText + " is already exists in sprite.  Name of limb must be unique for this sprite.", "name already used");
                return;
            }
            TextSprite = true;

            classSprite_Limb cLimbMaster = (classSprite_Limb)cCostumeInfo_Default.cLimb_Master;

            classSprite_Limb cLimbCrane = (classSprite_Limb)cCostumeInfo_Default.cBT_Limbs.Search("Crane");
            if (cLimbCrane == null)
            {
                Bitmap bmpBlank = new Bitmap(3, 3);

                Limb_New("Crane", bmpBlank, ref cCostumeInfo_Default.cLimb_Master);
                cLimbCrane = cCostumeInfo_Default.lstLimbs[cCostumeInfo_Default.lstLimbs.Count - 1];

                cLimbCrane.Hinge.Contact.Slave.Magnitude = 100;
                cLimbCrane.Hinge.Angle = 0;

            }

            classSprite_Limb cLimbCraneAxis = (classSprite_Limb)cCostumeInfo_Default.cBT_Limbs.Search("CraneAxis");// .lstLimbs[cCostumeInfo_Default.lstLimbs.Count - 1];
            if (cLimbCraneAxis == null)
            {
                Bitmap bmpBlank = new Bitmap(3, 3);
                Limb_New("CraneAxis", bmpBlank, ref cLimbCrane);
                cLimbCraneAxis = (classSprite_Limb)cCostumeInfo_Default.cBT_Limbs.Search("CraneAxis");
            }

            // add new limb
            classSprite cRefThis = this;
            Size szText = TextRenderer.MeasureText(strText, fnt);
            Bitmap bmp = new Bitmap(szText.Width, szText.Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.FillRectangle(new SolidBrush(clrTransparentColor), new RectangleF(0, 0, bmp.Width, bmp.Height));
                g.DrawString(strText, fnt, new SolidBrush(clrForeColor), new Point(0, 0));
            }

            classSprite_Limb cLimb_new = classSprite_Limb.New(strText, ref cRefThis, bmp);
            cLimb_new.Hinge = new classSprite_Hinge(ref cRefThis, ref cLimb_new, ref cLimbCraneAxis);
            cLimb_new.Hinge.SlaveContact_MagnitudeFactor = 1.0;
            cLimb_new.Hinge.Limb_Master = cLimbCraneAxis;
            cLimb_new.Hinge.Limb_Slave = cLimb_new;
            cLimb_new.Hinge.Limb_Master.Slave_Add(ref cLimb_new);

            classSpriteData cSpriteData = new classSpriteData();
            cSpriteData.cAnimationData.cSprite = this;

            for (int intAnimationCounter = 0; intAnimationCounter < lstAnimations.Count; intAnimationCounter++)
            {
                classAnimation cAnimation = lstAnimations[intAnimationCounter];
                cSpriteData.cAnimationData.cAnimation = cAnimation;

                cAnimation.DrawList_Add(ref cLimb_new, true);
                for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                {
                    classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];
                    classAnimation_Frame_LimbData cData_New = new classAnimation_Frame_LimbData(ref cFrame);
                    cData_New.Angle = 0;
                    cData_New.intLimbIndex = cCostumeInfo_Default.lstLimbs.IndexOf(cLimb_new);
                    cData_New.ptDrawCenter = new Point();
                    cData_New.SlaveContactMagnitude_Factor = 1;
                    cFrame.lstData.Add(cData_New);
                }
            }

            // generate animations

            List<classTextAnimation> lstTextAnimations = new List<classTextAnimation>();

            int intNumFrames = 4 * 16;

            lstTextAnimations.Add(new classTextAnimation(strText,
                                                          0,                                                    // num frames
                                                          0,                                                    // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " spin Clockwise x1",
                                                          intNumFrames,                                         // num frames
                                                          0,                                                    // limb angle start
                                                          -Math.PI * 2.0 / (double)intNumFrames,                // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta     

            lstTextAnimations.Add(new classTextAnimation(strText + " spin CounterClockwise x1",
                                                          intNumFrames,                                         // num frames
                                                          0,                                                    // limb angle start
                                                          Math.PI * 2.0 / (double)intNumFrames,                 // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta     
            lstTextAnimations.Add(new classTextAnimation(strText + " spin Clockwise x2",
                                                          intNumFrames,                                         // num frames
                                                          0,                                                    // limb angle start
                                                          -Math.PI * 4.0 / (double)intNumFrames,                // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta     

            lstTextAnimations.Add(new classTextAnimation(strText + " spin CounterClockwise x2",
                                                          intNumFrames,                                         // num frames
                                                          0,                                                    // limb angle start
                                                          Math.PI * 4.0 / (double)intNumFrames,                 // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta     
            lstTextAnimations.Add(new classTextAnimation(strText + " spin Clockwise x4",
                                                          intNumFrames,                                         // num frames
                                                          0,                                                    // limb angle start
                                                          -Math.PI * 8.0 / (double)intNumFrames,                // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta     

            lstTextAnimations.Add(new classTextAnimation(strText + " spin CounterClockwise x4",
                                                          intNumFrames,                                         // num frames
                                                          0,                                                    // limb angle start
                                                          Math.PI * 8.0 / (double)intNumFrames,                 // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          0,                                                    // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .1",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .1,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .1",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .1,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta


            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .2",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .2,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .2",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .2,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .3",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .3,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .3",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .3,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .4",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .4,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .4",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .4,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .5",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .5,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .5",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .5,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .6",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .6,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .6",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .6,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta


            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .7",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .7,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .7",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .7,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta


            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .8",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .8,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .8",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .8,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta


            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .9",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .9,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane .9",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          .9,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta


            lstTextAnimations.Add(new classTextAnimation(strText + " Crane 1.0",
                                                          intNumFrames,                                         // num frames
                                                          Math.PI / 2,                                           // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          1.0,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta

            lstTextAnimations.Add(new classTextAnimation(strText + " Crane 1.0",
                                                          1,                                                    // num frames
                                                          -Math.PI / 2,                                          // limb angle start
                                                          0,                                                    // limb angle delta
                                                          0,                                                    // limb magnitude start
                                                          0,                                                    // limb magnitude delta
                                                          0,                                                    // crane angle start
                                                          0,                                                    // crane angle delta
                                                          1.0,                                                   // crane magnitude start
                                                          0));                                                  // crane magnitude delta
            //                      spin clock-wise
            classSprite cSpriteMyRef = this;
            cSpriteData.cAnimationData.cSprite = this;

            while (lstTextAnimations.Count > 0)
            {
                classTextAnimation cTextAnimation = lstTextAnimations[0];
                lstTextAnimations.RemoveAt(0);

                classAnimation cAnimation_New = Animation_New(cTextAnimation.Name);
                cAnimation_New.lstFrames.Clear();

                cSpriteData.cAnimationData.cAnimation = cAnimation_New;
                cSpriteData.cAnimationData.dblDrawAngle = 0;
                cSpriteData.cAnimationData.dblDrawSizeFactor = 1.0;

                int intMasterLimbIndex = cCostumeInfo_Default.lstLimbs.IndexOf(cCostumeInfo_Default.cLimb_Master);
                int intCraneLimbIndex = cCostumeInfo_Default.lstLimbs.IndexOf(cLimbCrane);
                int intTextLimbIndex = cCostumeInfo_Default.lstLimbs.IndexOf(cLimb_new);

                for (int intFrameCounter = 0; intFrameCounter < intNumFrames; intFrameCounter++)
                {
                    classAnimation_Frame cFrame = new classAnimation_Frame(ref cSpriteMyRef);
                    cFrame.lstDrawSequence.Add(intTextLimbIndex);
                    cFrame.lstDrawSequence.Add(-1);

                    classAnimation_Frame_LimbData cData = new classAnimation_Frame_LimbData(ref cFrame);
                    classAnimation_Frame_LimbData cDataStandardSize = new classAnimation_Frame_LimbData(ref cFrame);

                    for (int intLimbCounter = 0; intLimbCounter < cCostumeInfo_Default.lstLimbs.Count; intLimbCounter++)
                    {
                        if (intLimbCounter != intMasterLimbIndex && intLimbCounter != intTextLimbIndex)
                            cFrame.lstDrawSequence.Add(intLimbCounter);

                        if (intLimbCounter == intTextLimbIndex)
                        {
                            classAnimation_Frame_LimbData cData_New = new classAnimation_Frame_LimbData(ref cFrame);
                            cData_New.Angle = cTextAnimation.LimbAngleStart + cTextAnimation.LimbAngleDelta * (double)intFrameCounter;
                            cData_New.intLimbIndex = intLimbCounter;
                            cData_New.ptDrawCenter = new Point();
                            cData_New.SlaveContactMagnitude_Factor = cTextAnimation.LimbMagnitudeStart + cTextAnimation.LimbMagnitudeDelta * (double)intFrameCounter;
                            cFrame.lstData.Add(cData_New);

                            /*classAnimation_Frame_LimbData cDataStandardSize_New = new classAnimation_Frame_LimbData(ref cFrame);
                            cDataStandardSize_New.Angle = cData_New.Angle;
                            cDataStandardSize_New.intLimbIndex = intLimbCounter;
                            cDataStandardSize_New.ptDrawCenter = new Point();
                            cDataStandardSize_New.SlaveContactMagnitude_Factor = cData_New.SlaveContactMagnitude_Factor;
                            cFrame.lstData.Add(cDataStandardSize_New);
                            */
                        }
                        else if (intLimbCounter == intCraneLimbIndex)
                        {
                            classAnimation_Frame_LimbData cData_New = new classAnimation_Frame_LimbData(ref cFrame);
                            cData_New.Angle = cTextAnimation.CraneAngleStart + cTextAnimation.CraneAngleDelta * (double)intFrameCounter;
                            cData_New.intLimbIndex = intLimbCounter;
                            cData_New.ptDrawCenter = new Point();
                            cData_New.SlaveContactMagnitude_Factor = cTextAnimation.CraneMagnitudeStart + cTextAnimation.CraneMagnitudeDelta * (double)intFrameCounter;
                            cFrame.lstData.Add(cData_New);
                            /*
                            classAnimation_Frame_LimbData cDataStandardSize_New = new classAnimation_Frame_LimbData(ref cFrame);
                            cDataStandardSize_New.Angle = cData_New.Angle;
                            cDataStandardSize_New.intLimbIndex = intLimbCounter;
                            cDataStandardSize_New.ptDrawCenter = new Point();
                            cDataStandardSize_New.SlaveContactMagnitude_Factor = cData_New.SlaveContactMagnitude_Factor;
                            cFrame.lstData.Add(cDataStandardSize_New);
                            */
                        }
                        else
                        {
                            classAnimation_Frame_LimbData cData_New = new classAnimation_Frame_LimbData(ref cFrame);
                            cData_New.Angle = 0;
                            cData_New.intLimbIndex = intLimbCounter;
                            cData_New.ptDrawCenter = new Point();
                            cData_New.SlaveContactMagnitude_Factor = 0;
                            cFrame.lstData.Add(cData_New);
                            /*
                            classAnimation_Frame_LimbData cDataStandardSize_New = new classAnimation_Frame_LimbData(ref cFrame);
                            cDataStandardSize_New.Angle = 0;
                            cDataStandardSize_New.intLimbIndex = intLimbCounter;
                            cDataStandardSize_New.ptDrawCenter = new Point();
                            cDataStandardSize_New.SlaveContactMagnitude_Factor = 0;
                            cFrame.lstData.Add(cDataStandardSize_New);
                            */
                        }
                    }
                    cFrame.Limb_DrawRelativeTo = cLimbMaster.intMyIndex;
                    cAnimation_New.lstFrames.Add(cFrame);
                }
            }
        }

        string strSpriteName = "";
        /// <summary>
        /// name of this sprite 
        /// </summary>
        public string Name
        {
            get { return strSpriteName; }
            set
            {
                if (string.Compare(strSpriteName, value) != 0)
                {
                    for (int intCostumeCounter = 0; intCostumeCounter < lstCostumeInfo.Count; intCostumeCounter++)
                        lstCostumeInfo[intCostumeCounter].lstLimbs[0].Name = conMasterLimb_Name;
                    strSpriteName = value;
                }
            }
        }

        bool bolUseRAMCache = true;
        /// <summary>
        /// when set DrawAnimation_Frame() returns the required animation/frame's cached image if found
        /// </summary>
        public bool UseRamCache
        {
            get { return bolUseRAMCache; }
            set
            {
                bolUseRAMCache = value;
            }
        }
        

        public enum enuRotatedLimbImage
        {
            SaveToFile,
            GenerateAtLoadTime,
            GenerateOnRequest,
            _numRotatedLimbImage
        };

        enuRotatedLimbImage _eRotatedLimbImage = enuRotatedLimbImage.SaveToFile;
        public enuRotatedLimbImage eRotatedLimbImage
        {
            get { return _eRotatedLimbImage; }
            set
            {
                if (_eRotatedLimbImage != value)
                {
                    _eRotatedLimbImage = value;
                    switch(_eRotatedLimbImage)
                    {
                        case enuRotatedLimbImage.SaveToFile:
                        case enuRotatedLimbImage.GenerateAtLoadTime:
                            {
                                Limbs_RotatedImages_Generate();
                            }
                            break;

                        case enuRotatedLimbImage.GenerateOnRequest:
                            {
                                Limbs_RotatedImages_Delete();
                            }
                            break;
                    }
                }
            }
        }


        void Limbs_RotatedImages_Delete()
        {
            for (int intCostumeCounter = 0; intCostumeCounter < lstCostumeInfo.Count; intCostumeCounter++)
            {
                classSprite_CostumeInfo cCostume = lstCostumeInfo[intCostumeCounter];
                for (int intLimbCounter = 0; intLimbCounter < cCostume.lstLimbs.Count; intLimbCounter++)
                {
                    classSprite_Limb cLimb = cCostume.lstLimbs[intLimbCounter];
                    for (int intLimbImageCounter = 0; intLimbImageCounter < cLimb.lstImages.Count; intLimbImageCounter++)
                    {
                        classSprite_Limb.classSprite_Limb_Images cImages = cLimb.lstImages[intLimbImageCounter];
                        for (int intBmpCounter = 1; intBmpCounter < cImages.bmpImages.Length; intBmpCounter++)
                        {
                            if (cImages.bmpImages[intBmpCounter] != null)
                            {
                                cImages.bmpImages[intBmpCounter].Dispose();
                                cImages.bmpImages[intBmpCounter] = null;
                            }
                        }
                    }
                }
            }
        }
     
        public void Limbs_RotatedImages_Generate()
        {
            for (int intCostumeCounter = 0; intCostumeCounter < lstCostumeInfo.Count; intCostumeCounter++)
            {
                classSprite_CostumeInfo cCostume = lstCostumeInfo[intCostumeCounter];
                for (int intLimbCounter = 0; intLimbCounter < cCostume.lstLimbs.Count; intLimbCounter++)
                {
                    classSprite_Limb cLimb = cCostume.lstLimbs[intLimbCounter];
                    for (int intLimbImageCounter = 0; intLimbImageCounter < cLimb.lstImages.Count; intLimbImageCounter++)
                    {
                        classSprite_Limb.classSprite_Limb_Images cImages = cLimb.lstImages[intLimbImageCounter];
                        // generate first quarter rotations
                        float fltDeltaAngle = 90f / (float)NumImagesPerQuadrant;
                        for (int intAngleCounter = 1; intAngleCounter < NumImagesPerQuadrant; intAngleCounter++)
                            cImages.bmpImages[intAngleCounter] = Math3.classGraphics.Rotate(cImages.bmpImages[0], fltDeltaAngle * (float)intAngleCounter);
                    }
                }
            }
        }
     
        /// <summary>
        /// deletes the specified animation
        /// </summary>
        /// <param name="strAnimation_Name">name of animation to be deleted</param>
        public void Animation_Delete(string strAnimation_Name)
        {
            classAnimation cAnimation = (classAnimation)cBT_Animations.Search(strAnimation_Name);
            Animation_Delete(ref cAnimation);
        }

        /// <summary>
        /// deletes the specified animation sent by reference
        /// </summary>
        /// <param name="animation">animation to be deleted</param>
        public void Animation_Delete(ref classAnimation animation)
        {
            if (animation == null) return;
            lstAnimations.Remove(animation);
            if (cBT_Animations != null) cBT_Animations = null;
            cBT_Animations = new BinTree.classBinTree();
            for (int intAnimationCounter = 0; intAnimationCounter < lstAnimations.Count; intAnimationCounter++)
            {
                classAnimation cAnimation = lstAnimations[intAnimationCounter];
                object objAnimation = (object)cAnimation;
                cBT_Animations.Insert(ref objAnimation, cAnimation.Name);
            }
        }


        public classAnimation Animation_New(string strAnimation_Name)
        {
            return Animation_New(strAnimation_Name, null);
        }

        /// <summary>
        /// creates and returns a new animation with one frame
        /// </summary>
        /// <param name="strAnimation_Name">name of animation to be created</param>
        /// <returns></returns>
        public classAnimation Animation_New(string strAnimation_Name, List<int> lstDrawSequence)
        {
            classSprite cMyReference = this;
            classAnimation cAnimation_New = new classAnimation(ref cMyReference);
            cAnimation_New.Name = strAnimation_Name;

            lstAnimations.Add(cAnimation_New);
            object objAnimation_New = (object)cAnimation_New;
            cBT_Animations.Insert(ref objAnimation_New, cAnimation_New.Name);

            cAnimation_New.Frame_Add(0);
            if (lstAnimations.Count > 1)
            {
                cAnimation_New.lstFrames[0].lstDrawSequence.Clear();
                for (int intLimbCounter = 0; intLimbCounter < lstAnimations[0].lstFrames[0].lstDrawSequence.Count; intLimbCounter++)
                {
                    cAnimation_New.lstFrames[0].lstDrawSequence.Add(lstDrawSequence != null
                                                                                     ? lstDrawSequence[intLimbCounter]
                                                                                     : lstAnimations[0].lstFrames[0].lstDrawSequence[intLimbCounter]);
                }
            }

            AlphabetizeAnimations();

            return cAnimation_New;
        }

        public void AlphabetizeAnimations()
        {
            IEnumerable<classAnimation> query = lstAnimations.OrderBy(animation => animation.Name);
            lstAnimations = (List<classAnimation>)query.ToList<classAnimation>();
        }

        /// <summary>
        /// sets the sprite's limb hinges to the values specified by the Animation Frame's lstData
        /// positioning the sprite in the pose defined by the specified Animation/Frame
        /// </summary>
        /// <param name="cAnimation">animation to be used to set the limb hinges's Angle/SlaveMagnitudeFactor variables</param>
        /// <param name="cFrame">frame of the animation to be used to set the limb hinges' Angle/SlaveMagnitudeFactor variables</param>
        void setFrameAnimationVariables(ref classSpriteData cSpriteData)//classAnimation cAnimation, ref classAnimation_Frame cFrame)
        {
            classAnimation cAnimation = cSpriteData.cAnimationData.cAnimation;
            classAnimation_Frame cFrame = cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            
            // copy frame's original data onto Override list
            cFrame.lstDataOverride.Clear();
            for (int intLimbDataCounter = 0; intLimbDataCounter < cFrame.lstData.Count; intLimbDataCounter++)
            {
                //cFrame.lstDataOverride.AddRange(cFrame.lstData);
                cFrame.lstDataOverride.Add(cFrame.lstData[intLimbDataCounter].Copy());
            }
            

            cFrame.strLimbDrawIndex_CacheTest = ""; // DEBUG - review why this is necessary
            if (cAnimation != null && cFrame != null)
            {
                List<int> lstLimbsAlteredByAnimationOverrides = new List<int>();

                for (int intAnimationOverrideCounter = cSpriteData.cAnimationData.lstAnimation_Overrides.Count - 1;
                    intAnimationOverrideCounter >= 0;
                    intAnimationOverrideCounter--)
                {
                    classAnimation_Override cAOData = cSpriteData.cAnimationData.lstAnimation_Overrides[intAnimationOverrideCounter];

                    classAnimation cAnimationOverride = cAOData.cAnimation;
                    classAnimation_Frame cFrameOverride = cAnimationOverride.lstFrames[cAOData.FrameIndex];
                    for (int intLimbCounter = 0; intLimbCounter < cFrameOverride.lstOverride.Count; intLimbCounter++)
                    {
                        classSprite_Limb cLimb = cFrameOverride.lstOverride[intLimbCounter];
                        if (!lstLimbsAlteredByAnimationOverrides.Contains(cLimb.intMyIndex))
                        {
                            lstLimbsAlteredByAnimationOverrides.Add(cLimb.intMyIndex);

                            classAnimation_Frame_LimbData cDataNew = cFrameOverride.getData(cLimb.Name);
                            int intIndex = cFrameOverride.lstData.IndexOf(cDataNew);
                            if (intIndex >= 0)
                            {
                                classAnimation_Frame_LimbData cDataOverride = cFrame.lstDataOverride[intIndex];
                                cDataOverride.Angle = cDataNew.Angle;
                                cDataOverride.ImageList_Index = cDataNew.ImageList_Index;
                                cDataOverride.SlaveContactMagnitude_Factor = cDataNew.SlaveContactMagnitude_Factor;
                            }
                        }
                    }
                }


                //////////////////////////////////////  IS THIS EVEN NECESSARY ???? ///////////////////////////////////////////////
                //for (int intDataCounter = 0; intDataCounter < cFrame.lstData.Count; intDataCounter++)
                //{
                //    classAnimation_Frame_LimbData cData = cFrame.lstData[intDataCounter];
                //    if (cData.intLimbIndex >= 0 && !lstLimbsAlteredByAnimationOverrides.Contains(cData.intLimbIndex))
                //    {
                //        if (cSpriteData.cCostumeInfo.lstLimbs[cData.intLimbIndex].Hinge != null)
                //        {
                //            cSpriteData.cCostumeInfo.lstLimbs[cData.intLimbIndex].Hinge.Angle = cData.Angle;
                //            cSpriteData.cCostumeInfo.lstLimbs[cData.intLimbIndex].Hinge.SlaveContact_MagnitudeFactor = cData.SlaveContactMagnitude_Factor;
                //            cSpriteData.cCostumeInfo.lstLimbs[cData.intLimbIndex].intImageList_Index = cData.ImageList_Index;
                //            if (UseRamCache)
                //                cFrame.strLimbDrawIndex_CacheTest += cData.ImageList_Index.ToString() + ".";
                //        }
                //    }
                //    else
                //    {
                //        ;
                //    }
                //}
                //////////////////////////////////////  IS THIS EVEN NECESSARY ???? ///////////////////////////////////////////////
            }
        }

        /// <summary>
        /// draws the Animation/Frame specified
        /// </summary>
        /// <param name="cSpriteData">information that defines the Animation, Frame, Size and Angle of the desired output image</param>
        /// <returns>bitmap of requested animation/frame</returns>
        public Bitmap draw_Animation_Frame(ref classSpriteData cSpriteData)
        {
            List<classSprite_Limb> lstLimbsSource = new List<classSprite_Limb>();
            lstLimbsSource.Add(cCostumeInfo_Default.cLimb_Master);
            List<Bitmap> lstBmp = draw_Animation_Frame(ref cSpriteData, lstLimbsSource);
            if (lstBmp.Count > 0)
                return lstBmp[0];
            else return null;
        }
        bool bolDrawAnimationFrame = false;

        public List<Bitmap> draw_Animation_Frame(ref classSpriteData cSpriteData, List<classSprite_Limb> lstLimbSources)
        {
            if (bolDrawAnimationFrame) return new List<Bitmap>();
            semDrawAnimation_Frame.WaitOne();
            bolDrawAnimationFrame = true;
            List<classSprite_Limb> lstDoNotDrawLimbs = new List<classSprite_Limb>();
            List<Bitmap> lstRetVal = new List<Bitmap>();

            if (cSpriteData.cAnimationData.cAnimation == null)
                cSpriteData.cAnimationData.cAnimation = cSpriteData.cAnimationData.cSprite.lstAnimations[0];

            classAnimation cAnimation = cSpriteData.cAnimationData.cAnimation;
            if (cAnimation == null)
            {
                lstRetVal.Add(new Bitmap(20, 20));
                semDrawAnimation_Frame.Release();
                bolDrawAnimationFrame = false;
                return lstRetVal;
            }

            if (cSpriteData.cAnimationData.intFrameIndex >= cAnimation.lstFrames.Count)
                cSpriteData.cAnimationData.intFrameIndex = 0;

            classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            classSprite_Limb cLimbDrawRelativeTo = cFrame.Limb_DrawRelativeTo >= 0
                                                                              ? cSpriteData.cCostumeInfo.lstLimbs[cFrame.Limb_DrawRelativeTo]
                                                                              : null;
            if (!cSpriteData.cCostumeInfo.lstLimbs.Contains(cLimbDrawRelativeTo))
            {
                if (cFrame.Limb_DrawRelativeTo >= 0)
                {
                    if (lstCostumeInfo.Count > 1)
                        cFrame.Limb_DrawRelativeTo = cSpriteData.cCostumeInfo.lstLimbs.IndexOf((classSprite_Limb)cSpriteData.cCostumeInfo.cBT_Limbs.Search(cLimbDrawRelativeTo.Name));
                    else
                        cFrame.Limb_DrawRelativeTo = cSpriteData.cCostumeInfo.lstLimbs.IndexOf(cSpriteData.cCostumeInfo.cLimb_Master);
                }
                else
                {
                    cFrame.Limb_DrawRelativeTo = cSpriteData.cCostumeInfo.lstLimbs.IndexOf(cSpriteData.cCostumeInfo.cLimb_Master);
                }
            }

            if (cSpriteData.cAnimationData.dblDrawSizeFactor <= 0) cSpriteData.cAnimationData.dblDrawSizeFactor = 1.0;
            DrawSizeFactor = cSpriteData.cAnimationData.dblDrawSizeFactor;
            cSpriteData.cCostumeInfo.cLimb_Master.DrawAngle = cSpriteData.cAnimationData.dblDrawAngle;

            if (cAnimation == null || cFrame == null)
            {
                semDrawAnimation_Frame.Release();
                bolDrawAnimationFrame = false;
                return null; /// adding a new frame results in a null frame in lstFrames ...
            }
            //Bitmap bmpRetVal = null;

            Size szBmpOutput = new Size();

            setFrameAnimationVariables(ref cSpriteData);//ref cAnimation, ref cFrame);

            if (UseRamCache
                && cFrame.cCache.DrawAngle == cSpriteData.cCostumeInfo.cLimb_Master.DrawAngle
                && cFrame.cCache.DrawSizeFactor == DrawSizeFactor
                && string.Compare(cFrame.cCache.strLimbDrawIndex, cFrame.strLimbDrawIndex_CacheTest) == 0)
            { // cached image good
                cSpriteData.cCostumeInfo.moveData();
                cSpriteData.cCostumeInfo.cDrawData_current = cFrame.cCache.cDrawData.Copy();
                lstRetVal.Add(cFrame.cCache.bmp);
                goto cacheExit;
            }

            cFrame.resetTLBR();
            setDrawPoints_PrePass(ref cSpriteData);
            setDrawPoints(ref cFrame, cSpriteData.cAnimationData.dblDrawAngle);

            cFrame.StandardSizeInitialized = true;

            szBmpOutput = new Size((int)(cFrame.ptBR.X - cFrame.ptTL.X), (int)(cFrame.ptBR.Y - cFrame.ptTL.Y));
            if (szBmpOutput.Width > 0 && szBmpOutput.Height > 0)
            {
                for (int intLimbSourceCounter = 0; intLimbSourceCounter < lstLimbSources.Count; intLimbSourceCounter++)
                {
                    classSprite_Limb cLimbSource = lstLimbSources[intLimbSourceCounter];
                    List<classSprite_Limb> lstLimbDraw = cLimbSource.Slaves_Get();

                    Bitmap bmpRetVal = new Bitmap(szBmpOutput.Width, szBmpOutput.Height);
                    Graphics g = Graphics.FromImage(bmpRetVal);
                    {
                        for (int intLimbCounter = 0; intLimbCounter < cFrame.lstDrawSequence.Count; intLimbCounter++)
                        {
                            classSprite_Limb cLimb = cFrame.lstDrawSequence[intLimbCounter] >= 0
                                                                                            ? cSpriteData.cCostumeInfo.lstLimbs[cFrame.lstDrawSequence[intLimbCounter]]
                                                                                            : null;
                            if (cLimb == null || cLimb.Hinge == null)
                                break;
                            if (lstLimbDraw.Contains(cLimb) && !lstDoNotDrawLimbs.Contains(cLimb))
                            {
                                Point ptDraw = new Point((int)((-cFrame.ptTL.X + cLimb.ptDrawCenter.X - cLimb.bmpDraw.Width * DrawSizeFactor / 2)),
                                                         (int)((-cFrame.ptTL.Y + cLimb.ptDrawCenter.Y - cLimb.bmpDraw.Height * DrawSizeFactor / 2)));

                                Rectangle recSource = new Rectangle(ptZero, cLimb.bmpDraw.Size);
                                Rectangle recDestination = new Rectangle(ptDraw,
                                                                         new Size((int)((double)cLimb.bmpDraw.Width * DrawSizeFactor),
                                                                                  (int)((double)cLimb.bmpDraw.Height * DrawSizeFactor)));

                                if (cLimb.Opacity != 255 && cLimb.ColorFilter.Valid)
                                {
                                    Bitmap bmpDraw =classGraphics.ColorFilter(classGraphics.DrawOpacity(cLimb.bmpDraw, (float)cLimb.Opacity / 255f), cLimb.ColorFilter.clr);
                                    g.DrawImage(bmpDraw, recDestination, recSource, GraphicsUnit.Pixel);
                                }
                                else if (cLimb.Opacity != 255)
                                {
                                    Bitmap bmpDraw = classGraphics.DrawOpacity(cLimb.bmpDraw, (float)cLimb.Opacity / 255f);
                                    g.DrawImage(bmpDraw, recDestination, recSource, GraphicsUnit.Pixel);
                                }
                                else if (cLimb.ColorFilter.Valid)
                                {
                                    Bitmap bmpDraw = classGraphics.ColorFilter(cLimb.bmpDraw, cLimb.ColorFilter.clr);
                                    g.DrawImage(bmpDraw, recDestination, recSource, GraphicsUnit.Pixel);
                                }
                                else
                                    g.DrawImage(cLimb.bmpDraw, recDestination, recSource, GraphicsUnit.Pixel);

                                //bmpRetVal.Save(@"c:\debug\bmpBuzNMick.png");
                            }
                        }
                    }
                    g.Dispose();
                    lstRetVal.Add(bmpRetVal);
                    lstDoNotDrawLimbs.AddRange(lstLimbDraw);
                }
                goto exitDraw_Animation;
            }
            else
            {
                lstRetVal.Add(new Bitmap(cSpriteData.cCostumeInfo.cLimb_Master.bmpDraw, cSpriteData.cCostumeInfo.cLimb_Master.bmpDraw.Size));
                cFrame.ptTL = ptZero;
                cFrame.ptBR = new Point(lstRetVal[0].Width, lstRetVal[0].Height);
                object objMasterLimb = (object)cSpriteData.cCostumeInfo.cLimb_Master;
            }

        exitDraw_Animation:
            if (cFrame.Limb_DrawRelativeTo < 0)
                cFrame.Limb_DrawRelativeTo = cSpriteData.cCostumeInfo.lstLimbs.IndexOf(cSpriteData.cCostumeInfo.cLimb_Master);

            // effect mirrors
            if (cFrame.Vertical_Mirror)
                Mirror_Vertical(ref cSpriteData, ref lstRetVal);

            if (cFrame.Horizontal_Mirror)
                Mirror_Horizontal(ref cSpriteData, ref lstRetVal);

            Bitmap bmpRef = lstRetVal[0];
            setSpriteDataInfo(ref cSpriteData, ref bmpRef);

        cacheExit:
            setSpriteData_PT(ref cSpriteData);

            /// cached image
            cFrame.cCache.strLimbDrawIndex = cFrame.strLimbDrawIndex_CacheTest;
            cFrame.cCache.DrawAngle = cSpriteData.cCostumeInfo.cLimb_Master.DrawAngle;
            cFrame.cCache.DrawSizeFactor = DrawSizeFactor;
            cFrame.cCache.cDrawData = cSpriteData.cCostumeInfo.cDrawData_current.Copy();
            cFrame.cCache.bmp = lstRetVal[0];

            semDrawAnimation_Frame.Release();
            bolDrawAnimationFrame = false;
            return lstRetVal;
        }

        public void Mirror_Horizontal(ref classSpriteData cSpriteData, ref List<Bitmap> lstImages)
        {
            classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            cFrame.ptTL.X = -(cFrame.ptTL.X + lstImages[0].Width);
            cFrame.ptBR.X = lstImages[0].Width + cFrame.ptTL.X;

            for (int intRetValCounter = 0; intRetValCounter < lstImages.Count; intRetValCounter++)
                lstImages[intRetValCounter].RotateFlip(RotateFlipType.RotateNoneFlipX);
            for (int intLimbCounter = 0; intLimbCounter < cSpriteData.cCostumeInfo.lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb = cSpriteData.cCostumeInfo.lstLimbs[intLimbCounter];
                cLimb.ptDrawCenter_X *= -1;

                classAnimation_Frame_LimbData cLimbData = cFrame.lstDataOverride[intLimbCounter];
                cLimbData.ptDrawCenter = cLimb.ptDrawCenter_StandardSize;
            }

            for (int intDataCounter = 0; intDataCounter < cFrame.lstData.Count; intDataCounter++)
            {
                classAnimation_Frame_LimbData cData = cFrame.lstDataOverride[intDataCounter];
                cData.ptDrawCenter = new Point(cData.ptDrawCenter.X * -1, cData.ptDrawCenter.Y);
                cData.ptDrawHinge = new Point(cData.ptDrawHinge.X * -1, cData.ptDrawHinge.Y);
            }

        }
        public void Mirror_Vertical(ref classSpriteData cSpriteData, ref List<Bitmap> lstImages)
        {
            classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            cFrame.ptTL.Y = -(cFrame.ptTL.Y + lstImages[0].Height);
            cFrame.ptBR.Y = lstImages[0].Height + cFrame.ptTL.Y;
            for (int intRetValCounter = 0; intRetValCounter < lstImages.Count; intRetValCounter++)
                lstImages[intRetValCounter].RotateFlip(RotateFlipType.RotateNoneFlipY);

            for (int intLimbCounter = 0; intLimbCounter < cSpriteData.cCostumeInfo.lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb = cSpriteData.cCostumeInfo.lstLimbs[intLimbCounter];
                cLimb.ptDrawCenter_Y *= -1;
                classAnimation_Frame_LimbData cLimbData = cFrame.lstDataOverride[intLimbCounter];
                cLimbData.ptDrawCenter = cLimb.ptDrawCenter_StandardSize;//.ptDrawCenter;
            }

            for (int intDataCounter = 0; intDataCounter < cFrame.lstData.Count; intDataCounter++)
            {
                classAnimation_Frame_LimbData cData = cFrame.lstDataOverride[intDataCounter];
                cData.ptDrawCenter = new Point(cData.ptDrawCenter.X, cData.ptDrawCenter.Y * -1);
                cData.ptDrawHinge = new Point(cData.ptDrawHinge.X, cData.ptDrawHinge.Y * -1);
            }
        }

        /// <summary>
        /// uses the classSpriteData and its record of the sprite's previous position to calculate its next location at the end of this frame
        /// </summary>
        /// <param name="cSpriteData">record of two Recursions of the sprite's position used to calculate the current position </param>
        /// <param name="cFrame">the Animation Frame that has just been drawn</param>
        public void setSpriteData_PT(ref classSpriteData cSpriteData)
        {
            classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            if (cSpriteData.cCostumeInfo.cDrawData_current.cFrame == null)
                cSpriteData.cCostumeInfo.cDrawData_current.cFrame = cFrame;
            if (cSpriteData.cCostumeInfo.cDrawData_old.cFrame != null)
            {
                classSprite_Limb cLimb_RelPrevious = cSpriteData.cCostumeInfo.lstLimbs[cSpriteData.cCostumeInfo.cDrawData_old.cFrame.Limb_DrawRelativeTo];
                classSprite_Limb cLimb_RelCurrent = cSpriteData.cCostumeInfo.lstLimbs[cFrame.Limb_DrawRelativeTo];

                object objPoint = cSpriteData.cCostumeInfo.cDrawData_current.cBT_LimbPositions.Search(cLimb_RelPrevious.Name);
                if (objPoint == null)
                {
                    Point pt = new Point();
                    objPoint = (object)pt;
                }
                Point ptLimb_RelPrevious = (Point)objPoint;

                objPoint = cSpriteData.cCostumeInfo.cDrawData_current.cBT_LimbPositions.Search(cLimb_RelCurrent.Name);
                if (objPoint == null)
                {
                    Point pt = new Point();
                    objPoint = (object)pt;
                }
                Point ptLimb_RelCurrent = (Point)objPoint;

                cSpriteData.cCostumeInfo.cDrawData_current.ptTransition = classMath3.SubTwoPoints(ptLimb_RelCurrent, ptLimb_RelPrevious);
            }
            cSpriteData.pt = classMath3.AddTwoPoints(cSpriteData.pt, cSpriteData.cCostumeInfo.cDrawData_current.ptTransition);
        }

        /// <summary>
        /// records the sprite's current position, frame and bitmap into the classSpriteData for in order to use it 
        /// in the setDataSprite_PT function that positions the sprite after every Animation Frame has been drawn
        /// </summary>
        /// <param name="cSpriteData">a record of the sprite's position used to generate its next position</param>
        /// <param name="cFrame">the Animation Frame after which this data is being recorded</param>
        /// <param name="bmp">output bitmap of this frame</param>
        public void setSpriteDataInfo(ref classSpriteData cSpriteData, ref Bitmap bmp)
        {
            // cFrame.ptTL is the distance NW away from masterLimb (-, -)
            classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            cSpriteData.cCostumeInfo.moveData();
            cSpriteData.cCostumeInfo.cDrawData_current.bmp = bmp;
            cSpriteData.cCostumeInfo.cDrawData_current.cFrame = cFrame;
            RectangleF recBitmap = new RectangleF(ptZero, new Size(cFrame.ptBR.X - cFrame.ptTL.X, cFrame.ptBR.Y - cFrame.ptTL.Y));
            if (cSpriteData.cCostumeInfo.cDrawData_current.cBT_LimbPositions != null)
                cSpriteData.cCostumeInfo.cDrawData_current.cBT_LimbPositions = null;
            cSpriteData.cCostumeInfo.cDrawData_current.cBT_LimbPositions = new BinTree.classBinTree();
            cSpriteData.cCostumeInfo.cDrawData_current.cQT_LimbPositions = new classQuadTree(recBitmap);
            // record limbpositions relative to TL of bitmap

            for (int intLimbCounter = 0; intLimbCounter < cFrame.lstDrawSequence.Count; intLimbCounter++)
            {
                int intLimbIndex = cFrame.lstDrawSequence[intLimbCounter];
                classSprite_Limb cLimb = intLimbIndex >= 0
                                                       ? cSpriteData.cCostumeInfo.lstLimbs[intLimbIndex]
                                                       : null;
                if (cLimb == null) cLimb = cSpriteData.cCostumeInfo.cLimb_Master;

                Point ptLimb = classMath3.SubTwoPoints(cLimb.ptDrawCenter, cFrame.ptTL);
                object objPt = (object)ptLimb;
                cSpriteData.cCostumeInfo.cDrawData_current.cBT_LimbPositions.Insert(ref objPt, cLimb.Name);

                object objLimb = (object)cLimb;
                if (!cSpriteData.cCostumeInfo.cDrawData_current.cQT_LimbPositions.Insert(new PointF(ptLimb.X, ptLimb.Y), ref objLimb))
                    if (ShowErrorMessages)
                        MessageBox.Show("Failed to insert " + cLimb.Name + " point into QuadTree");
            }
        }

        /// <summary>
        /// goes over the DrawSequence, and sets the boolean variable SetDrawPosition of each limb if its position is relevant to the position of 
        /// itself or any other limb that is to be drawn in the current Animation Frame
        /// </summary>
        /// <param name="lstDrawSequence">list of limbs that are to be drawn in the current Animation Frame</param>
        void setDrawPoints_PrePass(ref classSpriteData cSpriteData)
        {
            classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
            if (cFrame.StandardSizeInitialized && cFrame.DrawAngle == cSpriteData.cAnimationData.dblDrawAngle) return;

            List<int> lstDrawSequence = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex].lstDrawSequence;

            for (int intLimbCounter = 0; intLimbCounter < cSpriteData.cCostumeInfo.lstLimbs.Count; intLimbCounter++)
            {
                cSpriteData.cCostumeInfo.lstLimbs[intLimbCounter].SetDrawPosition = false; // DEBUG HERE
                cSpriteData.cCostumeInfo.lstLimbs[intLimbCounter].ptDrawCenter = ptZero;
            }
            for (int intLimbCounter = 0; intLimbCounter < lstDrawSequence.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb = lstDrawSequence[intLimbCounter] >= 0
                                                                            ? cSpriteData.cCostumeInfo.lstLimbs[lstDrawSequence[intLimbCounter]]
                                                                            : null;
                if (cLimb == null) break;
                cLimb.SetDrawPosition = true;

                if (cLimb == cSpriteData.cCostumeInfo.cLimb_Master)
                    break;
                if (cLimb.Hinge != null)
                {
                    classSprite_Limb cLimbThisMaster = cLimb.Hinge.Limb_Master;

                    while (cLimbThisMaster != cSpriteData.cCostumeInfo.cLimb_Master
                        && !cLimbThisMaster.SetDrawPosition)
                    {
                        cLimbThisMaster.SetDrawPosition = true;
                        cLimbThisMaster = cLimbThisMaster.Hinge.Limb_Master;
                    }
                }
            }
            cSpriteData.cCostumeInfo.cLimb_Master.SetDrawPosition = true;

            /*// debug start
            for (int intLimbCounter = 0; intLimbCounter < lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimbTest = lstLimbs[intLimbCounter];
                System.Diagnostics.Debug.Print(cLimbTest.Name.PadRight(40, ' ')+" :" + cLimbTest.SetDrawPosition.ToString());
            }
            // */
            // debug stop
        }

        static bool bolEditor = false;
        static public bool Editor
        {
            get { return bolEditor; }
            set { bolEditor = value; }
        }

        public void setDrawPoints(ref classAnimation_Frame cFrame, double dblDrawAngle)
        {
            classAnimation cAnimation = cFrame.Animation;
            classSprite_Limb cMasterLimb = cCostumeInfo_Default.cLimb_Master;

            if (Editor
                || !cFrame.StandardSizeInitialized
                || cFrame.DrawAngle != dblDrawAngle)
            {
                IEnumerable<classAnimation_Frame_LimbData> ieFrameData = cFrame.lstDataOverride.OrderBy(framedata => framedata.intLimbIndex);
                cFrame.lstDataOverride = (List<classAnimation_Frame_LimbData>)ieFrameData.ToList();

                cFrame.lstDataOverride[cMasterLimb.intMyIndex].DrawAngle = dblDrawAngle;
                setDrawPoints_TrigMethod(ref cMasterLimb, ref cFrame);
                cFrame.DrawAngle = dblDrawAngle;
            }

            cFrame.ptTL_StandardSize = new Point();
            cFrame.ptBR_StandardSize = new Point();

            for (int intLimbCounter = 0; intLimbCounter < cFrame.lstData.Count; intLimbCounter++)
            {
                //
                classSprite_Limb cLimb = cCostumeInfo_Default.lstLimbs[intLimbCounter];
                classAnimation_Frame_LimbData cFrameData = cFrame.getOverrideData( cLimb.Name);

                cLimb.bmpDraw = cLimb.GetImage(cFrameData.DrawAngle);
                Bitmap bmpLimb = cLimb.bmpDraw;

                cLimb.ptDrawCenter_StandardSize = cFrameData.ptDrawCenter;
                cLimb.ptDrawCenter = classMath3.Point_FactorSize(cFrameData.ptDrawCenter, (float)DrawSizeFactor);
                cLimb.DrawAngle = cFrameData.DrawAngle;
                cLimb.ptHingeDrawCenter = classMath3.Point_FactorSize(cFrameData.ptDrawHinge, (float)DrawSizeFactor);
                cLimb.Opacity = cFrameData.Opacity;
                cLimb.ColorFilter = cFrameData.ColorFilter;

                if (cFrame.ptTL_StandardSize.X > cFrameData.ptDrawCenter.X - bmpLimb.Width / 2)
                    cFrame.ptTL_StandardSize.X = cFrameData.ptDrawCenter.X - bmpLimb.Width / 2;
                if (cFrame.ptTL_StandardSize.Y > cFrameData.ptDrawCenter.Y - bmpLimb.Height / 2)
                    cFrame.ptTL_StandardSize.Y = cFrameData.ptDrawCenter.Y - bmpLimb.Height / 2;

                if (cFrame.ptBR_StandardSize.X < cFrameData.ptDrawCenter.X + bmpLimb.Width / 2)
                    cFrame.ptBR_StandardSize.X = cFrameData.ptDrawCenter.X + bmpLimb.Width / 2;
                if (cFrame.ptBR_StandardSize.Y < cFrameData.ptDrawCenter.Y + bmpLimb.Height / 2)
                    cFrame.ptBR_StandardSize.Y = cFrameData.ptDrawCenter.Y + bmpLimb.Height / 2;
            }

            cFrame.ptBR = classMath3.Point_FactorSize(cFrame.ptBR_StandardSize, (float)DrawSizeFactor);
            cFrame.ptTL = classMath3.Point_FactorSize(cFrame.ptTL_StandardSize, (float)DrawSizeFactor);
        }

        public static bool bolDebug = false;
        void setDrawPoints_TrigMethod(ref classSprite_Limb cLimb, ref classAnimation_Frame cFrame)
        {
            classAnimation cAnimation = cFrame.Animation;
            if (cLimb != null
                && cLimb.SetDrawPosition
                && cLimb.Hinge != null
                && cLimb.Hinge.Limb_Master != null)
            {
                /*
                string strName = cLimb.Name;

                classAnimation_Frame_LimbData cFrameData_Master = cFrame.lstData[cLimb.Hinge.Limb_Master.intMyIndex];

                Point ptMaster = cFrameData_Master.ptDrawCenter;
                Point ptMaster_HingeLocation = classMath3.AddTwoPoints(ptMaster,
                                                                       classMath3.RadToPt(cLimb.Hinge.Contact.Master,
                                                                                          -cFrameData_Master.DrawAngle));

                classAnimation_Frame_LimbData cFrameData_Limb = cFrame.lstData[cLimb.intMyIndex];
                cFrameData_Limb.DrawAngle = cFrameData_Master.DrawAngle + cFrameData_Limb.Angle;

                cLimb.bmpDraw = cLimb.GetImage(cFrameData_Limb.DrawAngle);

                classRadialCoordinate cRadVectorSlaveHinge
                    = new classRadialCoordinate(cLimb.Hinge.Contact.Slave.Radians - cFrameData_Limb.Angle - cFrameData_Master.DrawAngle,
                                                cLimb.Hinge.Contact.Slave.Magnitude * cFrameData_Limb.SlaveContactMagnitude_Factor);

                Point ptVectorSlaveHinge = classMath3.RadToPt(cRadVectorSlaveHinge, 0);
                cFrameData_Limb.ptDrawCenter = classMath3.AddTwoPoints(ptMaster_HingeLocation, ptVectorSlaveHinge);
                cFrameData_Limb.ptDrawHinge = classMath3.SubTwoPoints(cFrameData_Limb.ptDrawCenter, ptVectorSlaveHinge);
                /*/
                string strName = cLimb.Name;

                classAnimation_Frame_LimbData cFrameData_Master = cFrame.getOverrideData(cLimb.Hinge.Limb_Master.Name);// .lstDataOverride[cLimb.Hinge.Limb_Master.intMyIndex];

                Point ptMaster = cFrameData_Master.ptDrawCenter;
                Point ptMaster_HingeLocation = classMath3.AddTwoPoints(ptMaster,
                                                                       classMath3.RadToPt(cLimb.Hinge.Contact.Master,
                                                                                          -cFrameData_Master.DrawAngle));

                classAnimation_Frame_LimbData cFrameData_Limb = cFrame.getOverrideData(cLimb.Name);//.lstDataOverride[cLimb.intMyIndex];
                cFrameData_Limb.DrawAngle = cFrameData_Master.DrawAngle + cFrameData_Limb.Angle;
                cLimb.intImageList_Index = cFrameData_Limb.ImageList_Index;
                cLimb.bmpDraw = cLimb.GetImage(cFrameData_Limb.DrawAngle);

                classRadialCoordinate cRadVectorSlaveHinge
                    = new classRadialCoordinate(cLimb.Hinge.Contact.Slave.Radians - cFrameData_Limb.Angle - cFrameData_Master.DrawAngle,
                                                cLimb.Hinge.Contact.Slave.Magnitude * cFrameData_Limb.SlaveContactMagnitude_Factor);

                classAnimation_Frame_LimbData cFrameData = cFrame.getData(cLimb.Name);

                Point ptVectorSlaveHinge = classMath3.RadToPt(cRadVectorSlaveHinge, 0);
                
                //cFrame.lstData[cLimb.intMyIndex].ptDrawCenter 
                cFrameData.ptDrawCenter 
                    = cFrameData_Limb.ptDrawCenter 
                    = cLimb.ptDrawCenter
                    = classMath3.AddTwoPoints(ptMaster_HingeLocation, ptVectorSlaveHinge);

                //cFrame.lstData[cLimb.intMyIndex].ptDrawHinge 
                cFrameData.ptDrawHinge 
                    = cFrameData_Limb.ptDrawHinge 
                    = cLimb.ptHingeDrawCenter
                    = classMath3.SubTwoPoints(cFrameData_Limb.ptDrawCenter, ptVectorSlaveHinge);

                
                //*/
            }
            else
            { // master hinge
                cLimb.bmpDraw = cLimb.lstImages[cLimb.intImageList_Index].bmpImages[0];
            }

            for (int intSlaveCounter = 0; intSlaveCounter < cLimb.lstHinge_Slaves.Count; intSlaveCounter++)
            {
                classSprite_Limb cLimb_Slave = cLimb.lstHinge_Slaves[intSlaveCounter].Limb_Slave;
                setDrawPoints_TrigMethod(ref cLimb_Slave, ref cFrame);
            }

        }
    }

    /// <summary>
    /// contains a list of limbs - their rotated images and hinge information
    /// </summary>
    public class classSprite_CostumeInfo
    {
        public string SpriteName = "spriteName";
        public string Name = "Default_Costume";

        public classSprite_CostumeInfo(string strSpriteName)
        {
            SpriteName = strSpriteName;

            cDrawData[0] = new classDrawData();
            cDrawData[1] = new classDrawData();
        }

        /// <summary>
        /// alpha tree used to search and retrieve limbs by name
        /// </summary>
        //public BinTree.classBinTree cBT_Limbs = new BinTree.classBinTree();
        public classBinTree cBT_Limbs = new classBinTree();

        /// <summary>
        /// list of limbs redundant to the cBT_Limbs alpha tree.
        /// used to quickly assess the number of limbs sprite currently has
        /// </summary>
        public List<classSprite_Limb> lstLimbs = new List<classSprite_Limb>();

        /// <summary>
        /// Sprite's master limb around which all other limbs branch out
        /// </summary>
        public classSprite_Limb cLimb_Master = null;


        /// <summary>
        /// transitions cDrawData's current to last before overwriting old data with latest frame_drawn information
        /// </summary>
        public void moveData() { intIndex = (intIndex + 1) % 2; }


        /// <summary>
        /// used internally to keep track of this sprite's current & previous drawn frame/position information 
        /// </summary>
        classDrawData[] cDrawData = new classDrawData[2];
        int intIndex = 0;
        /// <summary>
        /// returns the sprite's data valid for the current draw Recursion
        /// </summary>
        public classDrawData cDrawData_current
        {
            get { return cDrawData[intIndex]; }
            set { cDrawData[intIndex] = value; }
        }

        /// <summary>
        /// returns the sprite's data valid for the previous draw Recursion
        /// </summary>
        public classDrawData cDrawData_old
        {
            get { return cDrawData[(intIndex + 1) % 2]; }
        }

        public void Limb_Rename(string strName_Old, string strName_New)
        {
            classSprite_Limb cLimb_renamed = (classSprite_Limb)cBT_Limbs.Search(strName_Old);
            if (cLimb_renamed != null)
                cLimb_renamed.Name = strName_New;
        }

        public classSprite_CostumeInfo Copy()
        {
            classSprite_CostumeInfo cRetVal = new classSprite_CostumeInfo(SpriteName);

            for (int intLimbCounter = 0; intLimbCounter < lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimbCopy = lstLimbs[intLimbCounter].Copy();
                object objLimbCopy = (Object)cLimbCopy;
                cRetVal.cBT_Limbs.Insert(ref objLimbCopy, cLimbCopy.Name);
                cLimbCopy.cCostumeInfo = cRetVal;
                cRetVal.lstLimbs.Add(cLimbCopy);
            }

            // for each limb copy their slave-limbs
            for (int intLimbCounter = 0; intLimbCounter < lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb_Original = lstLimbs[intLimbCounter];
                classSprite_Limb cLimb_Copy = cRetVal.lstLimbs[intLimbCounter];

                for (int intHingeCounter = 0; intHingeCounter < cLimb_Original.lstHinge_Slaves.Count; intHingeCounter++)
                {
                    classSprite_Hinge cHinge_Original = cLimb_Original.lstHinge_Slaves[intHingeCounter];
                    classSprite_Limb cLimbOriginal_Slave = cHinge_Original.Limb_Slave;
                    int intIndexSlaveLimb = cLimbOriginal_Slave != null
                                                                 ? lstLimbs.IndexOf(cLimbOriginal_Slave)
                                                                 : -1;
                    classSprite_Limb cLimbCopy_Slave = intIndexSlaveLimb >= 0
                                                                         ? cRetVal.lstLimbs[intIndexSlaveLimb]
                                                                         : null;
                    if (cLimbCopy_Slave != null)
                    {
                        classSprite_Hinge cHinge_Copy = cLimbCopy_Slave.Hinge; //new classSprite_Hinge(ref cLimbCopy_Slave.cSprite, ref cLimbCopy_Slave, ref cLimb_Copy);

                        cHinge_Copy.Contact.Master.Radians = cHinge_Original.Contact.Master.Radians;
                        cHinge_Copy.Contact.Master.Magnitude = cHinge_Original.Contact.Master.Magnitude;
                        cHinge_Copy.Contact.Slave.Radians = cHinge_Original.Contact.Slave.Radians;
                        cHinge_Copy.Contact.Slave.Magnitude = cHinge_Original.Contact.Slave.Magnitude;
                        cHinge_Copy.Limb_Slave = cLimbCopy_Slave;
                        cHinge_Copy.Limb_Master = cLimb_Copy;

                        cLimb_Copy.lstHinge_Slaves.Add(cHinge_Copy);
                    }
                }
            }

            cRetVal.cLimb_Master = (classSprite_Limb)cRetVal.cBT_Limbs.Search(cLimb_Master.Name);
            return cRetVal;
        }

        public void MatchDefault(ref classSprite cSprite)
        {
            //          match limbs list

            classBinTree cBT_Limbs_New = new classBinTree();
            lstLimbs.Clear();
            for (int intLimbCounter = 0; intLimbCounter < cSprite.cCostumeInfo_Default.lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb_Default = cSprite.cCostumeInfo_Default.lstLimbs[intLimbCounter];
                classSprite_Limb cLimb = (classSprite_Limb)cBT_Limbs.Search(cLimb_Default.Name);
                if (cLimb == null)
                {
                    cLimb = cLimb_Default.Copy();
                    cLimb.cCostumeInfo = this;
                }
                object objLimb = (object)cLimb;
                cBT_Limbs_New.Insert(ref objLimb, cLimb.Name);
                lstLimbs.Add(cLimb);
            }

            // set new alpha-tree
            if (cBT_Limbs != null)
                cBT_Limbs = null;
            cBT_Limbs = cBT_Limbs_New;

            // reproduce hinges for each limb
            for (int intLimbCounter = 0; intLimbCounter < cSprite.cCostumeInfo_Default.lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb_Default = cSprite.cCostumeInfo_Default.lstLimbs[intLimbCounter];
                classSprite_Limb cLimb = lstLimbs[intLimbCounter];

                List<classSprite_Hinge> lstHinge_Slaves_New = new List<classSprite_Hinge>();

                for (int intSlaveHinges = 0; intSlaveHinges < cLimb_Default.lstHinge_Slaves.Count; intSlaveHinges++)
                {
                    classSprite_Hinge cHinge_Default = cLimb_Default.lstHinge_Slaves[intSlaveHinges];
                    classSprite_Limb cLimb_Slave_Default = cHinge_Default.Limb_Slave;
                    classSprite_Limb cLimb_Slave = (classSprite_Limb)cBT_Limbs.Search(cLimb_Slave_Default.Name);

                    classSprite_Hinge cHinge_Slave = cLimb.GetSlaveHinge(ref cLimb_Slave);

                    if (cHinge_Slave == null)
                    {
                        // was not found in existing list of slave-hinges -> create a new hinge
                        cHinge_Slave = new classSprite_Hinge(ref cSprite, ref cLimb_Slave, ref cLimb);
                        cHinge_Slave.Contact.Master = cHinge_Default.Contact.Master.Copy();
                        cHinge_Slave.Contact.Slave = cHinge_Default.Contact.Slave.Copy();
                    }

                    cLimb_Slave.Hinge = cHinge_Slave;
                    lstHinge_Slaves_New.Add(cHinge_Slave);
                }
                cLimb.lstHinge_Slaves = lstHinge_Slaves_New;
            }
        }

        /// <summary>
        /// classDrawData is stored in an array cDrawData[2] to keep track of current and previous draw Recursions
        /// and are accessed to generate the ptTransition information that facilitates drawing a sprite relative to a stationary limb not the MasterLimb
        /// </summary>
        public class classDrawData
        {
            /// <summary>
            /// this draw Recursion's bitmap
            /// </summary>
            Bitmap _bmp;
            public Bitmap bmp
            {
                get { return _bmp; }
                set
                {
                    if (_bmp != null)
                        _bmp.Dispose();
                    _bmp = value;
                }
            }


            /// <summary>
            /// this draw Recursion's animation frame information
            /// animation frames are designed in the SpriteEditor.  any changes during runTime will not be saved except by the SpriteEditor
            /// </summary>
            public classAnimation_Frame cFrame;

            /// <summary>
            /// alpha tree of limb names that returns the limbs' current location on ouput bitmap
            /// </summary>
            public BinTree.classBinTree cBT_LimbPositions; // 

            /// <summary>
            /// quad tree of limb positions that returns the limb requested for collision detection purposes
            /// </summary>
            public classQuadTree cQT_LimbPositions;     // 

            /// <summary>
            /// used internally by classSprite.Draw_Animation_Frame() to move classSpriteData's pt 
            /// facilitating the drawing of sprites when their animations position them relative to a specific limb
            /// </summary>
            public Point ptTransition;                  // 

            public classDrawData Copy()
            {
                classDrawData cRetVal = new classDrawData();
                cRetVal.bmp = bmp;
                cRetVal.cBT_LimbPositions = cBT_LimbPositions;
                cRetVal.cFrame = cFrame;
                cRetVal.cQT_LimbPositions = cQT_LimbPositions;
                cRetVal.ptTransition = new Point(ptTransition.X, ptTransition.Y);

                return cRetVal;
            }
        }
    }

    /// <summary>
    /// an articulating limb of a sprite
    /// </summary>
    public class classSprite_Limb
    {
        public const string ValidLimbNameChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_ .0123456789";

        static int intIDCounter = 0;

        int intID = intIDCounter++;
        public int ID
        {
            get { return intID; }
        }

        /// <summary>
        /// sprite to which this limb belongs
        /// </summary>
        public classSprite cSprite = null;
        public classSprite_CostumeInfo cCostumeInfo = null;
        public int intMyIndex
        {
            get
            {
                if (cCostumeInfo == null) return -1;
                return cCostumeInfo.lstLimbs.IndexOf(this);
            }
        }


        byte bytOpacity = 255;
        public byte Opacity
        {
            get { return bytOpacity; }
            set { bytOpacity = value; }
        }


        classAnimation_Frame_LimbData.classColorFilter _ColorFilter = null;
        public classAnimation_Frame_LimbData.classColorFilter ColorFilter
        {
            get { return _ColorFilter; }
            set { _ColorFilter = value; }
        }


        public List<classSprite_Limb> Slaves_Get()
        {
            List<classSprite_Limb> lstRetVal = new List<classSprite_Limb>();
            lstRetVal.Add(this);
            for (int intSlaveCounter = 0; intSlaveCounter < lstHinge_Slaves.Count; intSlaveCounter++)
                lstRetVal.AddRange(lstHinge_Slaves[intSlaveCounter].Limb_Slave.Slaves_Get());

            return lstRetVal;
        }


        /// <summary>
        /// default name of limb image in limbImage list, each of which have 128 rotated variations
        /// </summary>
        public const string conDefaultLimbImageName = "default";

        /// <summary>
        /// creates a new limb
        /// </summary>
        /// <param name="name">name of newly created limb</param>
        /// <param name="Sprite">sprite to which this limb belongs</param>
        /// <param name="bmp">bitmap needed to draw the new limb</param>
        /// <returns>a new limb</returns>
        public static classSprite_Limb New(string name, ref classSprite Sprite, Bitmap bmp) { return New(name, ref Sprite, bmp, null); }


        /// <summary>
        /// creates a new limb
        /// </summary>
        /// <param name="name">name of newly created limb</param>
        /// <param name="Sprite">sprite to which this limb belongs</param>
        /// <param name="bmp">bitmap needed to draw the new limb</param>
        /// <param name ="progressReport_EventHandler">event handler to be called for progress reports</param>
        /// <returns>a new limb</returns>
        public static classSprite_Limb New(string name, ref classSprite Sprite, Bitmap bmp, EventHandler progressReport_EventHandler)
        {
            classSprite_Limb cLimbInAT = null;

            if (Sprite != null
                && Sprite.cCostumeInfo_Default.cBT_Limbs != null)
                cLimbInAT = (classSprite_Limb)Sprite.cCostumeInfo_Default.cBT_Limbs.Search(name);
            if (cLimbInAT != null)
            {
                if (classSprite.ShowErrorMessages)
                    MessageBox.Show("Name of limb must be unique.  This sprite already has a limb named :" + name);
                return cLimbInAT;
            }
            return new classSprite_Limb(name, ref Sprite, bmp);
        }

        /// <summary>
        /// creates a new limb
        /// </summary>
        /// <param name="name">name of new limb to be created</param>
        /// <param name="Sprite">sprite to which this new limb belongs</param>
        /// <returns>returns the newly created limb with no image to draw it</returns>
        public static classSprite_Limb New(string name, ref classSprite Sprite)
        {
            if (Sprite != null)
            {
                classSprite_Limb cLimbInAT = (classSprite_Limb)Sprite.cCostumeInfo_Default.cBT_Limbs.Search(name);
                if (cLimbInAT != null)
                {
                    if (classSprite.ShowErrorMessages)
                        MessageBox.Show("Name of limb must be unique.  This sprite already has a limb named :" + name);
                    return cLimbInAT;
                }
            }
            return new classSprite_Limb(name, ref Sprite);
        }

        /// <summary>
        /// item in list of limb images.
        /// one version of a limb's Costume
        /// </summary>
        public class classSprite_Limb_Images
        {
            public string Name = conDefaultLimbImageName;
            public Bitmap[] bmpImages = null;

            public classSprite_Limb_Images Copy()
            {
                classSprite_Limb_Images cRetVal = new classSprite_Limb_Images();

                cRetVal.Name = Name;
                cRetVal.bmpImages = new Bitmap[bmpImages.Length];

                for (int intImageCounter = 0; intImageCounter < bmpImages.Length; intImageCounter++)
                    cRetVal.bmpImages[intImageCounter] = bmpImages[intImageCounter] != null
                                                                                      ? (Bitmap)new Bitmap(bmpImages[intImageCounter])
                                                                                      : null;

                return cRetVal;
            }
        }


        bool bolSetDrawPosition = false;
        /// <summary>
        /// is set in DrawAnimation_Frame() pre-pass to determine whether or not this limb's position is relevant
        /// to the output image for that particular Animation/Frame
        /// </summary>
        public bool SetDrawPosition
        {
            get {
                return bolSetDrawPosition; }
            set
            {
                bolSetDrawPosition = value;
            }
        }

        bool bolDisplayPosition = false;
        /// <summary>
        /// used by the SpriteEditor to User-Interface
        /// </summary>
        public bool DisplayPosition
        {
            get { return bolDisplayPosition; }
            set
            {
                bolDisplayPosition = value;
            }
        }
        public classSpriteMaker.classLoadLimbsInfo cLoadInfo = null;


        /// <summary>
        /// index of limbImage this limb currently uses
        /// </summary>
        int _intImageList_Index = 0;
        public int intImageList_Index
        {
            get { return _intImageList_Index; }
            set { _intImageList_Index = value; }
        }

        /// <summary>
        /// list of limb's images 
        /// each item in list has its own Costume and 128 rotated images to alter this limb's Costume
        /// </summary>
        public List<classSprite_Limb_Images> lstImages = new List<classSprite_Limb_Images>();

        /// <summary>
        /// instantiates a new limb
        /// </summary>
        /// <param name="name">name of the new limb</param>
        /// <param name="Sprite">sprite to which the new limb belongs</param>
        /// <param name="bmp">base image of the new limb used to generate all 128 of base image's rotated instances of itself</param>
        classSprite_Limb(string name, ref classSprite Sprite, Bitmap bmp)
        {
            cSprite = Sprite;
            cCostumeInfo = cSprite.cCostumeInfo_Default;
            strLimbName = name;
            classSprite_Limb_Images cImages = new classSprite_Limb_Images();
            int intNumImagesPerQuadrant = Sprite != null
                                        ? Sprite.NumImagesPerQuadrant
                                        : classSpriteMaker.conNumImagesPerQuadrant;

            cImages.bmpImages = new Bitmap[intNumImagesPerQuadrant * 4];
            cImages.bmpImages[0] = bmp;
            lstImages.Add(cImages);

            GenerateFirstQuadrantImages(ref cImages, intNumImagesPerQuadrant);

            object objThis = (object)this;
            if (Sprite != null)
            {
                Sprite.cCostumeInfo_Default.cBT_Limbs.Insert(ref objThis, name);
                Sprite.cCostumeInfo_Default.lstLimbs.Add(this);
            }

        }

        /// <summary>
        /// creates a new limb
        /// </summary>
        /// <param name="name">name of new limb to be created</param>
        /// <param name="Sprite">sprite to which this limb belongs</param>
        classSprite_Limb(string name, ref classSprite Sprite)
        {
            cSprite = Sprite;
            strLimbName = name;
            classSprite_Limb_Images cImages = new classSprite_Limb_Images();
            lstImages.Add(cImages);
            lstImages[intImageList_Index].bmpImages = new Bitmap[(cSprite != null
                                                                           ? cSprite.NumImagesPerQuadrant
                                                                           : classSpriteMaker.conNumImagesPerQuadrant) * 4];
            if (Sprite != null)
            {
                cSprite.cCostumeInfo_Default.lstLimbs.Add(this);
                object objThis = (object)this;
                Sprite.cCostumeInfo_Default.cBT_Limbs.Insert(ref objThis, name);
            }
        }

        public classSprite_Limb()
        { }


        /// <summary>
        /// keeps list of LimbImages in tree to quick retrieval
        /// </summary>
        public BinTree.classBinTree cBT_LimbImages = new BinTree.classBinTree();

        /// <summary>
        /// add a new base image to existing list of limb images - a variation in this limb's Costume
        /// </summary>
        /// <param name="strName"></param>
        /// <param name="bmp"></param>
        public classSprite_Limb_Images ListImages_Add(string strName, Bitmap bmp)
        {
            classSprite_Limb_Images cLimbImages = new classSprite_Limb_Images();
            cLimbImages.Name = strName;

            object obLimbImage = (object)cLimbImages;
            cBT_LimbImages.Insert(ref obLimbImage, cLimbImages.Name);

            cLimbImages.bmpImages = new Bitmap[4 * cSprite.NumImagesPerQuadrant];
            cLimbImages.bmpImages[0] = bmp;
            GenerateFirstQuadrantImages(ref cLimbImages, cSprite.NumImagesPerQuadrant);
            lstImages.Add(cLimbImages);

            return cLimbImages;
        }

        /// <summary>
        /// rotates the limb's base image 32 times from 0-Pi/2 radians
        /// </summary>
        void GenerateFirstQuadrantImages()
        {
            classSprite_Limb_Images cLimbImages = lstImages[0];
            GenerateFirstQuadrantImages(ref cLimbImages, cSprite.NumImagesPerQuadrant);
        }

        //static void GenerateFirstQuadrantImage_RotationComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        //{
        //    cGenerateFirstQuadrantImages_cLimbImages.bmpImages[intGenerateFirstQuadrantImages_ImageCounter] = classGraphics.ro classRotateImage.Image_Rotated; 
        //    cGenerateFirstQuadrantImages_cLimbImages.bmpImages[intGenerateFirstQuadrantImages_ImageCounter].MakeTransparent(cGenerateFirstQuadrantImages_cLimbImages.bmpImages[intGenerateFirstQuadrantImages_ImageCounter].GetPixel(0, 0));

        //    GenerateFirstQuadrantImage_Repeater();
        //}

        //static void GenerateFirstQuadrantImage_Repeater()
        //{
        //    intGenerateFirstQuadrantImages_ImageCounter++;
        //    if (intGenerateFirstQuadrantImages_ImageCounter == intGenerateFirstQuadrantImage_intNumImagesPerQuadrant)
        //    {
        //        if (classSprite.GenerateRotatedLimbImage_CompleteHandler != null)
        //        {
        //            System.ComponentModel.RunWorkerCompletedEventArgs args = new System.ComponentModel.RunWorkerCompletedEventArgs((object)null, null, false);
        //            classSprite.GenerateRotatedLimbImage_CompleteHandler((object)null, args);
        //        }
        //    }
        //    else
        //    {
        //        classRotateImage.RotateImage_BackgroundWorker(cGenerateFirstQuadrantImages_cLimbImages.bmpImages[0], (double)intGenerateFirstQuadrantImages_ImageCounter * dblGenerateFirstQuadrantImages_Angle_Base);
        //    }
        //}

        //System.ComponentModel.ProgressChangedEventHandler proHandler = classRotateImage.ProgressChanged;
        //System.ComponentModel.RunWorkerCompletedEventHandler CompletedHandler = classRotateImage.WorkCompleted;
        static double dblGenerateFirstQuadrantImages_Angle_Base = 0;
        static int intGenerateFirstQuadrantImage_intNumImagesPerQuadrant = 0;
//        static int intGenerateFirstQuadrantImages_ImageCounter = 0;
        static classSprite_Limb_Images cGenerateFirstQuadrantImages_cLimbImages = null;
        /// <summary>
        /// rotates provided limb image 32 times from 0-Pi/2 radians
        /// </summary>
        /// <param name="cLimbImages">image to be rotated</param>
        public static void GenerateFirstQuadrantImages(ref classSprite_Limb_Images cLimbImages, int intNumImagesPerQuadrant)
        {
            if (cLimbImages.bmpImages[0] == null) return;
            Bitmap bmp = cLimbImages.bmpImages[0];
            bmp.MakeTransparent(bmp.GetPixel(0, 0));
            cLimbImages.bmpImages = new Bitmap[4 * intNumImagesPerQuadrant];
            cLimbImages.bmpImages[0] = bmp;
            cGenerateFirstQuadrantImages_cLimbImages = cLimbImages;

            //intGenerateFirstQuadrantImages_ImageCounter = 0;
            intGenerateFirstQuadrantImage_intNumImagesPerQuadrant = intNumImagesPerQuadrant;
            dblGenerateFirstQuadrantImages_Angle_Base = Math.PI / (2.0 * (double)intNumImagesPerQuadrant);

            float fltAngle_Base = (float)(180f / (2.0 * intNumImagesPerQuadrant));
            for (int intImageCounter = 1; intImageCounter < intNumImagesPerQuadrant; intImageCounter++)
            {
                cLimbImages.bmpImages[intImageCounter] = Math3.classGraphics.Rotate(cLimbImages.bmpImages[0], (float)(intImageCounter * fltAngle_Base)); // classRotateImage.RotateImage(cLimbImages.bmpImages[0], (double)intImageCounter * dblAngle_Base);
                cLimbImages.bmpImages[intImageCounter].MakeTransparent(cLimbImages.bmpImages[intImageCounter].GetPixel(0, 0));
            }
        }

        /// <summary>
        /// overwrites current images for LimbImage at intImageList_Index
        /// </summary>
        /// <param name="bmp">new base image for this LimbImage</param>
        public void Image_SetNew(Bitmap bmp) { Image_SetNew(bmp, intImageList_Index); }

        /// <summary>
        /// overwrites current images for specified LimbImage 
        /// </summary>
        /// <param name="bmp">new bitmap for LimbImage</param>
        /// <param name="intImageIndex">index of image to be overwritten</param>
        public void Image_SetNew(Bitmap bmp, int intImageIndex)
        {
            bmp.MakeTransparent(bmp.GetPixel(0, 0));
            lstImages[intImageIndex].bmpImages = new Bitmap[cSprite.NumImagesPerQuadrant * 4];
            lstImages[intImageIndex].bmpImages[0] = bmp;
            classSprite_Limb.classSprite_Limb_Images lstLimbImages = lstImages[intImageIndex];
            GenerateFirstQuadrantImages(ref lstLimbImages, cSprite.NumImagesPerQuadrant);
        }


        public void Image_SetNew(Bitmap[] bmpArray, string strName)
        {
            classSprite_Limb_Images cLimbImages = (classSprite_Limb_Images)cBT_LimbImages.Search(strName);
            Image_SetNew(bmpArray, ref cLimbImages);
        }


        /// <summary>
        /// overwrites current images for specified LimbImage
        /// </summary>
        /// <param name="bmpArray">array of rotated images is expected to be rotated for at least the first quadrant</param>
        /// <param name="intImageIndex">index of LimbImage to be overwritten</param>
        public void Image_SetNew(Bitmap[] bmpArray, int intImageIndex)
        {
            if (bmpArray.Length != cSprite.NumImagesPerQuadrant * 4)
            {
                Array.Resize(ref bmpArray, cSprite.NumImagesPerQuadrant * 4);
            }
            lstImages[intImageIndex].bmpImages = bmpArray;
        }


        public void Image_SetNew(Bitmap[] bmpArray, ref classSprite_Limb_Images cLimbImages)
        {
            if (bmpArray.Length != cSprite.NumImagesPerQuadrant * 4)
            {
                Array.Resize(ref bmpArray, cSprite.NumImagesPerQuadrant * 4);
            }
            cLimbImages.bmpImages = bmpArray;
        }

        string strLimbName = "";
        /// <summary>
        /// name of this limb.  Each limb must have a unique name within a given sprite
        /// invalid limb names are rejected without notice
        /// </summary>
        public string Name
        {
            get { return strLimbName; }
            set
            {
                classSprite_Limb cLimbInTree = (classSprite_Limb)cCostumeInfo.cBT_Limbs.Search(value);
                if (cLimbInTree != null)
                {
                    if (cLimbInTree != this && classSprite.ShowErrorMessages)
                        MessageBox.Show("Cannot change limb's name to " + value + " because a limb by that name already exists.");
                    return;
                }
                strLimbName = value;
                List<object> lstATree_Limbs_Traversal = cCostumeInfo.cBT_Limbs.Traverse();
                if (cCostumeInfo.cBT_Limbs != null)
                    cCostumeInfo.cBT_Limbs = null;
                cCostumeInfo.cBT_Limbs = new classBinTree();
                for (int intLimbCounter = 0; intLimbCounter < lstATree_Limbs_Traversal.Count; intLimbCounter++)
                {
                    object objRef = lstATree_Limbs_Traversal[intLimbCounter];
                    classSprite_Limb cLimb = (classSprite_Limb)objRef;
                    cCostumeInfo.cBT_Limbs.Insert(ref objRef, cLimb.Name);
                }
            }
        }

        double dblDrawAngle;
        /// <summary>
        /// Angle at which this limb was last drawn into a sprite animation frame by classSprite.DrawAnimation_Frame()
        /// </summary>
        public double DrawAngle
        {
            get { return dblDrawAngle; }
            set
            {
                dblDrawAngle = value;
                bmpDraw = GetImage(dblDrawAngle);
            }
        }

        /// <summary>
        /// returns the
        /// </summary>
        /// <param name="dblAngle"></param>
        /// <returns></returns>
        public Bitmap GetImage(double dblAngle) { return GetImage(getIndexFromRadian(dblAngle), intImageList_Index); }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dblAngle"></param>
        /// <param name="intImageListIndex"></param>
        /// <returns></returns>
        public Bitmap GetImage(double dblAngle, int intImageListIndex) { return GetImage(getIndexFromRadian(dblAngle), intImageListIndex); }

        /// <summary>
        /// returns the image requested by its index
        /// </summary>
        /// <param name="index">index of the image requested</param>
        /// <returns>returns the image stored at the specified index</returns>
        public Bitmap GetImage(int index, int intImageListIndex)
        {

            switch (cSprite.eRotatedLimbImage)
            {
                case classSprite.enuRotatedLimbImage.GenerateOnRequest:
                    return classGraphics.Rotate(lstImages[intImageListIndex].bmpImages[0], getAngleFromIndex(index));

                default:
                    {
                        if (index < cSprite.NumImagesPerQuadrant)
                        {
                            return lstImages[intImageListIndex].bmpImages[index];
                        }
                        else if (index < 2 * cSprite.NumImagesPerQuadrant)
                        {
                            if (lstImages[intImageListIndex].bmpImages[index] == null)
                            {
                                int intIndexFirstQuadrant = index % cSprite.NumImagesPerQuadrant;
                                lstImages[intImageListIndex].bmpImages[index] = new Bitmap(lstImages[intImageListIndex].bmpImages[intIndexFirstQuadrant]);
                                lstImages[intImageListIndex].bmpImages[index].RotateFlip(RotateFlipType.Rotate270FlipNone);
                            }
                            return lstImages[intImageListIndex].bmpImages[index];
                        }
                        else if (index < 3 * cSprite.NumImagesPerQuadrant)
                        {
                            if (lstImages[intImageListIndex].bmpImages[index] == null)
                            {
                                int intIndexFirstQuadrant = index % cSprite.NumImagesPerQuadrant;
                                lstImages[intImageListIndex].bmpImages[index] = new Bitmap(lstImages[intImageListIndex].bmpImages[intIndexFirstQuadrant]);
                                lstImages[intImageListIndex].bmpImages[index].RotateFlip(RotateFlipType.Rotate180FlipNone);
                            }
                            return lstImages[intImageListIndex].bmpImages[index];
                        }
                        else
                        {
                            if (lstImages[intImageListIndex].bmpImages[index] == null)
                            {
                                int intIndexFirstQuadrant = index % cSprite.NumImagesPerQuadrant;
                                lstImages[intImageListIndex].bmpImages[index] = new Bitmap(lstImages[intImageListIndex].bmpImages[intIndexFirstQuadrant]);
                                lstImages[intImageListIndex].bmpImages[index].RotateFlip(RotateFlipType.Rotate90FlipNone);
                            }
                            return lstImages[intImageListIndex].bmpImages[index];
                        }
                    }
                    break;
            }
        }

        /// <summary>
        /// returns the index of the image nearest to the specified radian angle
        /// </summary>
        /// <param name="radian">angle of the image the index of which is requested</param>
        /// <returns>the integer value of the index of the image for the radian angle requested</returns>
        int getIndexFromRadian(double radian)
        {
            while (radian < 0) radian += Math.PI * 2;
            while (radian > 2 * Math.PI) radian -= Math.PI * 2;
            return (int)((radian / (double)(Math.PI / (2 * (double)cSprite.NumImagesPerQuadrant))) % lstImages[intImageList_Index].bmpImages.Length);
        }

        double getRadianFromIndex(int index)
        {
            return (double)(index * (Math.PI / (2.0 * cSprite.NumImagesPerQuadrant)));
        }

        float getAngleFromIndex(int index)
        {
            return (float)(index * 90f / (float)cSprite.NumImagesPerQuadrant);
        }

        Point _ptDrawCenter;
        /// <summary>
        /// point relative from the Master Limb where the center of this limb's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public Point ptDrawCenter
        {
            get { return _ptDrawCenter; }
            set { _ptDrawCenter = value; }
        }

        Point _ptHingeDrawCenter;
        /// <summary>
        /// point relative from the Master Hinge where the center of this Hinge's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public Point ptHingeDrawCenter
        {
            get { return _ptHingeDrawCenter; }
            set { _ptHingeDrawCenter = value; }
        }

        /// <summary>
        /// X variable of point relative from the Master Limb where the center of this limb's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public int ptDrawCenter_X
        {
            get { return _ptDrawCenter.X; }
            set { _ptDrawCenter.X = value; }
        }

        /// <summary>
        /// Y variable of point relative from the Master Limb where the center of this limb's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public int ptDrawCenter_Y
        {
            get { return _ptDrawCenter.Y; }
            set { _ptDrawCenter.Y = value; }
        }

        Point _ptDrawCenter_StandardSize;
        /// <summary>
        /// point relative from the Master Limb where the Center_StandardSize of this limb's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public Point ptDrawCenter_StandardSize
        {
            get { return _ptDrawCenter_StandardSize; }
            set { _ptDrawCenter_StandardSize = value; }
        }

        /// <summary>
        /// X variable of point relative from the Master Limb where the Center_StandardSize of this limb's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public int ptDrawCenter_StandardSize_X
        {
            get { return _ptDrawCenter_StandardSize.X; }
            set { _ptDrawCenter_StandardSize.X = value; }
        }

        /// <summary>
        /// Y variable of point relative from the Master Limb where the Center_StandardSize of this limb's image was placed by classSprite.DrawAnimation_Frame()
        /// </summary>
        public int ptDrawCenter_StandardSize_Y
        {
            get { return _ptDrawCenter_StandardSize.Y; }
            set { _ptDrawCenter_StandardSize.Y = value; }
        }

        Bitmap _bmpDraw;
        /// <summary>
        /// rotated image of this limb last used by classSprite.DrawAnimation_Frame()
        /// </summary>
        public Bitmap bmpDraw
        {
            get { return _bmpDraw; }
            set
            {
                _bmpDraw = value;
            }
        }

        classSprite_Hinge cHinge = null;// points to hinge in master limb's slave hinge list
        /// <summary>
        /// hinge that binds this limb to its master limb
        /// </summary>
        public classSprite_Hinge Hinge
        {
            get { return cHinge; }
            set
            {
                cHinge = value;
            }
        }

        /// <summary>
        /// adds an existing limb to this limb's slaveLimb list
        /// </summary>
        /// <param name="cSlave_Limb">limb to be added as a slaveLimb to this limb's slaveLimb list</param>
        public void Slave_Add(ref classSprite_Limb cSlave_Limb)
        {
            lstHinge_Slaves.Add(cSlave_Limb.cHinge);
            cSlave_Limb.cSprite = cSprite;
            cSlave_Limb.cHinge.cSprite = cSprite;
            cSlave_Limb.cHinge.Limb_Master = this;
        }

        /// <summary>
        /// list of the hinges of this limb's slaveLimbs
        /// </summary>
        public List<classSprite_Hinge> lstHinge_Slaves = new List<classSprite_Hinge>();

        public classSprite_Hinge GetSlaveHinge(ref classSprite_Limb cLimbSlave)
        {
            for (int intSHCounter = 0; intSHCounter < lstHinge_Slaves.Count; intSHCounter++)
                if (lstHinge_Slaves[intSHCounter].Limb_Slave == cLimbSlave)
                    return lstHinge_Slaves[intSHCounter];
            return null;
        }
        public classSprite_Limb Copy()
        {
            classSprite_Limb cRetVal = new classSprite_Limb();

            cRetVal.cSprite = cSprite;
            cRetVal.strLimbName = strLimbName;

            cRetVal.bolDisplayPosition = bolDisplayPosition;
            cRetVal.bolSetDrawPosition = bolSetDrawPosition;
            cRetVal.cSprite = cSprite;
            cRetVal.dblDrawAngle = dblDrawAngle;
            cRetVal.DisplayPosition = DisplayPosition;
            cRetVal.Hinge = Hinge != null ? Hinge.Copy() : null;
            cRetVal.intImageList_Index = intImageList_Index;

            cRetVal.lstHinge_Slaves = new List<classSprite_Hinge>();
            cRetVal.lstImages = new List<classSprite_Limb_Images>();
            for (int intImageCounter = 0; intImageCounter < lstImages.Count; intImageCounter++)
            {
                classSprite_Limb_Images cLimbImages = lstImages[intImageCounter].Copy();
                cRetVal.lstImages.Add(cLimbImages);
            }
            cRetVal.DrawAngle = DrawAngle;
            cRetVal.ptDrawCenter = new Point(ptDrawCenter.X, ptDrawCenter.Y);

            return cRetVal;
        }
    }

    /// <summary>
    /// hinges connect two limbs together and are described by two radial coordinates which locate the ContactPoints 
    /// measured away from the center of both the slave and the master limbs that are connected together by the hinge, 
    /// as well as an Angle describing the rotation of the slave relative to its master in a given Animation/Frame
    /// </summary>
    public class classSprite_Hinge
    {
        /// <summary>
        /// sprite to which this hinge belongs
        /// </summary>
        public classSprite cSprite = null;
        public const string conHingeNameExtension = "_Hinge";

        /// <summary>
        /// instantiates a new hinge
        /// </summary>
        /// <param name="name">name of hinge to be instantiated</param>
        /// <param name="Sprite">sprite to which this new hinge belongs</param>
        /// <param name="limb_Slave">slave limb attached to this hinge</param>
        /// <param name="limb_Master">master limb attached to this hinge</param>
        public classSprite_Hinge(ref classSprite Sprite, ref classSprite_Limb limb_Slave, ref classSprite_Limb limb_Master)
        {
            cSprite = Sprite;

            cLimb_Master = limb_Master;
            cLimb_Slave = limb_Slave;

            object objThis = (object)this;
        }

        classRadialCoordinate cRad = new classRadialCoordinate();
        /// <summary>
        /// angle slave limb makes with master limb
        /// </summary>
        public double Angle
        {
            get {

                return cRad.Radians; }
            set
            {
                cRad.Radians = value;
            }
        }
        /// <summary>
        /// default value = 0; varies when dislocating limb from body for animation
        /// </summary>
        public double SlaveContact_MagnitudeFactor
        {
            get { return cRad.Magnitude; }
            set
            {
                cRad.Magnitude = value;
            }
        }

        /// <summary>
        /// sets value contact points for the hinge between master and slave - NOT EDITED DURING ANIMATION 
        /// </summary>
        public classContact Contact = new classContact();

        classSprite_Limb cLimb_Master;
        /// <summary>
        /// limb onto which this slave is connected and about which it rotates
        /// </summary>
        public classSprite_Limb Limb_Master
        {
            get { return cLimb_Master; }
            set
            {
                cLimb_Master = value;
            }
        }

        classSprite_Limb cLimb_Slave = null;
        /// <summary>
        /// slave limb attached to this hinge
        /// </summary>
        public classSprite_Limb Limb_Slave
        {
            get { return cLimb_Slave; }
            set
            {
                cLimb_Slave = value;
            }
        }

        public classSprite_Hinge Copy()
        {
            classSprite_Limb cLimbMaster_Copy = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cLimb_Master.Name);
            classSprite_Limb cLimbSlave_Copy = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cLimb_Slave.Name);

            classSprite_Hinge cRetVal = new classSprite_Hinge(ref cSprite, ref cLimbSlave_Copy, ref cLimbMaster_Copy);
            cRetVal.Angle = Angle;
            cRetVal.cRad = cRad.Copy();
            cRetVal.cSprite = cSprite;
            cRetVal.SlaveContact_MagnitudeFactor = SlaveContact_MagnitudeFactor;

            cRetVal.Contact.Master = Contact.Master.Copy();
            cRetVal.Contact.Slave = Contact.Slave.Copy();

            return cRetVal;
        }
    }

    /// <summary>
    /// point connecting the hinge to a limb
    /// a contact point is defined as a radial coordinate describing the position of a hinge's Contact point onto a limb measured away from the limb's center 
    /// when it rests at zero angular rotation.
    /// both the slave and master limbs's contact points are static throughout the life of the sprite outside the SpriteEditor where they are defined
    /// however, the SlaveLimb's contact point's magnitude value is multiplied by SlaveContactMagnitude_Factor every time the sprite is drawn, affecting the position
    /// of the slave relative to its master.  Values greater than 1.0 distance the slave from its master, smaller approach it.
    /// </summary>
    public class classContact
    { // values set during build phase -> DO NOT VARY DURING ANIMATION

        classRadialCoordinate cRad_Master = new classRadialCoordinate();
        /// <summary>
        /// point where hinge is located relative to the center of the master limb
        /// </summary>
        public classRadialCoordinate Master
        {
            get { return cRad_Master; }
            set
            {
                cRad_Master = value;
            }
        }
        classRadialCoordinate cRad_Slave = new classRadialCoordinate();
        /// <summary>
        /// point where hinge is located relative to the center of the slave limb
        /// </summary>
        public classRadialCoordinate Slave
        {
            get { return cRad_Slave; }
            set
            {
                cRad_Slave = value;
            }
        }
    }

    public class classTextAnimation
    {
        string strName = "";
        public string Name
        {
            get { return strName; }
            set { strName = value; }
        }

        double dblLimbAngleStart = 0;
        public double LimbAngleStart
        {
            get { return dblLimbAngleStart; }
            set { dblLimbAngleStart = value; }
        }

        double dblLimbAngleDelta = 0;
        public double LimbAngleDelta
        {
            get { return dblLimbAngleDelta; }
            set { dblLimbAngleDelta = value; }
        }

        double dblLimbMagnitudeStart = 1;
        public double LimbMagnitudeStart
        {
            get { return dblLimbMagnitudeStart; }
            set { dblLimbMagnitudeStart = value; }
        }

        double dblLimbMagnitudeDelta = 0;
        public double LimbMagnitudeDelta
        {
            get { return dblLimbMagnitudeDelta; }
            set { dblLimbMagnitudeDelta = value; }
        }

        double dblCraneAngleStart = 0;
        public double CraneAngleStart
        {
            get { return dblCraneAngleStart; }
            set { dblCraneAngleStart = value; }
        }

        double dblCraneAngleDelta = 0;
        public double CraneAngleDelta
        {
            get { return dblCraneAngleDelta; }
            set { dblCraneAngleDelta = value; }
        }

        double dblCraneMagnitudeStart = 1;
        public double CraneMagnitudeStart
        {
            get { return dblCraneMagnitudeStart; }
            set { dblCraneMagnitudeStart = value; }
        }

        double dblCraneMagnitudeDelta = 0;
        public double CraneMagnitudeDelta
        {
            get { return dblCraneMagnitudeDelta; }
            set { dblCraneMagnitudeDelta = value; }
        }

        int intNumFrames = 1;
        public int NumFrames
        {
            get { return intNumFrames; }
            set { intNumFrames = value; }
        }

        public List<classSprite_Limb> lstMasterLimb = new List<classSprite_Limb>();

        public classTextAnimation() { }

        public classTextAnimation(string strName,
                                  int intNumFrames,
                                  double dblLimbAngleStart,
                                  double dblLimbAngleDelta,
                                  double dblLimbMagnitudeStart,
                                  double dblLimbMagnitudeDelta,

                                  double dblCraneAngleStart,
                                  double dblCraneAngleDelta,
                                  double dblCraneMagnitudeStart,
                                  double dblCraneMagnitudeDelta
                                  )
        {
            this.Name = strName;
            this.NumFrames = intNumFrames;
            this.LimbAngleStart = dblLimbAngleStart;
            this.LimbAngleDelta = dblLimbAngleDelta;
            this.LimbMagnitudeStart = dblLimbMagnitudeStart;
            this.LimbMagnitudeDelta = dblLimbMagnitudeDelta;
            this.CraneAngleStart = dblCraneAngleStart;
            this.CraneAngleDelta = dblCraneAngleDelta;
            this.CraneMagnitudeStart = dblCraneMagnitudeStart;
            this.CraneMagnitudeDelta = dblCraneMagnitudeDelta;
        }
        public classTextAnimation(string strName,
                                  int intNumFrames,
                                  double dblLimbAngleStart,
                                  double dblLimbAngleDelta,
                                  double dblLimbMagnitudeStart,
                                  double dblLimbMagnitudeDelta,

                                  double dblCraneAngleStart,
                                  double dblCraneAngleDelta,
                                  double dblCraneMagnitudeStart,
                                  double dblCraneMagnitudeDelta,
                                  ref List<classSprite_Limb> lstMasterLimb
                                  )
        {
            this.Name = strName;
            this.NumFrames = intNumFrames;
            this.LimbAngleStart = dblLimbAngleStart;
            this.LimbAngleDelta = dblLimbAngleDelta;
            this.LimbMagnitudeStart = dblLimbMagnitudeStart;
            this.LimbMagnitudeDelta = dblLimbMagnitudeDelta;
            this.CraneAngleStart = dblCraneAngleStart;
            this.CraneAngleDelta = dblCraneAngleDelta;
            this.CraneMagnitudeStart = dblCraneMagnitudeStart;
            this.CraneMagnitudeDelta = dblCraneMagnitudeDelta;
            this.lstMasterLimb = lstMasterLimb;
        }
    }

    public class classAnimation_Override
    {
        public classAnimation cAnimation = null;
        public int FrameIndex = 0;
        public classSprite cSprite = null;

        public classAnimation_Override (ref classSprite cSprite)
        {
            this.cSprite = cSprite;
        }

        public classAnimation_Override Next()
        {
            classAnimation_Override cRetVal = new classAnimation_Override(ref cSprite);
            cRetVal.cAnimation = cAnimation;
            cRetVal.FrameIndex = cAnimation.lstFrames.Count > 0
                                        ? (FrameIndex + 1) % cAnimation.lstFrames.Count
                                        : 0;
            return cRetVal;
        }

    }
}