Subversion Repositories AndroidProjects

Rev

Go to most recent revision | 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 = 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 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 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);
                }*/

       
                /** 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));
                }



    }
}