Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

package com.gebauz.bauzoid.graphics.sprite;

import com.gebauz.bauzoid.math.MathUtil;
import com.gebauz.bauzoid.math.Matrix4;
import com.gebauz.bauzoid.math.Vector2;
import com.gebauz.bauzoid.math.collision.AABoundingBox;

/** Transformation, alpha, and color parameters of a sprite. */
public class SpriteTransform
{

        // Constants========================================================================================

        // Embedded Types===================================================================================

        // Fields===========================================================================================

        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 boolean mirrorX = false;
        public boolean mirrorY = false;
       
        /** Rotation and scaling pivot point in absolute coordinates. */
        public float pivotX = 0.0f;
        public float pivotY = 0.0f;
       
        private AABoundingBox mApproximateBoundingBox = new AABoundingBox();
        private AABoundingBox mBoundingBox = new AABoundingBox();
        private Vector2 mTemp1 = new Vector2();
        private Vector2 mTemp2 = new Vector2();
       
        // Methods==========================================================================================

        public SpriteTransform()
        {
        }
       
        public void centerPivot()
        {
                pivotX = w/2.0f;
                pivotY = h/2.0f;
        }
       
        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, float _pivotX, float _pivotY, boolean _mirrorX, boolean _mirrorY)
        {
                x = _x; y = _y; w = _w; h = _h; pivotX = _pivotX; pivotY = _pivotY; mirrorX = _mirrorX; mirrorY = _mirrorY;
        }
       
        public void set(float _x, float _y, float _w, float _h, float _pivotX, float _pivotY)
        {
                set(_x, _y, _w, _h, _pivotX, _pivotY, false, false);
        }
       
        public void set(float _x, float _y, float _w, float _h)
        {
                set(_x, _y, _w, _h, pivotX, pivotY, mirrorX, mirrorY);
        }
       
        public void setPos(float _x, float _y)
        {
                set(_x, _y, w, h, pivotX, pivotY, mirrorX, mirrorY);
        }
       
        public void setSize(float _w, float _h)
        {
                set(x, y, _w, _h, pivotX, pivotY, mirrorX, mirrorY);
        }
       
        public void setPivot(float _pivotX, float _pivotY)
        {
                set(x, y, w, h, _pivotX, _pivotY, mirrorX, mirrorY);
        }

        public void setMirror(boolean _mirrorX, boolean _mirrorY)
        {
                set(x, y, w, h, pivotX, pivotY, _mirrorX, _mirrorY);
        }
       
        /** Calculate a 4x4 Matrix that transforms from normalized sprite space (coordinates in [-1..1] range) to world space. */
        public final Matrix4 getNormalizedTransform()
        {
                /*mScale.setScale(_w/2, _h/2, 1.0f);
                mPivotTranslate.setTranslation(-_pivotX+_w/2, -_pivotY+_h/2, 0);
                mMirror.setScale((_mirrorX ? -1 : 1), (_mirrorY ? -1 : 1), 1);
                mRotateZ.setRotationZ(_angle);
                mTranslate.setTranslation(_x, _y, 0);

                mModelMatrix.identity();*/

               
                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 final 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. */

        @Deprecated
        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. */

        @Deprecated
        public Vector2 spriteToWorld(float pX, float pY, boolean 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, boolean 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)
                {
                        final float cos = MathUtil.cos(angle);
                       
                        // Rotate CCW (like Matrix4.CreateRotationZ).
                        final 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. */
        @Deprecated
        public Vector2 worldToSprite(float pX, float pY)
        {
                return worldToSprite(pX, pY, false);
        }
       
        /** Transform a point that is specified in world space into sprite space. */
        @Deprecated
        public Vector2 worldToSprite(float pX, float pY, boolean 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, boolean 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
                        final float cos = MathUtil.cos(-angle);
                        final 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);
                float maxHeight = Math.max(pivotY, h - pivotY);
               
                float r = (float)Math.sqrt(maxWidth*maxWidth + maxHeight*maxHeight);
               
                //return new AABoundingBox(x - maxWidth, y - maxHeight, x + maxWidth, y + maxHeight);
                mApproximateBoundingBox.min.set(x - r, y - r);
                mApproximateBoundingBox.max.set(x + r, y + r);
                /*mApproximateBoundingBox.min.set(x - w, y - h);
                mApproximateBoundingBox.max.set(x + w, y + h);*/

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

        /** Get the upper left corner as a Vector2 in world space. */
        public void getTopLeft(Vector2 result)
        {
                if (angle != 0)
                        spriteToWorld(0, 0, true, result);
                else
                        result.set(x - pivotX, y - pivotY);
        }
        /*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 void getTopRight(Vector2 result)
        {
                if (angle != 0)
                        spriteToWorld(w, 0, true, result);
                else
                        result.set(x - pivotX + w, y - pivotY);
        }
        /*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 void getBottomLeft(Vector2 result)
        {
                if (angle != 0)
                        spriteToWorld(0, h, true, result);
                else
                        result.set(x - pivotX, y - pivotY + h);
        }
        /*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 void getBottomRight(Vector2 result)
        {
                if (angle != 0)
                        spriteToWorld(w, h, true, result);
                else
                        result.set(x - pivotX + w, y - pivotY + h);
        }
        /*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 boolean 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));
        }

}