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