Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Sprite Editor for .NET

, 27 Jan 2010
Build, edit, and animate your own sprites.
classSprite_C_2008.zip
classSprite
classSprite
classSprite.csproj.user
bin
Release
classSprite.dll
Properties
GraphicsEditor_C_2008.zip
GraphicsEditor CSharp
GraphicsEditor CSharp
graphics editor icon.ico
GraphicsEditor CSharp.csproj.user
Properties
Settings.settings
Resources
Brush_Icon.bmp
click to load image.bmp
colorTemplate.bmp
cursor_cross.bmp
cursor_move.bmp
cursor_resizeDiagonal_BL_TR.bmp
cursor_resizeDiagonal_TL_BR.bmp
cursor_resizeLeftRight.bmp
cursor_resizeUpDown.bmp
Edit_Redo_Icon.bmp
Edit_Undo_Icon.bmp
Eraser_Icon.bmp
FloodFill_Icon.bmp
FloodFill_pnlBackground_sameColor.bmp
FloodFill_pnlBackground_toBorder.bmp
Free-Form Select_Icon.bmp
Gun.bmp
Line_Icon.bmp
Magnify_Icon.bmp
Pencil_Icon.bmp
Pick-color_Icon.bmp
Select_Icon.bmp
sprite Editor.jpg
Straighten_Icon.bmp
Night_Stalker__C_2008.zip
Night Stalker
Night Stalker
Night Stalker.csproj.user
nightstalker.ico
Properties
Settings.settings
Resources
bomb.wav
bulletEaten.wav
BulletEater.spr
bulletEater.wav
bunker.png
bunkerbuster.spr
BunkerBuster.wav
CDbunkerWalls.bmp
Colt Round.png
Colt.spr
colt45.wav
corpse (small).spr
diescream.wav
emptychamber.wav
Evil Jessica (small).spr
Felix the Cat (small).spr
FelixFire.spr
FelixFire.wav
freeLife.wav
gun.png
gun.spr
heartbeat.wav
help_background.jpg
hithard.wav
Jessica Rabbit Small.spr
largeJessica.spr
Laser.spr
laserFire.wav
loadclip.wav
Map WPs.png
Map.jpg
MapCD.bmp
mini bat.spr
NearestWayPointsTable.bfs
nightstalker.bmp
nightstalker.png
red bunker.png
Robot Den New.png
Robot_A.spr
smurf (small).spr
smurf-attack.spr
spider (small).spr
Spider Web.png
splat.wav
WayPointsArray.bfs
WayPointsTable.bfs
Sprites.zip
Sprites
Robot1.bmp
Robot2.bmp
robot3.bmp
Bat
bat.spr
head.bmp
head.jpg
leftwing.bmp
mini bat.spr
wing.bmp
Bullets
bulletEater original.png
bulletEater.bmp
BulletEater.spr
bunkerbuster.bmp
bunkerbuster.spr
Colt.bmp
Colt.spr
Laser.bmp
Laser.spr
master limb.bmp
smurf-attack.bmp
smurf-attack.spr
Claudia Schiffer
alt.spr
Claudia.spr
Claudia_Arm.bmp
Claudia_Foot.bmp
Claudia_Forearm.bmp
Claudia_Hand_Left.bmp
Claudia_Hand_Right.bmp
Claudia_head.bmp
Claudia_head2.bmp
Claudia_mini.spr
Claudia_Schiffer_1.jpg
Claudia_Shin.bmp
Claudia_Thigh.bmp
Claudia_Torso.bmp
gunHand.bmp
Corpse
blood.bmp
corpse (small).spr
Corpse.spr
guts.bmp
master limb.bmp
robot.png
smurfcorpse.png
Evil Jessica
Evil Jessica (small).spr
Evil Jessica.spr
GunHand(near).bmp
JR_Arm.bmp
JR_Arm.png
JR_Dress.bmp
JR_Dress_resized.bmp
JR_Foot.bmp
JR_Forearm.bmp
JR_Hair(far).bmp
JR_Hair(near).bmp
JR_Hand.bmp
JR_Hand_Right.bmp
JR_Head.bmp
JR_MasterBlock.bmp
JR_Shin.bmp
JR_Thigh_far.bmp
JR_Thigh_near.bmp
JR_Torso.bmp
gun
gun.bmp
gun.spr
master block.bmp
Jessica Rabbit
GunHand(near).bmp
Jessica Rabbit Small.spr
Jessica Rabbit.spr
jessica_rabbit at mic.jpg
JR_Arm.bmp
JR_Dress.bmp
JR_Dress_resized.bmp
JR_Foot.bmp
JR_Forearm.bmp
JR_Hair(far).bmp
JR_Hair(near).bmp
JR_Hand.bmp
JR_Hand_Right.bmp
JR_Head.bmp
JR_MasterBlock.bmp
JR_Shin.bmp
JR_Thigh_far.bmp
JR_Thigh_near.bmp
JR_Torso.bmp
Lindsay Lohan
arm.bmp
foot.bmp
forearm.bmp
gunHand.bmp
Hand_Left.bmp
head.bmp
Lindsay Lohan.spr
Mini Lindsay Lohan.spr
shin.bmp
skirt_ass.bmp
skirt_front.bmp
thigh.bmp
torso.bmp
NightStalkerSprites
BulletEater.spr
bunkerbuster.spr
Colt.spr
corpse (small).spr
Evil Jessica (small).spr
gun.spr
Jessica Rabbit Small.spr
Laser.spr
mini bat.spr
Mini Lindsay Lohan.spr
Robot_A.spr
smurf (small).spr
smurf-attack.spr
spider (small).spr
Robot Heart
RobotHeart_Head.bmp
RobotHeart_Torso.bmp
Robot_EyeShut.bmp
ROBOT_heart.bmp
Robot_Heart.spr
Robot_Heart_small.spr
Robot_LeftArm.bmp
Robot_Leg.bmp
Robot_dumb
Arm.bmp
Arm_right_front.bmp
Hand.bmp
Head.bmp
head_back.bmp
Head_Front.bmp
Leg.bmp
leg_back.bmp
leg_front.bmp
Robot_A.spr
Robot_A_original.spr
Robot_A_original_copy.spr
Torso.bmp
Torso_Front.bmp
Smurf
arm(far).bmp
arm(near).bmp
head.bmp
leg.bmp
smurf (small).spr
smurf.spr
Torso.bmp
spider
body.bmp
eyes shut.bmp
head.bmp
legA_left.bmp
legA_right.bmp
legB_left.bmp
legB_right.bmp
LegC_left.bmp
legC_right.bmp
legD_left.bmp
legD_right.bmp
mandible_left.bmp
mandible_right.bmp
spider (small).spr
spider 2.spr
spider.png
spider.spr
sprite_Demo_C_2008.zip
Sprite demo
Sprite demo
Sprite demo.csproj.user
bin
Release
Sprite demo.exe
Properties
Settings.settings
Resources
cartoon grass.jpg
smurf (small).spr
sprite_Editor_C_2008.zip
Sprite Editor
Sprite Editor
Sprite Editor.csproj.user
sprite Editor.ico
bin
Release
cLibPicBoxViewer.dll
Sprite Editor.exe
Properties
Settings.settings
Resources
click to load image.bmp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;

namespace Sprite
{
    public enum enuMirror { none, vertical, horizontal, VerticalAndHorizontal }

    public struct udtSprite_StorageRetrieval
    {
        public string myName;
        public udtLimb_StorageRetrieval[] limbs;
    }

    public struct udtLimb_StorageRetrieval
    {
        public string myName;
        public Bitmap bmp;
        public bool IRotate;
        public bool AlwaysVertical;
        public classMath.classRadialCoor radMaster;
        public int MasterIndex;
        public classMath.classRadialCoor radSlave;
        public string hingeName;
    }

    /// <summary>
    /// a hinge connects to limbs together
    /// radial coordinates are relative to the center of each image
    /// the slave's master coordinate is place at the same location as its master's slave coordinate onto the screen
    /// </summary>
    public class classSpriteHinge
    {
        string myName;
        public bool bolFlag = true;

        public string name
        {
            get { return myName; }
        }

        double myAngle;
        /// <summary>
        /// angle of slave limb relative to angle of master limb
        /// </summary>
        public double Angle
        {
            get { return myAngle; }
            set 
            {
                double dblTestAngle = value - (Math.PI / 16.0);
                if (dblTestAngle < 0)
                    dblTestAngle += (Math.PI * 2.0);
                int intDir = (int)(Math.Ceiling(dblTestAngle / (Math.PI / 8.0)));
                myAngle = intDir * Math.PI / 8.0;
            }
        }

        public classSpriteHinge(string name) { myName = name; }
       /// <summary>
       /// a hinge connects to limbs together
       /// radial coordinates are relative to the center of each image
       /// the slave's master coordinate is place at the same location as its master's slave coordinate onto the screen    
       /// </summary>
       /// <param name="name">name of this hinge, e.g. "elbow"</param>
       /// <param name="RadCoor_Master">radial coordinate (radians, pixels) of location of joint on master image relative to center</param>
        /// <param name="RadCoor_Slave">radial coordinate (radians, pixels) of location of joint on slave image relative to center</param>
       /// <param name="LimbMaster">pointer to Master-Limb</param>
       /// <param name="LimbSlave">pointer to Slave-Limb</param>
        public classSpriteHinge(string name, classMath.classRadialCoor RadCoor_Master, classMath.classRadialCoor RadCoor_Slave, classSpriteLimb LimbMaster, classSpriteLimb LimbSlave)
        {
            udrRadCoor_Master = RadCoor_Master;
            udrRadCoor_Slave = RadCoor_Slave;
            classLimb_Master = LimbMaster;
            classLimb_Slave = LimbSlave;
            myName = name;
        }

        classMath.classRadialCoor udrRadCoor_Master;
        /// <summary>
        /// radial coordinate location relative to center of image
        /// </summary>
        public classMath.classRadialCoor RadCoor_Master
        {
            get { return udrRadCoor_Master; }
            set { udrRadCoor_Master = value; }
        }

        classMath.classRadialCoor udrRadCoor_Slave;
        /// <summary>
        /// radial coordinate location relative to center of image
        /// </summary>
        public classMath.classRadialCoor RadCoor_Slave
        {
            get { return udrRadCoor_Slave; }
            set { udrRadCoor_Slave = value; }
        }

        classSpriteLimb classLimb_Master;
        /// <summary>
        /// pointer to limb connected to this hinge
        /// </summary>
        public classSpriteLimb Limb_Master
        {
            get { return classLimb_Master; }
            set { classLimb_Master = value; }
        }

        classSpriteLimb classLimb_Slave;
        /// <summary>
        /// pointer to limb connected to this hinge
        /// </summary>
        public classSpriteLimb Limb_Slave
        {
            get { return classLimb_Slave; }
            set { classLimb_Slave = value; }
        }
    }

    /// <summary>
    /// one element in array of 16 that describes a limb's position relative to its master
    /// as well as the locations of any number of slaves relative to it
    /// </summary>
    public class classSpriteLimbImage
    {
        public classSpriteLimbImage() { }
        public classSpriteLimbImage(Bitmap bmpOriginal) { bmp = bmpOriginal; }

        /// <summary>
        /// this sprite limb's image for this angle
        /// </summary>
        public Bitmap bmp;
    }

    public class classSpriteLimb
    {
        Sprite.classSprite mainSprite;
        public bool bolFlag = true;
        public Rectangle recDest;
        public classSpriteLimbImage myCurrentImage;

        public classSpriteLimb[] mySlaveLimbs;
        int intMySlaveID;
        /// <summary>
        /// my index in my master's slave limb array
        /// </summary>
        public int MySlaveID
        {
            get { return intMySlaveID; }
            set { intMySlaveID = value; }
        }

        bool bolAlwaysVertical = false;
        /// <summary>
        /// determines whether generated images are flipped to remain vertical or rotated 360 degrees
        /// </summary>
        public bool AlwaysVertical { get { return bolAlwaysVertical; } }

        string myName;
        public string Name { get { return myName; } }

        Point ptLoc;
        /// <summary>
        /// location of top-left corner of image's rectangle
        /// </summary>
        public Point Loc
        {
            get { return ptLoc; }
            set { ptLoc = value; }
        }

        int dir;
        /// <summary>
        /// 0-15 where 0 is east, 4 north, etc.
        /// also corresponds to the udrSpriteLimbImages's index of currently displayed image
        /// </summary>
        public int Dir
        {
            get { return dir; }
            set { dir = value; }
        }

        double angle;
        /// <summary>
        /// at which this limb currently has on the screen
        /// </summary>
        public double Angle
        {
            get { return -angle; }
            set { angle = -value; }
        }

        /// <summary>
        /// this limb's images
        /// </summary>
        public classSpriteLimbImage[] udrSpriteLimbImages;

        bool bolIRotate = true;
        /// <summary>
        /// boolean variable which determines whether this limb rotates or animates
        /// when true, SpriteLimbImages is expected to consist of 16 images at 16 angles
        /// when false, SpriteLimbImages is either one or many images which are used to animate this limb
        /// </summary>
        public bool IRotate
        {
            get { return bolIRotate; }
            set { bolIRotate = value; }
        }

        //bool bolIHaveNoMaster = false;
        //public bool IHaveNoMaster { get { return bolIHaveNoMaster; } }
        public classSpriteHinge MasterHinge;

        /// <summary>
        /// a limb consists of an array of images with their corresponding hinge locations
        /// </summary>
        /// <param name="IRotate">
        /// when this is set the indices of udrSpriteLimbImage are direction of rotation, e.g. action-arm, these are created if not provided
        /// when this is not set these are animation images, e.g. walking legs</param>
        /// </param>
        /// <param name="AlwaysVertical">
        /// determines whether generated images are flipped to remain vertical or rotated 360 degrees
        /// </param>
        /// <param name="_myName">
        /// used for ease of debugging e.g. "Torso", "left arm", "right hand"
        /// </param>
        /// <param name="bmpOriginal">
        /// first elements of array of images
        /// </param>
        public classSpriteLimb(ref classSprite sprite, bool IRotate, bool AlwaysVertical, string _myName, params Bitmap[] bmpOriginal)
        {
            mainSprite = sprite;
            myName = _myName;
            bolIRotate = IRotate;
            bolAlwaysVertical = AlwaysVertical;
            initImages(bmpOriginal);
        }

        public void initImages(Bitmap[] bmpOriginal)
        {
            //myName = "arm(near fuck)";
            if (bolIRotate)
            {
                udrSpriteLimbImages = new classSpriteLimbImage[16];
                for (int intBmpCounter = 0; intBmpCounter < bmpOriginal.Length; intBmpCounter++)
                    udrSpriteLimbImages[intBmpCounter] = new classSpriteLimbImage(bmpOriginal[intBmpCounter]);

                if (bmpOriginal.Length < 4)
                { // generate 1, 2 & 3 from 0
                    generateBaseFourImagesFromOriginal();
                }

                if (bmpOriginal.Length < 15)
                { // generate all from 0,1,2 & 3
                    for (int intImageCounter = 4; intImageCounter < 16; intImageCounter++)
                    {
                        udrSpriteLimbImages[intImageCounter] = getLimbImageFromArray_ByDir(ref udrSpriteLimbImages, intImageCounter);
                    }
                }
               
            }
            else
            {
                udrSpriteLimbImages = new classSpriteLimbImage[bmpOriginal.Length];
                for (int intBmpCounter = 0; intBmpCounter < bmpOriginal.Length; intBmpCounter++)
                {
                    udrSpriteLimbImages[intBmpCounter] = new classSpriteLimbImage();
                    udrSpriteLimbImages[intBmpCounter].bmp = bmpOriginal[intBmpCounter];
                }
            }
        }



        #region "initialize images"
        /// <summary>
        /// generates three angled copies of the original(udrSpriteLimbImage[0]) and stores them in udrSpriteLimbImage[1,2,3]
        /// </summary>
        void generateBaseFourImagesFromOriginal()
        {
            classMath cLibMath = new classMath();
            Color clrTransparent = udrSpriteLimbImages[0].bmp.GetPixel(0,0);
            double dblRotationAngle = 0;
            for (int intImageCounter = 1; intImageCounter < 4; intImageCounter++)
            {
                dblRotationAngle =Math.PI +  (Math.PI * (double)intImageCounter / 8.0);
                udrSpriteLimbImages[intImageCounter] = new classSpriteLimbImage();
                udrSpriteLimbImages[intImageCounter].bmp = rotate(udrSpriteLimbImages[0].bmp, dblRotationAngle, ref cLibMath);
            }
        }

        Bitmap rotate(Bitmap bmpInput, double dblAngleRotation, ref classMath cLibMath)
        {
            int intMinSquare = bmpInput.Width > bmpInput.Height ?
                                3 * bmpInput.Width
                                : 3 * bmpInput.Height;
            Color clrHole = Color.YellowGreen;// some color assumed NOT in the input bmp

            Bitmap bmpCopy = new Bitmap(intMinSquare, intMinSquare);
            Point ptTL;
            Point ptBR;
            Point ptCopyCenter = new Point(bmpCopy.Width / 2, bmpCopy.Height / 2);
            Point ptOriginalCenter = new Point(bmpInput.Width / 2, bmpInput.Height / 2);
            using (Graphics g = Graphics.FromImage(bmpCopy))
            {
                g.FillRectangle(new SolidBrush(clrHole), new Rectangle(new Point(0, 0), bmpCopy.Size));
                ptTL = new Point(ptCopyCenter.X, ptCopyCenter.Y);
                ptBR = new Point(ptCopyCenter.X, ptCopyCenter.Y);

                for (int intX = 0; intX < bmpInput.Width; intX++)
                {
                    for (int intY = 0; intY < bmpInput.Height; intY++)
                    {
                        int intDX = ptOriginalCenter.X - intX;
                        int intDY = ptOriginalCenter.Y - intY;
                        classMath.classRadialCoor udrOriginalRad = new classMath.classRadialCoor( cLibMath.arcTan(intDX, intDY), Math.Sqrt(intDX * intDX + intDY * intDY));
                        classMath.classRadialCoor udrCopyRad = new classMath.classRadialCoor(udrOriginalRad.angle - dblAngleRotation, udrOriginalRad.radius);
                        Point ptCopy = new Point((int)(ptCopyCenter.X + udrCopyRad.radius * Math.Cos(udrCopyRad.angle)),
                                                 (int)(ptCopyCenter.Y + udrCopyRad.radius * Math.Sin(udrCopyRad.angle)));

                        try { bmpCopy.SetPixel(ptCopy.X, ptCopy.Y, bmpInput.GetPixel(intX, intY)); }
                        catch (Exception) { }

                        // keep track of limits of output image
                        if (ptCopy.X < ptTL.X)
                            ptTL.X = ptCopy.X;
                        if (ptCopy.Y < ptTL.Y)
                            ptTL.Y = ptCopy.Y;
                        if (ptCopy.X > ptBR.X)
                            ptBR.X = ptCopy.X;
                        if (ptCopy.Y > ptBR.Y)
                            ptBR.Y = ptCopy.Y;
                    }
                }
            }

            // write image to output array
            Size szOfImage = new Size(ptBR.X - ptTL.X, ptBR.Y - ptTL.Y);
            Rectangle recSrc = new Rectangle(ptTL, szOfImage);
            Rectangle recDest = new Rectangle(new Point(0, 0), szOfImage);

            // fill the blanks missed when rotating image
            // scanning x from 0 to width created a problem in the fill-blank
            for (int intX = ptTL.X; intX < ptBR.X; intX++)
                for (int intY = ptTL.Y; intY < ptBR.Y; intY++)
                {
                    Color clrTest = bmpCopy.GetPixel(intX, intY);
                    if (clrTest.A == clrHole.A
                        && clrTest.R == clrHole.R 
                        && clrTest.G == clrHole.G 
                        && clrTest.B == clrHole.B)
                    {
                        udtPixilateColorFind[] udrColorFind = new udtPixilateColorFind[0];
                        if (intX > 0 && intX < bmpCopy.Width - 2 && intY > 0 && intY < bmpCopy.Height - 2)
                        {
                            Point ptUp = new Point(intX, intY - 1);
                            Point ptDown = new Point(intX, intY + 1);
                            Point ptLeft = new Point(intX - 1, intY);
                            Point ptRight = new Point(intX + 1, intY);
                            Point ptUL = new Point(intX - 1, intY - 1);
                            Point ptUR = new Point(intX + 1, intY - 1);
                            Point ptDR = new Point(intX + 1, intY + 1);
                            Point ptDL = new Point(intX - 1, intY + 1);

                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUp.X, ptUp.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDown.X, ptDown.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptLeft.X, ptLeft.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptRight.X, ptRight.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDL.X, ptDL.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptDR.X, ptDR.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUL.X, ptUL.Y));
                            addPixilateColorFound(ref udrColorFind, bmpCopy.GetPixel(ptUR.X, ptUR.Y));
                            reorderPixilateColorFound(ref udrColorFind);
                            if (udrColorFind[0].numFound >= 2)
                                try { bmpCopy.SetPixel(intX, intY, udrColorFind[0].clr); }
                                catch (Exception) { }
                            else
                            {
                                int intDX = ptCopyCenter.X - intX;
                                int intDY = ptCopyCenter.Y - intY;
                                classMath.classRadialCoor udrOriginalRad = new classMath.classRadialCoor(cLibMath.arcTan(intDX, intDY), Math.Sqrt(intDX * intDX + intDY * intDY));
                                classMath.classRadialCoor udrCopyRad = new classMath.classRadialCoor(udrOriginalRad.angle + dblAngleRotation, udrOriginalRad.radius);
                                Point ptCopy = new Point((int)(ptOriginalCenter.X + udrCopyRad.radius * Math.Cos(udrCopyRad.angle)),
                                                         (int)(ptOriginalCenter.Y + udrCopyRad.radius * Math.Sin(udrCopyRad.angle)));

                                if (ptCopy.X >= 0 && ptCopy.X < bmpCopy.Width && ptCopy.Y >= 0 && ptCopy.Y < bmpCopy.Height)
                                    try { bmpCopy.SetPixel(intX, intY, bmpInput.GetPixel(ptCopy.X, ptCopy.Y)); }
                                    catch (Exception) { }
                            }
                        }
                    }
                }
            if (recDest.Width < 1)
                recDest.Width = 1;
            if (recDest.Height < 1)
                recDest.Height = 1;
            Bitmap bmpTemp = new Bitmap(recDest.Width, recDest.Height);

            using (Graphics g = Graphics.FromImage(bmpTemp))
            {
                g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, bmpTemp.Width, bmpTemp.Height));
                bmpCopy.MakeTransparent(bmpCopy.GetPixel(0,0));
                g.DrawImage(bmpCopy, recDest, recSrc, GraphicsUnit.Pixel);
            }

            return bmpTemp;
        }

        public struct udtPixilateColorFind
        {
            public Color clr;
            public int numFound;
        }

        private void addPixilateColorFound(ref udtPixilateColorFind[] udrPixilateColorFind, Color clrFound)
        {
            if (udrPixilateColorFind == null)
            {
                udrPixilateColorFind = new udtPixilateColorFind[1];
                udrPixilateColorFind[0] = new udtPixilateColorFind();
                udrPixilateColorFind[0].clr = clrFound;
                udrPixilateColorFind[0].numFound = 1;
            }
            else
            {
                for (int intClrCounter = 0; intClrCounter < udrPixilateColorFind.Length; intClrCounter++)
                    if (udrPixilateColorFind[intClrCounter].clr == clrFound)
                    {
                        udrPixilateColorFind[intClrCounter].numFound++;
                        return;
                    }
                Array.Resize<udtPixilateColorFind>(ref udrPixilateColorFind, udrPixilateColorFind.Length + 1);
                udrPixilateColorFind[udrPixilateColorFind.Length - 1] = new udtPixilateColorFind();
                udrPixilateColorFind[udrPixilateColorFind.Length - 1].clr = clrFound;
                udrPixilateColorFind[udrPixilateColorFind.Length - 1].numFound = 1;
            }
        }

        void reorderPixilateColorFound(ref udtPixilateColorFind[] udrPixilateColorFind)
        {
            int intBestFind;
            for (int intOuterLoop = 0; intOuterLoop < udrPixilateColorFind.Length - 1; intOuterLoop++)
            {
                intBestFind = intOuterLoop;
                for (int intInnerLoop = intOuterLoop + 1; intInnerLoop < udrPixilateColorFind.Length; intInnerLoop++)
                {
                    if (udrPixilateColorFind[intInnerLoop].numFound > udrPixilateColorFind[intBestFind].numFound)
                        intBestFind = intInnerLoop;
                }
                if (intBestFind != intOuterLoop)
                {
                    udtPixilateColorFind udrTemp = udrPixilateColorFind[intOuterLoop];
                    udrPixilateColorFind[intOuterLoop] = udrPixilateColorFind[intBestFind];
                    udrPixilateColorFind[intBestFind] = udrTemp;
                }
            }
        }

        /// <summary>
        /// returns image appropriate for this limb at current angle
        /// selected from array of 16 images
        /// </summary>
        public classSpriteLimbImage getSpriteImageFromArray() { return getSpriteImageFromArray(ref udrSpriteLimbImages, angle); }

        /// <summary>
        /// returns image appropriate for this limb at input angle
        /// selected from array of 16 images
        /// </summary>
        /// <param name="dblAngle">
        /// angled image to be returned
        /// </param>
        /// <returns></returns>
        public classSpriteLimbImage getSpriteImageFromArray(double dblAngle) { return getSpriteImageFromArray(ref udrSpriteLimbImages, dblAngle); }

        /// <summary>
        /// returns image appropriate for this limb at input angle
        /// selected from array of 16 images
        /// </summary>
        /// <param name="udrSpriteImage">array of 4 images pointing in 16 angles where east is 0th, North-east is 2nd, North 4th, etc.</param>
        /// <param name="dblAngle">angle in radians where 0 is east Pi/2 is north, Pi is west, and 3Pi/2 is south</param>
        /// <returns></returns>
        public classSpriteLimbImage getSpriteImageFromArray(ref classSpriteLimbImage[] udrSpriteImage, double dblAngle)
        {
            angle = dblAngle;
            while (angle < 0)
                angle += (2.0 * Math.PI);

            while (angle > 2.0 * Math.PI)
                angle -= (2.0 * Math.PI);

            setDir();
            return getLimbImageFromArray_ByDir(ref udrSpriteImage, dir);
        }

        public void setDir() { setDir(angle); }
        public void setDir(double dblAngle)
        {
            double dblTestAngle = dblAngle - (Math.PI / 16.0);
            if (dblTestAngle < 0)
                dblTestAngle += (Math.PI * 2.0);
            int intPicIndex = (int)(Math.Ceiling(dblTestAngle / (Math.PI / 8.0)));

            if (intPicIndex == 16)
                intPicIndex = 0;
            dir = intPicIndex;

            angle = dir * (Math.PI / 8);
        }

        /// <summary>
        /// returns image appropriate for this limb at input direction
        /// selected from array of 16 images
        /// </summary>
        /// <param name="udrSpriteImage">array of 4 images pointing in 16 angles where east is 0th, North-east is 2nd, North 4th, etc.</param>
        /// <param name="intDir">indicates the desired direction of image where 0th is east, 4th is north, 8 is west and 12th south, etc.</param>
        /// <returns></returns>
        public classSpriteLimbImage getLimbImageFromArray_ByDir(ref classSpriteLimbImage[] udrSpriteImage, int intDir)
        {
            if (udrSpriteImage == null)
                return null;
            if (intDir < 0 || intDir > 15)
            {
                MessageBox.Show("error getLimbImageFromArray_ByDir");
                return udrSpriteImage[0];
            }
            else
            {
                if (udrSpriteImage.Length > 1)
                {
                    if (intDir < udrSpriteImage.Length && false)
                    {
                        return udrSpriteImage[intDir];
                    }
                    else
                        switch (intDir)
                        {
                            case 0:
                            case 1:
                            case 2:
                            case 3:
                                return udrSpriteImage[intDir];

                            default:
                                if (udrSpriteLimbImages[intDir] != null)
                                    return udrSpriteLimbImages[intDir];
                                else
                                {
                                    if (bolAlwaysVertical)
                                    {
                                        classSpriteLimbImage udrRetVal = new classSpriteLimbImage();
                                        switch (intDir)
                                        {
                                            case 4:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);

                                                return udrRetVal;

                                            case 5:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 6:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 7:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 8:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                                                return udrRetVal;

                                            case 9:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipX);
                                                return udrRetVal;

                                            case 10:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipX);
                                                return udrRetVal;

                                            case 11:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipY);
                                                return udrRetVal;

                                            case 12:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 13:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 14:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            default:  // case 15
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;
                                        }
                                    }
                                    else
                                    {
                                        classSpriteLimbImage udrRetVal = new classSpriteLimbImage();
                                        switch (intDir)
                                        {
                                            case 4:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);

                                                return udrRetVal;

                                            case 5:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
                                                return udrRetVal;

                                            case 6:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
                                                return udrRetVal;

                                            case 7:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
                                                return udrRetVal;

                                            case 8:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 9:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 10:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 11:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                                return udrRetVal;

                                            case 12:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[0].bmp.Width, udrSpriteImage[0].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[0].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 13:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[1].bmp.Width, udrSpriteImage[1].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[1].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            case 14:
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[2].bmp.Width, udrSpriteImage[2].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[2].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;

                                            default:  // case 15
                                                udrRetVal.bmp = new Bitmap(udrSpriteImage[3].bmp.Width, udrSpriteImage[3].bmp.Height);
                                                using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
                                                    g.DrawImage(udrSpriteImage[3].bmp, new Point(0, 0));
                                                udrRetVal.bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
                                                return udrRetVal;
                                        }
                                    }
                                }
                        }
                }
                else
                {
                    return udrSpriteImage[0];
                }
            }
        }
        #endregion

        public void addLimb(classSpriteLimb newLimb, string hingeName, classMath.classRadialCoor radMasterJoint, classMath.classRadialCoor radSlaveJoint)
        {
            if (mySlaveLimbs == null)
                mySlaveLimbs = new classSpriteLimb[0];
            Array.Resize<classSpriteLimb>(ref mySlaveLimbs, mySlaveLimbs.Length + 1);
            mySlaveLimbs[mySlaveLimbs.Length - 1] = newLimb;
            mySlaveLimbs[mySlaveLimbs.Length - 1].MasterHinge = new classSpriteHinge(hingeName, radMasterJoint, radSlaveJoint, this, newLimb);
           
            Array.Resize<Sprite.classSpriteHinge>(ref mainSprite.hinges, mainSprite.hinges.Length + 1);
            mainSprite.hinges[mainSprite.hinges.Length - 1] = mySlaveLimbs[mySlaveLimbs.Length - 1].MasterHinge;
            newLimb.intMySlaveID = mainSprite.hinges.Length - 1;
        }

        public void subLimb(ref classSpriteLimb thisLimb)
        {
            if (thisLimb.myName.CompareTo(mySlaveLimbs[thisLimb.MySlaveID].myName) != 0)
                MessageBox.Show("we have a problem!");

            disposeAllHinges(ref thisLimb);

            mySlaveLimbs[thisLimb.MySlaveID] = mySlaveLimbs[mySlaveLimbs.Length - 1];
            Array.Resize<Sprite.classSpriteLimb>(ref mySlaveLimbs, mySlaveLimbs.Length - 1);
        }

        void disposeAllHinges(ref Sprite.classSpriteLimb thisLimb)
        {
            for (int intSlaveCounter =0; intSlaveCounter< mySlaveLimbs.Length; intSlaveCounter++)
                disposeAllHinges(ref mySlaveLimbs[intSlaveCounter]);

            for (int intHingeCounter =0; intHingeCounter < mainSprite.hinges.Length; intHingeCounter++)
                if (mainSprite.hinges[intHingeCounter].name.CompareTo(thisLimb.MasterHinge.name) == 0)
                {
                    mainSprite.hinges[intHingeCounter] = mainSprite.hinges[mainSprite.hinges.Length - 1];
                    Array.Resize<Sprite.classSpriteHinge>(ref mainSprite.hinges, mainSprite.hinges.Length - 1);
                }
        }
    }

    public class classSpriteMaker
    {
        udtSprite_StorageRetrieval udrStorageSprite;
        const int conMaxNameStringSize = 50;
        const string conStrNull = "---NULL---";

        public classSprite getSprite(bool masterLimbRotates, bool AlwaysVertical, string _myName, string MasterLimb_Name , params Bitmap[] bmpOriginal)
        {
            classSprite spriteRetVal = new classSprite();
            spriteRetVal.myName = _myName;
            spriteRetVal.MasterLimb = new classSpriteLimb(ref spriteRetVal, masterLimbRotates, AlwaysVertical, MasterLimb_Name, bmpOriginal);
            return spriteRetVal;
        }

        #region "Storage and Retrieval"
        public classSprite loadSprite(string strFilename)
        {
            udtSprite_StorageRetrieval udrThisSprite = new udtSprite_StorageRetrieval();
           
            int intcutchr = strFilename.IndexOf(".");
            if (intcutchr > 0)
                strFilename = strFilename.Substring(0, intcutchr);
            strFilename += ".spr";

            FileStream fs = new FileStream(strFilename, FileMode.Open);

            BinaryFormatter formatter = new BinaryFormatter();
            udrThisSprite.myName = (string)formatter.Deserialize(fs);

            int intNumLimbs = (int)formatter.Deserialize(fs);

            udrThisSprite.limbs = new udtLimb_StorageRetrieval[intNumLimbs];

            for (int intLimbCounter = 0; intLimbCounter < intNumLimbs; intLimbCounter++)
            {
                udrThisSprite.limbs[intLimbCounter].myName = (string)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].IRotate = (bool)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].AlwaysVertical = (bool)formatter.Deserialize(fs);
         
                udrThisSprite.limbs[intLimbCounter].bmp = (Bitmap)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].radMaster = new classMath.classRadialCoor();
                udrThisSprite.limbs[intLimbCounter].radMaster.angle = (double)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].radMaster.radius = (double)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].radSlave = new classMath.classRadialCoor();
                udrThisSprite.limbs[intLimbCounter].radSlave.angle = (double)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].radSlave.radius = (double)formatter.Deserialize(fs);

                udrThisSprite.limbs[intLimbCounter].MasterIndex = (int)formatter.Deserialize(fs);
                udrThisSprite.limbs[intLimbCounter].hingeName = (string)formatter.Deserialize(fs);
            }

            classSprite retval = getSprite(udrThisSprite.limbs[0].IRotate, udrThisSprite.limbs[0].AlwaysVertical, udrThisSprite.myName, udrThisSprite.limbs[0].myName, udrThisSprite.limbs[0].bmp);

            for (int intLimbCounter = 1; intLimbCounter < udrThisSprite.limbs.Length; intLimbCounter++)
            {
                Sprite.classSpriteLimb masterLimb = retval.getLimbByName(udrThisSprite.limbs[udrThisSprite.limbs[intLimbCounter].MasterIndex].myName);
                if (masterLimb == null)
                    masterLimb = retval.MasterLimb;
                Sprite.classSpriteLimb newLimb = new Sprite.classSpriteLimb(ref retval, 
                                            udrThisSprite.limbs[intLimbCounter].IRotate, 
                                            udrThisSprite.limbs[intLimbCounter].AlwaysVertical, 
                                            udrThisSprite.limbs[intLimbCounter].myName.Trim(), 
                                            udrThisSprite.limbs[intLimbCounter].bmp);
                masterLimb.addLimb(newLimb,
                                   udrThisSprite.limbs[intLimbCounter].hingeName.Trim(),
                                   new classMath.classRadialCoor(udrThisSprite.limbs[intLimbCounter].radMaster.angle, udrThisSprite.limbs[intLimbCounter].radMaster.radius),
                                   new classMath.classRadialCoor(udrThisSprite.limbs[intLimbCounter].radSlave.angle, udrThisSprite.limbs[intLimbCounter].radSlave.radius));
            }

            // load limb draw sequence here
            //
            int intNumDrawPointers = (int)formatter.Deserialize(fs);
            retval.limbDrawSequence = new classSpriteLimb[intNumDrawPointers];
            for (int intDrawCounter = 0; intDrawCounter < intNumDrawPointers; intDrawCounter++)
            {
                string strNameLimb = ((string)formatter.Deserialize(fs)).Trim();
                retval.limbDrawSequence[intDrawCounter] = retval.getLimbByName(strNameLimb);
                if (retval.limbDrawSequence[intDrawCounter] == null)
                        retval.limbDrawSequence[intDrawCounter] = retval.MasterLimb;
            }         

            // load configurations
            int intNumConfigurations = (int)formatter.Deserialize(fs);
           
            Array.Resize<classConfiguration >(ref retval.Configurations, intNumConfigurations);
            for (int intConfigurationCounter = 0; intConfigurationCounter < retval.Configurations.Length; intConfigurationCounter++)
            {
                classConfiguration  thisCon = new classConfiguration();
                thisCon.name = ((string)formatter.Deserialize(fs)).Trim();

                int intNumberLimbs= (int)formatter.Deserialize(fs);
                Array.Resize<classSpriteLimb>(ref thisCon.LimbDrawSequence, intNumberLimbs);
                for (int intLimbCounter = 0; intLimbCounter < thisCon.LimbDrawSequence.Length; intLimbCounter++)
                {
                    string strConLimbName = ((string)formatter.Deserialize(fs)).Trim();
                    thisCon.LimbDrawSequence[intLimbCounter] = retval.getLimbByName(strConLimbName);

                    if (thisCon.LimbDrawSequence[intLimbCounter] == null)
                        if (retval.MasterLimb.Name.ToUpper().Trim().CompareTo(strConLimbName.Trim().ToUpper()) == 0)
                            thisCon.LimbDrawSequence[intLimbCounter] = retval.MasterLimb;
                }

                int intNumSteps = (int)formatter.Deserialize(fs);
                Array.Resize<udtConfigurationStep>(ref thisCon.steps, intNumSteps);
                for (int intStepCounter = 0; intStepCounter < thisCon.steps.Length; intStepCounter++)
                {
                    Array.Resize<udtConfigurationStepHinge>(ref thisCon.steps[intStepCounter].hingeDetails, intNumberLimbs);
                    for (int intHingeCounter = 0; intHingeCounter < thisCon.steps[intStepCounter].hingeDetails.Length; intHingeCounter++)
                    {
                        string strConStepHingeName = ((string)formatter.Deserialize(fs)).Trim();
                        thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge = retval.getHingeByName(strConStepHingeName);
                        thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].angle = (double)formatter.Deserialize(fs);
                        thisCon.steps[intStepCounter].BmpCacheByMirrorType = new udtConfigurationStepBmpMirrortype[4];
                        for (int intMirrorType = 0; intMirrorType < 4; intMirrorType++)
                            thisCon.steps[intStepCounter].BmpCacheByMirrorType[intMirrorType].dir = new udtBmpAndPtTLInfo[16];
                    }
                }

                retval.Configurations[intConfigurationCounter] = thisCon;
            }
            fs.Close();

            return retval;
        }

        /// <summary>
        /// turns any string into a string of exact size (conMaxNameStringSize) for storage
        /// </summary>
        /// <param name="strName">input string of any length</param>
        /// <returns>output copy of input parameter set to specific storage string length</returns>
        string getNameFromString(string strName) { return (strName.Trim().PadRight(conMaxNameStringSize)).Substring(0, conMaxNameStringSize); }

        public void saveSprite(ref Sprite.classSprite thisSprite, string strFilename)
        {
            udrStorageSprite = new udtSprite_StorageRetrieval();
            udrStorageSprite.myName = getNameFromString(thisSprite.myName);
            udrStorageSprite.limbs = new udtLimb_StorageRetrieval[0];
            createStorageSpriteLimbs(ref thisSprite.MasterLimb);
           
            FileStream fs = new FileStream(strFilename, FileMode.Create);

            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(fs, udrStorageSprite.myName);
            
            formatter.Serialize(fs, udrStorageSprite.limbs.Length);

            for (int intLimbCounter = 0; intLimbCounter < udrStorageSprite.limbs.Length; intLimbCounter++)
            {
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].myName);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].IRotate);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].AlwaysVertical);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].bmp);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radMaster.angle);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radMaster.radius);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radSlave.angle);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].radSlave.radius);

                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].MasterIndex);
                formatter.Serialize(fs, udrStorageSprite.limbs[intLimbCounter].hingeName);
            }

            // save limb drawsequence
            formatter.Serialize(fs, thisSprite.limbDrawSequence.Length);
            for (int intLimbCounter = 0; intLimbCounter < thisSprite.limbDrawSequence.Length; intLimbCounter++)
            {
                if (thisSprite.limbDrawSequence[intLimbCounter] == null)
                    formatter.Serialize(fs, getNameFromString("---NULL---"));
                else 
                formatter.Serialize(fs, getNameFromString(thisSprite.limbDrawSequence[intLimbCounter].Name));
            }
            // save configuration info
            if (thisSprite.Configurations == null)
                formatter.Serialize(fs, 0);
            else
            {
                formatter.Serialize(fs, thisSprite.Configurations.Length);

                for (int intConfigurationCounter = 0; intConfigurationCounter < thisSprite.Configurations.Length; intConfigurationCounter++)
                {
                    classConfiguration thisCon = thisSprite.Configurations[intConfigurationCounter];
                    formatter.Serialize(fs, getNameFromString(thisCon.name));
                    formatter.Serialize(fs, thisCon.LimbDrawSequence.Length);

                    for (int intHingeCounter = 0; intHingeCounter < thisCon.LimbDrawSequence.Length; intHingeCounter++)
                        formatter.Serialize(fs, getNameFromString(thisCon.LimbDrawSequence[intHingeCounter].Name));

                    formatter.Serialize(fs, thisCon.steps.Length);

                    for (int intStepCounter = 0; intStepCounter < thisCon.steps.Length; intStepCounter++)
                    {
                        for (int intHingeCounter = 0; intHingeCounter < thisCon.steps[intStepCounter].hingeDetails.Length; intHingeCounter++)
                        {                            
                            if (thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge == null)
                            {
                                formatter.Serialize(fs, (getNameFromString(conStrNull)));
                                formatter.Serialize(fs, (double)0.0);
                            }
                            else
                            {
                                formatter.Serialize(fs, getNameFromString(thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].hinge.name));
                                formatter.Serialize(fs, thisCon.steps[intStepCounter].hingeDetails[intHingeCounter].angle);
                            }
                        }
                    }

                    thisSprite.Configurations[intConfigurationCounter] = thisCon;
                }
            }
            fs.Close();
        }

        void createStorageSpriteLimbs(ref Sprite.classSpriteLimb thisLimb)
        {
            Array.Resize<udtLimb_StorageRetrieval>(ref udrStorageSprite.limbs, udrStorageSprite.limbs.Length + 1);
            udtLimb_StorageRetrieval udrTemp = new udtLimb_StorageRetrieval();

            udrTemp.myName = getNameFromString(thisLimb.Name);

            udrTemp.AlwaysVertical = thisLimb.AlwaysVertical;
            udrTemp.IRotate = thisLimb.IRotate;
     
            udrTemp.bmp = thisLimb.udrSpriteLimbImages[0].bmp;

            udrTemp.radMaster = new classMath.classRadialCoor();
            udrTemp.radSlave = new classMath.classRadialCoor();
           
            try
            {
                udrTemp.radMaster.angle = thisLimb.MasterHinge.RadCoor_Master.angle;
                udrTemp.radMaster.radius = thisLimb.MasterHinge.RadCoor_Master.radius;
            }
            catch (Exception)
            {
                udrTemp.radMaster.angle = 0;
                udrTemp.radMaster.radius = 0;
            }

            try
            {
                udrTemp.radSlave.angle = thisLimb.MasterHinge.RadCoor_Slave.angle;
                udrTemp.radSlave.radius = thisLimb.MasterHinge.RadCoor_Slave.radius;
            }
            catch (Exception)
            {
                udrTemp.radSlave.angle = 0;
                udrTemp.radSlave.radius = 0;
            }

            try
            { udrTemp.MasterIndex = getLimbIndex(thisLimb.MasterHinge.Limb_Master.Name); }
            catch (Exception)
            { udrTemp.MasterIndex = 0; }

            try
            { udrTemp.hingeName = getNameFromString(thisLimb.MasterHinge.name); }
            catch (Exception)
            { udrTemp.hingeName = ""; }

            udrStorageSprite.limbs[udrStorageSprite.limbs.Length - 1] = udrTemp;
            if (thisLimb.mySlaveLimbs != null)
                for (int intSlaveCounter = 0; intSlaveCounter < thisLimb.mySlaveLimbs.Length; intSlaveCounter++)
                    createStorageSpriteLimbs(ref thisLimb.mySlaveLimbs[intSlaveCounter]);
        }

        int getLimbIndex(string strName)
        {
            for (int intLimbCounter = 0; intLimbCounter < udrStorageSprite.limbs.Length; intLimbCounter++)
                if (udrStorageSprite.limbs[intLimbCounter].myName.Trim().CompareTo(strName) == 0)
                    return intLimbCounter;
            return -1;
        }

        #endregion
    }

    public struct udtBmpAndPtTLInfo
    {
        public Bitmap bmp;
        public Point ptTL;
        public udtConfigStepLimbPosition[] limbPositions;
    }

    public struct udtConfigStepLimbPosition
    {
        public classSpriteLimb limb;
        public Point pt;
    }

    public struct udtConfigurationStepBmpMirrortype
    {
        public udtBmpAndPtTLInfo[] dir;
    }

    public struct udtConfigurationStep
    {
        public udtConfigurationStepHinge[] hingeDetails;
        public udtConfigurationStepBmpMirrortype[] BmpCacheByMirrorType;
    }

    public struct udtConfigurationStepHinge
    {
        public classSpriteHinge hinge;
        public double angle;
    }

    public class classConfiguration
    {
        public string name;
        public classSpriteLimb[] LimbDrawSequence;
        public udtConfigurationStep[] steps;

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// </summary>
        /// <param name="strLimbName">name of limb whose position is to be determined</param>
        /// <param name="mirror">type of mirror image : vertical, horizontal or both</param>
        /// <param name="intStep">configuration's step index</param>
        /// <param name="intDir">direction(0-15 where east is 0) of the master block</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(string strLimbName, enuMirror mirror, int intStep, int intDir)
        {
            strLimbName = strLimbName.ToUpper().Trim();
            for (int intLimbCounter = 0; intLimbCounter < LimbDrawSequence.Length; intLimbCounter++)
            {
                if (strLimbName.CompareTo(LimbDrawSequence[intLimbCounter].Name.Trim().ToUpper()) == 0)
                {
                    return getLimbPos(intLimbCounter, mirror, intStep, intDir);
                }
            }
            return new Point(0, 0);
        }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// assumes mirror = none, and intDir = 0(east)
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="intStep">configuration's step index</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, int intStep)
        { return getLimbPos(intLimbDrawSequenceIndex, enuMirror.none, intStep, 0); }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// assumes intDir =0(east)
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="mirror">type of mirror image : vertical, horizontal or both</param>
        /// <param name="intStep">configuration's step index</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, enuMirror mirror, int intStep)
        { return getLimbPos(intLimbDrawSequenceIndex, mirror, 0, intStep); }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// assumes mirror = none
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="intStep">configuration's step index</param>
        /// <param name="intDir">direction(0-15 where east is 0) of the master block</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, int intStep, int intDir)
        { return getLimbPos(intLimbDrawSequenceIndex, enuMirror.none, intStep, intDir); }

        /// <summary>
        /// returns the position of the limb identified by a string with reference to the master limb centered at the sprite's 'loc' for this specific configuration
        /// </summary>
        /// <param name="intLimbDrawSequenceIndex">index in drawsequence of limb whose position is to be determined</param>
        /// <param name="mirror">type of mirror image : vertical, horizontal or both</param>
        /// <param name="intStep">configuration's step index</param>
        /// <param name="intDir">direction(0-15 where east is 0) of the master block</param>
        /// <returns>returns the location of limb relative to master limb</returns>
        public Point getLimbPos(int intLimbDrawSequenceIndex, enuMirror mirror, int intStep, int intDir)
        { return steps[intStep].BmpCacheByMirrorType[(int)mirror].dir[intDir].limbPositions[intLimbDrawSequenceIndex].pt; }

        /// <summary>
        /// returns the index of a limb in this configuration's DrawSequence identified by its name string
        /// </summary>
        /// <param name="strLimbName">name of limb to find</param>
        /// <returns>integer index of limb in drawSequence array, -1 if not found</returns>
        public int getLimbDrawSequenceIndex(string strLimbName)
        {
            strLimbName = strLimbName.ToUpper().Trim();
            for (int intLimbCounter = 0; intLimbCounter < LimbDrawSequence.Length; intLimbCounter++)
                if (strLimbName.CompareTo(LimbDrawSequence[intLimbCounter].Name.Trim().ToUpper()) == 0)
                    return intLimbCounter;

            return -1;
        }
    }
    
    public class classSprite
    {
        public classSpriteLimb MasterLimb;
        public classConfiguration[] Configurations;
        public classConfiguration conCurrent;
        public int intConfigurationStep_Current;

        /// <summary>
        /// array of pointers to the sprite's limbs equal in size to the size of the actual limbs & hinges arrays
        /// the order in which the limbs are drawn is controlled by the order in which their pointers appear in this array.
        /// only the limbs listed in this array will be drawn by the 'putSpriteToScreen()' function
        /// </summary>
        public classSpriteLimb[] limbDrawSequence;

        string strMyName = "";
        public string myName
        {
            get { return strMyName; }
            set { strMyName = value; }
        }

        double dblDisplaySize = 1.0;
        /// <summary>
        /// double variable factor which determines size of output image relative to original images size where 1.0 is the same
        /// </summary>
        public double DisplaySize
        {
            get { return dblDisplaySize; }
            set { dblDisplaySize = value; }
        }

        public Sprite.classSpriteHinge[] hinges = new classSpriteHinge[0];
        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="intConfigurationIndex">sprite's output configuration index value</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 int intConfigurationIndex,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation)
        {
            putConfigurationOnScreen(ref bmpOutput,
                                         intConfigurationIndex,
                                         intConfigurationStep,
                                         ptOnScreenLocation,
                                         0,
                                         DisplaySize,
                                         enuMirror.none,
                                        false);
        }

        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="strConfigurationName">sprite's output configuration name</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 string strConfigurationName,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation)
        {
            putConfigurationOnScreen(ref bmpOutput,
                                         getIndexOfConfigurationByName(strConfigurationName),
                                         intConfigurationStep,
                                         ptOnScreenLocation,
                                         0,
                                         DisplaySize,
                                         enuMirror.none,
                                        false);
        }

        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="strConfigurationName">sprite's output configuration name</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        /// <param name="DisplaySize">double variable which is multiplied times all size relevant parameters in the drawing sequence 1.0=original image size</param>
        /// <param name="mirror">configuration image reflected in any of four directions, (none, vertical, horizontal or both)</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 string strConfigurationName,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation,
                                                 double displaySize,
                                                 enuMirror mirror)
        {
            putConfigurationOnScreen(ref bmpOutput,
                                        getIndexOfConfigurationByName(strConfigurationName),
                                        intConfigurationStep,
                                        ptOnScreenLocation,
                                        0,
                                        displaySize,
                                        mirror,
                                        false);
        }

        /// <summary>
        /// displays the sprite in the specified configuration and step at a point on referenced bitmap
        /// all of the sprite's hinges are set to their specified configuration and step values
        /// </summary>
        /// <param name="bmpOutput">reference bitmap on which the sprite is to be drawn</param>
        /// <param name="intConfigurationIndex">sprite's output configuration index value</param>
        /// <param name="intConfigurationStep">sprite's output configuration step value</param>
        /// <param name="ptOnScreenLocation">point on the screen where the center of the sprite's master limb is to be located</param>
        /// <param name="DisplaySize">double variable which is multiplied times all size relevant parameters in the drawing sequence 1.0=original image size</param>
        /// <param name="mirror">configuration image reflected in any of four directions, (none, vertical, horizontal or both)</param>
        public void putConfigurationOnScreen(ref Bitmap bmpOutput,
                                                 int intConfigurationIndex,
                                                 int intConfigurationStep,
                                                 Point ptOnScreenLocation,
                                                 double dblAngle,
                                                 double DisplaySize,
                                                 enuMirror mirror,
                                                 bool bolForceRebuild)
        {
            if (bmpOutput == null) 
                return;

            if (Configurations.Length <= intConfigurationIndex
                || intConfigurationIndex <0
                || intConfigurationStep <0
                || Configurations[intConfigurationIndex].steps == null 
                || Configurations[intConfigurationIndex].steps.Length <= intConfigurationStep
               )
                return;

            conCurrent = Configurations[intConfigurationIndex];
            intConfigurationStep_Current = intConfigurationStep;

            if (MasterLimb.IRotate)
            {
                MasterLimb.Angle = dblAngle;
                MasterLimb.setDir();
            }

            setSpriteHingesToConfiguration(intConfigurationIndex, intConfigurationStep);

            if (Configurations[intConfigurationIndex].steps != null)
            {
                if (Configurations[intConfigurationIndex].steps[intConfigurationStep].BmpCacheByMirrorType[(int)mirror].dir[MasterLimb.Dir].bmp == null
                    || bolForceRebuild)
                {
                    classSpriteLimb[] limDrawSequence = Configurations[intConfigurationIndex].LimbDrawSequence;
                    Configurations[intConfigurationIndex].steps[intConfigurationStep].BmpCacheByMirrorType[(int)mirror].dir[MasterLimb.Dir] = getImageOnBitmap(DisplaySize, mirror, limDrawSequence);
                }
                drawImageOnoutPutBitmap(ref bmpOutput,
                                            Configurations[intConfigurationIndex].steps[intConfigurationStep].BmpCacheByMirrorType[(int)mirror].dir[MasterLimb.Dir],
                                            ptOnScreenLocation);
            }
        }

        /// <summary>
        /// this function arranges the sprite's hinges according to the values stored in its configurations for a specific configuration & step
        /// </summary>
        /// <param name="intConfigurationIndex">configuration index to which hinges are to be set</param>
        /// <param name="intConfigurationStep">configuration step to which hinges are to be set</param>
        public void setSpriteHingesToConfiguration(int intConfigurationIndex, int intConfigurationStep)
        {

            for (int intHingeCounter = 0;
                 intHingeCounter < Configurations[intConfigurationIndex].steps[intConfigurationStep].hingeDetails.Length;
                 intHingeCounter++)
                try
                {
                    Configurations[intConfigurationIndex]
                        .steps[intConfigurationStep]
                        .hingeDetails[intHingeCounter].hinge.Angle
                          = Configurations[intConfigurationIndex].steps[intConfigurationStep].hingeDetails[intHingeCounter]
                                            .angle;
                }
                catch (Exception ) { }
        }

        /// <summary>
        /// draws this sprite onto bitmap at point
        /// </summary>
        /// <param name="bmpOutput">bitmap onto which this sprite is drawn given its current configuration</param>
        /// <param name="ptOnScreenLocation">location on bitmap where this sprite is drawn</param>
        public void putImageOnScreen(ref Bitmap bmpOutput, Point ptOnScreenLocation)
        { putImageOnScreen(ref bmpOutput, ptOnScreenLocation, dblDisplaySize, enuMirror.none); }

        /// <summary>
        /// draws this sprite onto bitmap at point
        /// </summary>
        /// <param name="bmpOutput">bitmap onto which this sprite is drawn given its current configuration</param>
        /// <param name="ptOnScreenLocation">location on bitmap where this sprite is drawn</param>
        /// <param name="DisplaySize">factor by which images are multiplied, e.g. 1.0 original size, 2.0 twice original & 0.5 half original size</param>
        public void putImageOnScreen(ref Bitmap bmpOutput, Point ptOnScreenLocation, double DisplaySize, enuMirror mirror)
        {
            if (bmpOutput == null)
                return;

            if (MasterLimb.IRotate)
                MasterLimb.setDir();

            udtBmpAndPtTLInfo udrTemp = getImageOnBitmap(DisplaySize, mirror, limbDrawSequence);
            drawImageOnoutPutBitmap(ref bmpOutput, udrTemp, ptOnScreenLocation);
        }

        void drawImageOnoutPutBitmap(ref Bitmap bmpOutput,udtBmpAndPtTLInfo udrBmpAndPtTL,  Point ptOnScreenLocation)
        {
            using (Graphics g = Graphics.FromImage(bmpOutput))
            { g.DrawImage(udrBmpAndPtTL.bmp, new Point(ptOnScreenLocation.X + udrBmpAndPtTL.ptTL.X, ptOnScreenLocation.Y + udrBmpAndPtTL.ptTL.Y)); }

            for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
            {
                hinges[intLimbCounter].Limb_Slave.Loc = new Point(ptOnScreenLocation.X + udrBmpAndPtTL.ptTL.X + hinges[intLimbCounter].Limb_Slave.Loc.X,
                                                                  ptOnScreenLocation.Y + udrBmpAndPtTL.ptTL.Y + hinges[intLimbCounter].Limb_Slave.Loc.Y);
            }
            MasterLimb.Loc = ptOnScreenLocation;
        }

        /// <summary>
        /// this function returns the sprite's image, as it appears with the hinges
        /// already set, onto the largest bitmap that will fit the resultant image
        /// </summary>
        /// <param name="DisplaySize">factor by which the original image size is multiplied before out is generated</param>
        /// <param name="mirror">mirror option, e.g. horizontal, vertical, both or neither</param>
        /// <param name="limDrawSequence">classSpriteLimb array specifying in which order the different limbs are to be put onto the screen/param>
        /// <returns>returns a structure of type udtBmpAndPTTLInfo which holds the largest bitmap that will fit the output image it contains.
        /// the center of the image is not necessarily the center of the bitmap but is described by the point ptTL</returns>
        public udtBmpAndPtTLInfo getImageOnBitmap(double DisplaySize, 
                                                  enuMirror mirror,
                                                  classSpriteLimb[] limDrawSequence)
        {
            udtBmpAndPtTLInfo udrRetVal = new udtBmpAndPtTLInfo();

            MasterLimb.Loc = new Point(0, 0);
            putImageOntoScreen_recursion(ref MasterLimb, DisplaySize);

            udrRetVal.ptTL = new Point(-MasterLimb.myCurrentImage.bmp.Width / 2, -MasterLimb.myCurrentImage.bmp.Height / 2);
            Point ptBR = new Point(MasterLimb.myCurrentImage.bmp.Width / 2, MasterLimb.myCurrentImage.bmp.Height / 2);

            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
            {
                Sprite.classSpriteLimb thisLimb= hinges[intHingeCounter].Limb_Slave;
                if (thisLimb.recDest.Left < udrRetVal.ptTL.X)
                    udrRetVal.ptTL.X = thisLimb.recDest.Left;
                if (thisLimb.recDest.Left + thisLimb.recDest.Width > ptBR.X)
                    ptBR.X = thisLimb.recDest.Left + thisLimb.recDest.Width;
                if (thisLimb.recDest.Top < udrRetVal.ptTL.Y)
                    udrRetVal.ptTL.Y = thisLimb.recDest.Top;
                if (thisLimb.recDest.Top + thisLimb.recDest.Height > ptBR.Y)
                    ptBR.Y = thisLimb.recDest.Top + thisLimb.recDest.Height;
            }

            if (ptBR.X == udrRetVal.ptTL.X)
                ptBR.X += 1;
            if (ptBR.Y == udrRetVal.ptTL.Y)
                ptBR.Y += 1;

            udrRetVal.bmp  = new Bitmap(ptBR.X - udrRetVal.ptTL.X, ptBR.Y - udrRetVal.ptTL.Y);
            using (Graphics g = Graphics.FromImage(udrRetVal.bmp))
            {
                if (limDrawSequence != null)
                {
                    udrRetVal.limbPositions = new udtConfigStepLimbPosition[limDrawSequence.Length];
                    
                    for (int intLimbCounter = 0; intLimbCounter < limDrawSequence.Length; intLimbCounter++)
                    {
                        Sprite.classSpriteLimb thisLimb = limDrawSequence[intLimbCounter];
                        
                        if (thisLimb != null)
                        {
                            thisLimb.myCurrentImage.bmp.MakeTransparent();
                            Point ptPos = new Point((int)(-udrRetVal.ptTL.X + thisLimb.recDest.Left), (int)(-udrRetVal.ptTL.Y + thisLimb.recDest.Top));
                            thisLimb.Loc = new Point(ptPos.X + (int)(thisLimb.myCurrentImage.bmp.Width * DisplaySize / 2),
                                                     ptPos.Y + (int)(thisLimb.myCurrentImage.bmp.Height * DisplaySize / 2));
                            if (conCurrent != null)
                            {
                                int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(thisLimb.Name.ToString());
                                if (intDrawSequenceIndex >= 0)
                                {
                                    udrRetVal.limbPositions[intDrawSequenceIndex].limb = thisLimb;
                                    udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(thisLimb.Loc.X - MasterLimb.Loc.X, thisLimb.Loc.Y - MasterLimb.Loc.Y);
                                }
                            }
                            g.DrawImage(new Bitmap(thisLimb.myCurrentImage.bmp, thisLimb.recDest.Size), ptPos);
                        }
                    }
                }
            }

            if (mirror == enuMirror.vertical)
            {
                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
                for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
                {
                    if (conCurrent != null)
                    {
                        int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(hinges[intLimbCounter].Limb_Slave.Name.ToString());
                        if (intDrawSequenceIndex >= 0)
                        {
                            udrRetVal.limbPositions[intDrawSequenceIndex].limb = hinges[intLimbCounter].Limb_Slave;

                            udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(udrRetVal.limbPositions[intDrawSequenceIndex].pt.X,
                                                                                         -udrRetVal.limbPositions[intDrawSequenceIndex].pt.Y);
                        }
                    }
                    hinges[intLimbCounter].Limb_Slave.Loc = new Point(hinges[intLimbCounter].Limb_Slave.Loc.X, udrRetVal.bmp.Height - hinges[intLimbCounter].Limb_Slave.Loc.Y);
                }
                udrRetVal.ptTL.Y = -ptBR.Y;
            }
            else if (mirror == enuMirror.horizontal)
            {
                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipX);
                for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
                {
                    if (conCurrent != null)
                    {
                        int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(hinges[intLimbCounter].Limb_Slave.Name.ToString());
                        if (intDrawSequenceIndex >= 0)
                        {
                            udrRetVal.limbPositions[intDrawSequenceIndex].limb = hinges[intLimbCounter].Limb_Slave;
                            udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(-udrRetVal.limbPositions[intDrawSequenceIndex].pt.X ,
                                                                                         udrRetVal.limbPositions[intDrawSequenceIndex].pt.Y );
                        }
                    }
                    hinges[intLimbCounter].Limb_Slave.Loc = new Point(udrRetVal.bmp.Width - hinges[intLimbCounter].Limb_Slave.Loc.X, hinges[intLimbCounter].Limb_Slave.Loc.Y);
                }  
                udrRetVal.ptTL.X = -ptBR.X;
            }
            else if (mirror == enuMirror.VerticalAndHorizontal)
            {
                udrRetVal.bmp.RotateFlip(RotateFlipType.RotateNoneFlipXY);
                for (int intLimbCounter = 0; intLimbCounter < hinges.Length; intLimbCounter++)
                {
                    if (conCurrent != null)
                    {
                        int intDrawSequenceIndex = conCurrent.getLimbDrawSequenceIndex(hinges[intLimbCounter].Limb_Slave.Name.ToString());
                        if (intDrawSequenceIndex >= 0)
                        {
                            udrRetVal.limbPositions[intDrawSequenceIndex].limb = hinges[intLimbCounter].Limb_Slave;
                            udrRetVal.limbPositions[intDrawSequenceIndex].pt = new Point(-udrRetVal.limbPositions[intDrawSequenceIndex].pt.X,
                                                                                         -udrRetVal.limbPositions[intDrawSequenceIndex].pt.Y);
                        }
                    }
                    hinges[intLimbCounter].Limb_Slave.Loc = new Point(udrRetVal.bmp.Width - hinges[intLimbCounter].Limb_Slave.Loc.X,
                                                                          udrRetVal.bmp.Height - hinges[intLimbCounter].Limb_Slave.Loc.Y);
                }
                udrRetVal.ptTL = new Point(-ptBR.X, -ptBR.Y);
            }
            udrRetVal.bmp.MakeTransparent();
            return udrRetVal;
        }

        /// <summary>
        /// this function receives a limb which has already been angled and positioned
        /// this limb then places all of its slaves limbs by setting their respective positions & angles
        /// then calls itself once for each slave that recurses with each of these limbs
        /// </summary>
        /// <param name="thisLimb">reference to this recursion's master-limb which will recurse for each of its slave limbs</param>
        /// <param name="dblLocalSizeFactor">factor by which original image is multiplied when calculating positions of slave limbs</param>
        public void putImageOntoScreen_recursion(ref classSpriteLimb thisLimb, 
                                                 double dblLocalSizeFactor)
        {
            if (thisLimb.IRotate)
                thisLimb.setDir();
            thisLimb.myCurrentImage = thisLimb.getSpriteImageFromArray();
            thisLimb.recDest = new Rectangle(new Point(thisLimb.Loc.X - (int)(thisLimb.myCurrentImage.bmp.Width * dblLocalSizeFactor / 2), 
                                                       thisLimb.Loc.Y - (int)(thisLimb.myCurrentImage.bmp.Height * dblLocalSizeFactor / 2)), 
                                             new Size((int)((double)thisLimb.myCurrentImage.bmp.Size.Width * dblLocalSizeFactor), 
                                                      (int)((double)thisLimb.myCurrentImage.bmp.Size.Height * dblLocalSizeFactor)));
            if (thisLimb.recDest.Width < 1)
                thisLimb.recDest.Width = 1;
            if (thisLimb.recDest.Height < 1)
                thisLimb.recDest.Height = 1;

            if (thisLimb.mySlaveLimbs != null)
                for (int intSlaveCounter = 0; intSlaveCounter < thisLimb.mySlaveLimbs.Length; intSlaveCounter++)
                {
                    double dblNewAngle = thisLimb.Angle
                                       + thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.Angle;
                    thisLimb.mySlaveLimbs[intSlaveCounter].Angle = dblNewAngle;
                    thisLimb.mySlaveLimbs[intSlaveCounter].setDir();

                    Point ptOnMaster = new Point(thisLimb.Loc.X + (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.radius * dblLocalSizeFactor * Math.Cos(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.angle - thisLimb.Angle)),
                                                 thisLimb.Loc.Y - (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.radius * dblLocalSizeFactor * Math.Sin(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Master.angle - thisLimb.Angle)));

                    thisLimb.mySlaveLimbs[intSlaveCounter].Loc = new Point(ptOnMaster.X + (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.radius * dblLocalSizeFactor * Math.Cos(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.angle + thisLimb.mySlaveLimbs[intSlaveCounter].Angle + Math.PI)),
                                                                           ptOnMaster.Y + (int)(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.radius * dblLocalSizeFactor * Math.Sin(thisLimb.mySlaveLimbs[intSlaveCounter].MasterHinge.RadCoor_Slave.angle + thisLimb.mySlaveLimbs[intSlaveCounter].Angle + Math.PI)));

                    putImageOntoScreen_recursion(ref  thisLimb.mySlaveLimbs[intSlaveCounter], 
                                                dblLocalSizeFactor);
                }
        }

        /// <summary>
        /// returns a pointer to the limb identified by name
        /// </summary>
        /// <param name="LimbName">name of the limb to be searched</param>
        /// <returns>returns a pointer to an object of type classSpriteLimb</returns>
        public Sprite.classSpriteLimb getLimbByName(string LimbName)
        {
            LimbName = LimbName.Trim().ToUpper();
            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
            {
                if (hinges[intHingeCounter].Limb_Slave.Name.Trim().ToUpper().CompareTo(LimbName) == 0)
                    return hinges[intHingeCounter].Limb_Slave;
            }
            if (MasterLimb.Name.Trim().CompareTo(LimbName) == 0)
                return MasterLimb;
            return null;
        }

        /// <summary>
        /// returns a pointer to the hinge identified by name
        /// </summary>
        /// <param name="HingeName">name of hinge to be searched</param>
        /// <returns>returns a pointer to an object of type classSpriteHinge </returns>
        public Sprite.classSpriteHinge getHingeByName(string HingeName)
        {
            HingeName = HingeName.ToUpper();
            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
                if (hinges[intHingeCounter].name.ToUpper().CompareTo(HingeName) == 0)
                    return hinges[intHingeCounter];
            return null;
        }

        public Sprite.classConfiguration getConfigurationByName(string ConfigurationName)
        {
            ConfigurationName = ConfigurationName.Trim().ToUpper();
            for (int intConfigurationCounter = 0; intConfigurationCounter < Configurations.Length; intConfigurationCounter++)
                if (Configurations[intConfigurationCounter].name.Trim().ToUpper().CompareTo(ConfigurationName) == 0)
                    return Configurations[intConfigurationCounter];
            return null;
        }

        public int  getIndexOfConfigurationByName(string ConfigurationName)
        {
            ConfigurationName = ConfigurationName.Trim().ToUpper();
            for (int intConfigurationCounter = 0; intConfigurationCounter < Configurations.Length; intConfigurationCounter++)
                if (Configurations[intConfigurationCounter].name.Trim().ToUpper().CompareTo(ConfigurationName) == 0)
                    return intConfigurationCounter;
            return -1;
        }

        public int getIndexOfHingeByName(string hingeName)
        {
            hingeName = hingeName.Trim().ToUpper();
            for (int intHingeCounter = 0; intHingeCounter < hinges.Length; intHingeCounter++)
                if (hinges[intHingeCounter].name.Trim().ToUpper().CompareTo(hingeName) == 0)
                    return intHingeCounter;
            return -1;
        }

        public int getIndexOfLimbByName(string limbName)
        {
            limbName = limbName.Trim().ToUpper();
            for (int intlimbCounter = 0; intlimbCounter < hinges.Length; intlimbCounter++)
                if (hinges[intlimbCounter].Limb_Slave.Name.Trim().ToUpper().CompareTo(limbName) == 0)
                    return intlimbCounter;
            return -1;
        }
    }
}

public class classMath 
{
    public class classMaxMinDouble
    {
        public double Min;
        public double Max;

        public classMaxMinDouble()
        {
            Min = 0.0;
            Max = 0.0;
        }

        public classMaxMinDouble(double min, double max)
        {
            Min = min;
            Max = max;
        }
    }
    
    public class classRadialCoor
    {
        public double angle;
        public double radius;

        public classRadialCoor()
        {
            angle = 0;
            radius = 0;
        }
        public classRadialCoor(double Angle, double Radius)
        {
            angle = Angle;
            radius = Radius;
        }
    }

    /// <summary>
    /// converts a radial coordinate system into cartesian with origin as initial coordinate
    /// </summary>
    /// <param name="radCoor">radial vector</param>
    /// <returns>cartesian point</returns>
    public Point getRadLocation(classRadialCoor radCoor) { return getRadLocation(new Point(0, 0), radCoor); }

    /// <summary>
    /// calculates the cartesian location away from input point using radial vector
    /// </summary>
    /// <param name="pt">input point from which </param>
    /// <param name="radCoor">radial vector</param>
    /// <returns>cartesian point</returns>
    public Point getRadLocation(Point pt, classRadialCoor radCoor)
    { return new Point((int)(pt.X + radCoor.radius * Math.Cos(radCoor.angle)), (int)(pt.Y + radCoor.radius * Math.Sin(radCoor.angle))); }

    /// <summary>
    /// returns the angle in radians between the points ptA and ptB
    /// </summary>
    /// <param name="ptA">first point</param>
    /// <param name="ptB">second point</param>
    /// <returns>double variable equal to angle between origin and point(dX, dY) in radians</returns>
    public double arcTan(Point ptA, Point ptB) { return arcTan(ptA.X - ptB.X, ptA.Y - ptB.Y); }
    /// <summary>
    /// returns the angle in radians between the origin and the point located at (dX, dY)
    /// </summary>
    /// <param name="dX">x coordinate of vector end</param>
    /// <param name="dY">y coordinate of vector end</param>
    /// <returns>double variable equal to angle between origin and point(dX, dY) in radians</returns>
    public double arcTan(double dX, double dY)
    {
        double dblAngle = 0;
        if (dX == 0)
            if (dY < 0)
                dblAngle = 3.0 * Math.PI / 2.0;
            else
                dblAngle = Math.PI / 2.0;
        else
        {
            dblAngle = Math.Atan((double)dY / (double)dX);
            //  Q2 Q1
            //  Q3 Q4
            if (dX < 0)
            {
                if (dY < 0) // Q3
                    dblAngle = Math.PI + dblAngle;
                else              // Q2
                    dblAngle = Math.PI + dblAngle;
            }
            else if (dX > 0)
            {
                if (dY < 0) // Q4
                    dblAngle = 2.0 * Math.PI + dblAngle;
                else              // Q1
                    ;
            }
        }
        cleanAngle(ref dblAngle);
        return dblAngle;
    }

    public void cleanRadians(ref classRadialCoor udrRadCoor) { cleanAngle(ref udrRadCoor.angle); }
    public double cleanAngle(ref double angle)
    {
        while (angle < 0)
            angle += 2 * Math.PI;

        while (angle > 2 * Math.PI)
            angle -= 2 * Math.PI;

        return angle;
    }

    public double distanceBetweenTwoPoints(Point pt1, Point pt2) { return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2)); }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Christ Kennedy
CEO unemployable
Canada Canada
Christ Kennedy, published his fourth novel "Cleats of the Counter Revolution" in the summer of 2010. He grew up in the suburbs of Montreal and is a bilingual Quebecois with a bachelor’s degree in computer engineering from McGill University and is currently walking across ontario plotting a new novel, far away from any computer.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 27 Jan 2010
Article Copyright 2010 by Christ Kennedy
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid