Subversion Repositories AndroidProjects

Rev

Rev 1428 | Blame | Compare with Previous | Last modification | View Log | RSS feed

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using BauzoidNET.math;

namespace BauzoidNET.graphics.sprite
{
    public class SpriteTransform
    {
        public float X
        {
            get { return x; }
            set { x = value; }
        }

        public float Y
        {
            get { return y; }
            set { y = value; }
        }

        public float Width
        {
            get { return w; }
            set { w = value; }
        }

        public float Height
        {
            get { return h; }
            set { h = value; }
        }

        public float PivotX
        {
            get { return pivotX; }
            set { pivotX = value; }
        }

        public float PivotY
        {
            get { return pivotY; }
            set { pivotY = value; }
        }

        public float Angle
        {
            get { return angle; }
            set { angle = value; }
        }

        public bool MirrorX
        {
            get { return mirrorX; }
            set { mirrorX = value; }
        }

        public bool MirrorY
        {
            get { return mirrorY; }
            set { mirrorY = value; }
        }


        public float x = 0.0f;
        public float y = 0.0f;

        public float w = 0.0f;
        public float h = 0.0f;

        /** Angle in degrees. */
        public float angle = 0.0f;

        public bool mirrorX = false;
        public bool mirrorY = false;

        /** Rotation and scaling pivot point in absolute coordinates. */
        public float pivotX = 0.0f;
        public float pivotY = 0.0f;

        public override string ToString()
        {
            return "SpriteTransform";        
        }

        public SpriteTransform()
            {
            }
       
            public void set(SpriteTransform param)
            {
                    x = param.x;
                    y = param.y;
                    w = param.w;
                    h = param.h;
                    pivotX = param.pivotX;
                    pivotY = param.pivotY;
                    angle = param.angle;
                    mirrorX = param.mirrorX;
                    mirrorY = param.mirrorY;
            }

        public void set(float _x, float _y, float _w, float _h, bool _centerPivot = true)
        {
            x = _x; y = _y; w = _w; h = _h;
            if (_centerPivot)
                centerPivot();
        }

        public void set(float _x, float _y, float _w, float _h, float _pivotX, float _pivotY)
        {
            x = _x; y = _y; w = _w; h = _h;
            pivotX = _pivotX; pivotY = _pivotY;
        }

        public void setPosition(float _x, float _y)
        {
            x = _x; y = _y;
        }

        public void setSize(float _w, float _h)
        {
            w = _w; h = _h;
        }

        public void setPivot(float _pivotX, float _pivotY)
        {
            pivotX = _pivotX; pivotY = _pivotY;
        }


        public void centerPivot()
        {
                pivotX = w/2.0f;
            pivotY = h/2.0f;
            }
               
            /** Calculate a 4x4 Matrix that transforms from normalized sprite space (coordinates in [-1..1] range) to world space. */
            public Matrix4 getNormalizedTransform()
            {
                    Matrix4 result = Matrix4.createIdentity();
               
                    Matrix4.multiply(result, result, Matrix4.createScale((mirrorX ? -1 : 1), (mirrorY ? -1 : 1), 1));
                    Matrix4.multiply(result, result, Matrix4.createScale(w/2, h/2, 1.0f));
                    Matrix4.multiply(result, result, Matrix4.createTranslation(-pivotX+w/2, -pivotY+h/2, 0));
                    Matrix4.multiply(result, result, Matrix4.createRotationZ(angle));
                    Matrix4.multiply(result, result, Matrix4.createTranslation(x, y, 0));
               
                    return result;
            }
       
            /** Calculate a 4x4 Matrix that transforms points from sprite space to world space. */
            public Matrix4 getTransform()
            {
                    Matrix4 result = Matrix4.createIdentity();

                    Matrix4.multiply(result,  result, Matrix4.createTranslation(-w/2, -h/2, 0));
                    Matrix4.multiply(result, result, Matrix4.createScale((mirrorX ? -1 : 1), (mirrorY ? -1 : 1), 1));
                    Matrix4.multiply(result,  result, Matrix4.createTranslation(w/2, h/2, 0));
                    Matrix4.multiply(result,  result, Matrix4.createTranslation(-pivotX, -pivotY, 0));
                    Matrix4.multiply(result, result, Matrix4.createRotationZ(angle));
                    Matrix4.multiply(result,  result, Matrix4.createTranslation(x, y, 0));
               
                    return result;
            }
       
            /** Transform a point that is specified in sprite space into world space.
                * pX/pY is defined in sprite pixel space. */

            public Vector2 spriteToWorld(float pX, float pY)
            {
                    return spriteToWorld(pX, pY, false);
            }
       
            /** Transform a point that is specified in sprite space into world space.
                * pX/pY is defined in sprite pixel space. */

            public Vector2 spriteToWorld(float pX, float pY, bool ignoreMirror)
            {
                    Vector2 result = new Vector2();
               
                    spriteToWorld(pX, pY, ignoreMirror, result);               
               
                    return result;
            }
       
            /** Transform a point that is specified in sprite space into world space.
                * pX/pY is defined in sprite pixel space. */

            public void spriteToWorld(float pX, float pY, Vector2 result)
            {
                    spriteToWorld(pX, pY, false, result);
            }
       
            /** Transform a point that is specified in sprite space into world space.
                * pX/pY is defined in sprite pixel space. */

            public void spriteToWorld(float pX, float pY, bool ignoreMirror, Vector2 result)
            {
                    // Step 1. Find out the relative position of (pX/pY) to the pivot point
                    // Step 1a. Translate px/pY so that it's coordinates are relative to the pivot point (pivot point becomes origin)
                    // Step 1b. Rotate around pivot point
                    // Step 2a. Move back to original space
                    // Step 2b. Add x/y to the relative position
                    result.x = 0;
                    result.y = 0;
               
                    if (!ignoreMirror)
                    {
                            // mirror in sprite space
                            if (mirrorX)
                                    pX = w - pX;
                       
                            if (mirrorY)
                                    pY = h - pY;
                    }
       
                    float relativeToPivotX = pX - pivotX;
                    float relativeToPivotY = pY - pivotY;
               
                    // rotate relativeToPivotX/Y around pivot (which has become origin now)
                    if (angle != 0)
                    {
                            float cos = MathUtil.cos(angle);
                       
                            // Rotate CCW (like Matrix4.CreateRotationZ).
                            float sin = MathUtil.sin(-angle);
                       
                            result.x = relativeToPivotX * cos - relativeToPivotY * sin;
                            result.y = relativeToPivotX * sin + relativeToPivotY * cos;
                    }
                    else
                    {
                            // no rotation
                            result.x = relativeToPivotX;
                            result.y = relativeToPivotY;
                    }                  
               
                    // translate back
                    //resultX += pivotX;
                    //resultY += pivotY;

                    // translate to world space
                    result.x += x;
                    result.y += y;
            }
       
            /** Transform a point that is specified in world space into sprite space. */
            public Vector2 worldToSprite(float pX, float pY)
            {
                    return worldToSprite(pX, pY, false);
            }
       
            /** Transform a point that is specified in world space into sprite space. */
            public Vector2 worldToSprite(float pX, float pY, bool ignoreMirror)
            {
                    Vector2 result = new Vector2();
               
                    worldToSprite(pX, pY, ignoreMirror, result);
               
                    return result;
            }

            /** Transform a point that is specified in world space into sprite space. */
            public void worldToSprite(float pX, float pY, Vector2 result)
            {
                    worldToSprite(pX, pY, false, result);              
            }
       
            /** Transform a point that is specified in world space into sprite space. */
            public void worldToSprite(float pX, float pY, bool ignoreMirror, Vector2 result)
            {
                    // Step 1a. Transform into pivot space (pivot becomes origin), translate by x/y (world position of pivot)
                    // Step 1b. Rotate back (CW).
                    // Step 2a. Translate by Pivot to transform into sprite space.
                    // Step 2b. Mirror.
               
                    result.x = 0;
                    result.y = 0;
               
                    float relativeToPivotX = pX - x;
                    float relativeToPivotY = pY - y;
               
                    // rotate relativeToPivotX/Y around pivot (which has become origin now)
                    if (angle != 0)
                    {
                            // Rotate CW
                            float cos = MathUtil.cos(-angle);
                            float sin = MathUtil.sin(angle);
                       
                            result.x = relativeToPivotX * cos - relativeToPivotY * sin;
                            result.y = relativeToPivotX * sin + relativeToPivotY * cos;
                    }
                    else
                    {
                            // no rotation
                            result.x = relativeToPivotX;
                            result.y = relativeToPivotY;
                    }
               
                    result.x += pivotX;
                    result.y += pivotY;
               
                    if (!ignoreMirror)
                    {
                            // mirror
                            if (mirrorX)
                                    result.x = w - result.x;
                            if (mirrorY)
                                    result.y = h - result.y;
                    }
            }
       
            /** Get an approximate bounding box of the sprite in world space. */
            /*public AABoundingBox getApproximateBoundingBox()
            {
                    float maxWidth = Math.max(pivotX, w - pivotX)*1.5f;
                    float maxHeight = Math.max(pivotY, h - pivotY)*1.5f;
               
                    return new AABoundingBox(x - maxWidth, y - maxHeight, x + maxWidth, y + maxHeight);
            }*/

       
            /** Get an exact bounding box of the sprite in world space. */
            /*public AABoundingBox getBoundingBox()
            {
                    Vector2 p1 = spriteToWorld(0, 0);
                    //Vector2 p2 = spriteToWorld(w, 0);
                    Vector2 p3 = spriteToWorld(w, h);
                    //Vector2 p4 = spriteToWorld(0, h);
               
                    Vector2 center = new Vector2((p1.x + p3.x) / 2, (p1.y + p3.y) / 2);
                    center.subtractVector(p1);
               
                    // Circumcircle radius
                    float radius = center.length();
               
                    return new AABoundingBox(center.x - radius, center.y - radius, center.x + radius, center.y + radius);
            }*/


        public Vector2 getAABoxMin()
        {
            Vector2 p1 = getTopLeft();
            Vector2 p2 = getTopRight();
            Vector2 p3 = getBottomLeft();
            Vector2 p4 = getBottomRight();

            float minX = Math.Min(p1.x, Math.Min(p2.x, Math.Min(p3.x, p4.x)));
            float minY = Math.Min(p1.y, Math.Min(p2.y, Math.Min(p3.y, p4.y)));

            return new Vector2(minX, minY);
        }

        public Vector2 getAABoxMax()
        {
            Vector2 p1 = getTopLeft();
            Vector2 p2 = getTopRight();
            Vector2 p3 = getBottomLeft();
            Vector2 p4 = getBottomRight();

            float maxX = Math.Max(p1.x, Math.Max(p2.x, Math.Max(p3.x, p4.x)));
            float maxY = Math.Max(p1.y, Math.Max(p2.y, Math.Max(p3.y, p4.y)));

            return new Vector2(maxX, maxY);
        }
       
            /** Get the upper left corner as a Vector2 in world space. */
            public Vector2 getTopLeft()
            {
                    // return transformed coordinates (without mirroring)
                    if (angle != 0)
                            return spriteToWorld(0, 0, true);
               
                    return new Vector2(x - pivotX, y - pivotY);
            }
       
            /** Get the upper left corner as a Vector2 in world space. */
            public Vector2 getTopRight()
            {
                    // return transformed coordinates (without mirroring)
                    if (angle != 0)
                            return spriteToWorld(w, 0, true);
               
                    return new Vector2(x - pivotX + w, y - pivotY);
            }
       
            /** Get the upper left corner as a Vector2 in world space. */
            public Vector2 getBottomLeft()
            {
                    // return transformed coordinates (without mirroring)
                    if (angle != 0)
                            return spriteToWorld(0, h, true);

                    return new Vector2(x - pivotX, y - pivotY + h);
            }
       
            /** Get the upper left corner as a Vector2 in world space. */
            public Vector2 getBottomRight()
            {
                    // return transformed coordinates (without mirroring)
                    if (angle != 0)
                            return spriteToWorld(w, h, true);

                    return new Vector2(x - pivotX + w, y - pivotY + h);
            }
       
            /** Check if the point is inside the sprite. */
            public bool isInside(float x, float y)
            {
                    // Check in sprite space. Ignore mirroring since we don't need it for this operation
                    Vector2 spriteSpacePt = worldToSprite(x, y, true);
               
                    return ((spriteSpacePt.x >= 0) && (spriteSpacePt.y >= 0) &&
                                    (spriteSpacePt.x <= w) && (spriteSpacePt.y <= h));
            }



    }
}