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