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
;
// 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;
}
/** 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 the same space as the pivot point. */
public Vector2 spriteToWorld
(float pX,
float pY
)
{
return spriteToWorld
(pY, pY,
false);
}
/** Transform a point that is specified in sprite space into world space.
* pX/pY is defined in the same space as the pivot point. */
public Vector2 spriteToWorld
(float pX,
float pY,
boolean ignoreMirror
)
{
// 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 2. Add x/y to the relative position
float resultX
;
float resultY
;
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
);
resultX = relativeToPivotX
* cos - relativeToPivotY
* sin
;
resultY = relativeToPivotX
* sin + relativeToPivotY
* cos
;
}
else
{
// no rotation
resultX = relativeToPivotX
;
resultY = relativeToPivotY
;
}
// translate to world space
resultX += x
;
resultY += y
;
return new Vector2
(resultX, resultY
);
}
/** 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,
boolean ignoreMirror
)
{
// 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.
float resultX
;
float resultY
;
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
);
resultX = relativeToPivotX
* cos - relativeToPivotY
* sin
;
resultY = relativeToPivotX
* sin + relativeToPivotY
* cos
;
}
else
{
// no rotation
resultX = relativeToPivotX
;
resultY = relativeToPivotY
;
}
resultX += pivotX
;
resultY += pivotY
;
if (!ignoreMirror
)
{
// mirror
if (mirrorX
)
resultX = w - resultX
;
if (mirrorY
)
resultY = h - resultY
;
}
return new Vector2
(resultX, resultY
);
}
/** 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
);
}
// Getters/Setters==================================================================================
/** 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 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
));
}
}