1133 lines
34 KiB
Scheme
Executable File
1133 lines
34 KiB
Scheme
Executable File
//-------------------------------------------------
|
|
// File: ggsm_arcade_maths.sch
|
|
// Purpose: general functions required by system
|
|
//-------------------------------------------------
|
|
|
|
//-------------------------------------------------
|
|
// INCLUDES
|
|
//-------------------------------------------------
|
|
USING "ggsm_structs.sch"
|
|
|
|
//-------------------------------------------------
|
|
// MISC FUNCTIONS
|
|
//-------------------------------------------------
|
|
FUNC INT GGSM_GET_NUMBER_OF_DIGITS_IN_NUMBER(INT iNumber)
|
|
RETURN FLOOR(LOG10(TO_FLOAT(iNumber))) + 1
|
|
ENDFUNC
|
|
|
|
//-------------------------------------------------
|
|
// COLOR FUNCTIONS
|
|
//-------------------------------------------------
|
|
PROC GGSM_SET_PACKED_R_COLOR(INT &col, INT c)
|
|
SET_BITS_IN_RANGE(col, 24, 31, c & 255)
|
|
ENDPROC
|
|
|
|
PROC GGSM_SET_PACKED_G_COLOR(INT &col, INT c)
|
|
SET_BITS_IN_RANGE(col, 16, 23, c & 255)
|
|
ENDPROC
|
|
|
|
PROC GGSM_SET_PACKED_B_COLOR(INT &col, INT c)
|
|
SET_BITS_IN_RANGE(col, 8, 15, c & 255)
|
|
ENDPROC
|
|
|
|
PROC GGSM_SET_PACKED_A_COLOR(INT &col, INT c)
|
|
SET_BITS_IN_RANGE(col, 0, 7, c & 255)
|
|
ENDPROC
|
|
|
|
FUNC INT GGSM_PACK_RGBA_COLOUR(INT r, INT g, INT b, INT a = 255)
|
|
RETURN (SHIFT_LEFT(r & 255, 24) | SHIFT_LEFT(g & 255, 16) | SHIFT_LEFT(b & 255, 8) | (a & 255))
|
|
ENDFUNC
|
|
|
|
FUNC INT GGSM_PACK_RGBA_COLOUR_STRUCT(RGBA_COLOUR_STRUCT &col)
|
|
RETURN (SHIFT_LEFT(col.iR & 255, 24) | SHIFT_LEFT(col.iG & 255, 16) | SHIFT_LEFT(col.iB & 255, 8) | (col.iA & 255))
|
|
ENDFUNC
|
|
|
|
PROC GGSM_UNPACK_RGBA_COLOUR(INT iCol, RGBA_COLOUR_STRUCT &out)
|
|
out.iA = GET_BITS_IN_RANGE(iCol, 0, 7)
|
|
out.iB = GET_BITS_IN_RANGE(iCol, 8, 15)
|
|
out.iG = GET_BITS_IN_RANGE(iCol, 16, 23)
|
|
out.iR = GET_BITS_IN_RANGE(iCol, 24, 31)
|
|
ENDPROC
|
|
|
|
//-------------------------------------------------
|
|
// DIRECTION FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// This packed 2d direction to int
|
|
/// Only holds values between -1.0 an 1.0
|
|
/// PARAMS:
|
|
/// vec -
|
|
/// RETURNS:
|
|
///
|
|
FUNC INT GGSM_PACK_DIRECTION_2D_TO_INT(VECTOR_2D vec)
|
|
INT ix = FLOOR(vec.x * 32767.0) + 32767
|
|
INT iy = FLOOR(vec.y * 32767.0) + 32767
|
|
RETURN ix + SHIFT_LEFT(iy, 16)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// This packed 2d direction to int
|
|
/// PARAMS:
|
|
/// vec -
|
|
/// RETURNS:
|
|
///
|
|
FUNC INT GGSM_PACK_DIRECTION_2D_TO_INT_EXPLICIT(FLOAT x, FLOAT y)
|
|
INT ix = FLOOR(x * 32767.0) + 32767
|
|
INT iy = FLOOR(y * 32767.0) + 32767
|
|
RETURN ix + SHIFT_LEFT(iy, 16)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// This unpacks 2d direction from int
|
|
/// PARAMS:
|
|
/// vec -
|
|
/// RETURNS:
|
|
///
|
|
FUNC VECTOR_2D GGSM_UNPACK_DIRECTION_2D(INT i)
|
|
VECTOR_2D v
|
|
v.x = TO_FLOAT(GET_BITS_IN_RANGE(i, 0, 15) - 32767) / 32767.0
|
|
v.y = TO_FLOAT(GET_BITS_IN_RANGE(i, 16, 31) - 32767) / 32767.0
|
|
RETURN v
|
|
ENDFUNC
|
|
|
|
//-------------------------------------------------
|
|
// VECTOR FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
FUNC VECTOR_2D GGSM_FLOOR_VECTOR_2D_FOR_RENDERING(VECTOR_2D vec)
|
|
VECTOR_2D out
|
|
out.x = TO_FLOAT(FLOOR(vec.x))
|
|
out.y = TO_FLOAT(FLOOR(vec.y))
|
|
RETURN out
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// This packed 2d vector to int
|
|
/// It doesn't care about decimal points and only holds up to -32767 to +32767
|
|
/// PARAMS:
|
|
/// vec -
|
|
/// RETURNS:
|
|
///
|
|
FUNC INT GGSM_PACK_VECTOR_2D_TO_INT(VECTOR_2D vec)
|
|
INT ix = FLOOR(vec.x) + 32767
|
|
INT iy = FLOOR(vec.y) + 32767
|
|
RETURN ix + SHIFT_LEFT(iy, 16)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// This packed 2d vector to int
|
|
/// It doesn't care about decimal points and only holds up to -32767 to +32767
|
|
/// PARAMS:
|
|
/// vec -
|
|
/// RETURNS:
|
|
///
|
|
FUNC INT GGSM_PACK_VECTOR_2D_TO_INT_EXPLICIT(FLOAT x, FLOAT y)
|
|
INT ix = FLOOR(x) + 32767
|
|
INT iy = FLOOR(y) + 32767
|
|
RETURN ix + SHIFT_LEFT(iy, 16)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// This unpacks 2d vector to int
|
|
/// It doesn't care about decimal points and only holds up to -32767 to +32767
|
|
/// PARAMS:
|
|
/// vec -
|
|
/// RETURNS:
|
|
///
|
|
FUNC VECTOR_2D GGSM_UNPACK_VECTOR_2D(INT i)
|
|
VECTOR_2D v
|
|
v.x = TO_FLOAT(GET_BITS_IN_RANGE(i, 0, 15) - 32767)
|
|
v.y = TO_FLOAT(GET_BITS_IN_RANGE(i, 16, 31) - 32767)
|
|
RETURN v
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Given a vector return the value of the largest axis
|
|
FUNC FLOAT GGSM_GET_DOMINANT_AXIS(VECTOR_2D v)
|
|
IF (ABSF(v.x) > ABSF(v.y))
|
|
RETURN v.x
|
|
ENDIF
|
|
|
|
RETURN v.y
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Given a rectangle as topleft corner and size work out the center
|
|
/// PARAMS:
|
|
/// tlx - top left x
|
|
/// tly - top left y
|
|
/// w - width
|
|
/// h - height
|
|
/// RETURNS:
|
|
/// Center as vector 2D
|
|
FUNC VECTOR_2D GGSM_GET_CENTER_FROM_CORNER_RECT(FLOAT tlx, FLOAT tly, FLOAT w, FLOAT h)
|
|
RETURN INIT_VECTOR_2D(tlx + (w / 2.0), tly + (h / 2.0))
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Returns a vector from a heading - 0 is south, 90 is west, 180 is north and 270 is east
|
|
/// PARAMS:
|
|
/// fHeading -
|
|
/// RETURNS:
|
|
///
|
|
FUNC VECTOR_2D GGSM_GET_VECTOR_FROM_HEADING(FLOAT fHeading)
|
|
VECTOR_2D new
|
|
|
|
IF (fHeading = 0.0)
|
|
new.x = 0.0
|
|
new.y = 1.0
|
|
ELIF (fHeading = 180.0)
|
|
new.x = 0.0
|
|
new.y = -1.0
|
|
ELIF (fHeading = 90.0)
|
|
new.x = -1.0
|
|
new.y = 0.0
|
|
ELIF (fHeading = 270.0)
|
|
new.x = 1.0
|
|
new.y = 0.0
|
|
ELSE
|
|
new.x = -SIN(fHeading)
|
|
new.y = COS(fHeading)
|
|
ENDIF
|
|
|
|
RETURN new
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Rotates a vector in 3D space about the world z-axis.
|
|
/// It is assumed here that the axis of rotation passes through the origin.
|
|
/// If you are rotating by an increment of 90 degrees, see next function.
|
|
/// If you are rotating lots of things by the same angle and want to precompute the trig values, see next next function.
|
|
/// PARAMS:
|
|
/// vToRotate - Should be orientation only (should come from origin)
|
|
/// fZRot - Rotation in degrees
|
|
/// RETURNS:
|
|
/// Vector rotated locally about the world z axis by fZRot degrees - should really put an optimization in here
|
|
FUNC VECTOR_2D GGSM_ROTATE_VECTOR_2D_ABOUT_Z(VECTOR_2D vToRotate, FLOAT fZRot)
|
|
VECTOR_2D vNew
|
|
FLOAT fSin = SIN(fZRot)
|
|
FLOAT fCos = COS(fZRot)
|
|
vNew.x = vToRotate.x * fCos - vToRotate.y * fSin
|
|
vNew.y = vToRotate.x * fSin + vToRotate.y * fCos
|
|
RETURN vNew
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Rotates a vector in 3D space about the world z-axis.
|
|
/// It is assumed here that the axis of rotation passes through the origin.
|
|
/// If you are rotating by an increment of 90 degrees, see next function.
|
|
/// If you are rotating lots of things by the same angle and want to precompute the trig values, see next next function.
|
|
/// PARAMS:
|
|
/// vToRotate - Should be orientation only (should come from origin)
|
|
/// fZRot - Rotation in degrees
|
|
/// RETURNS:
|
|
/// Vector rotated locally about the world z axis by fZRot degrees
|
|
FUNC VECTOR_2D GGSM_ROTATE_VECTOR_2D_ABOUT_Z_PRECOMPUTE(VECTOR_2D vToRotate, FLOAT fSin, FLOAT fCos)
|
|
VECTOR_2D vNew
|
|
vNew.x = vToRotate.x * fCos - vToRotate.y * fSin
|
|
vNew.y = vToRotate.x * fSin + vToRotate.y * fCos
|
|
RETURN vNew
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Get offset relative to a screen coord
|
|
/// PARAMS:
|
|
/// vPos - position to offset around
|
|
/// fRotation - rotation
|
|
/// vOffset - offset desired
|
|
/// RETURNS:
|
|
/// Offset Vector
|
|
FUNC VECTOR_2D GGSM_GET_OFFSET_FROM_POSITION(VECTOR_2D vPos, FLOAT fRotation, VECTOR_2D vOffset)
|
|
VECTOR_2D v
|
|
|
|
v = GGSM_ROTATE_VECTOR_2D_ABOUT_Z(vOffset, fRotation)
|
|
v.x += vPos.x
|
|
v.y += vPos.y
|
|
|
|
RETURN v
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Translates rotation by a given direction and speed
|
|
/// This is just a wrapper as I got sick of writing this all the time
|
|
PROC GGSM_TRANSLATE_VECTOR_BY_DIRECTION(VECTOR_2D &vec, VECTOR_2D dir, FLOAT spd)
|
|
vec.x += (dir.x * spd)
|
|
vec.y += (dir.y * spd)
|
|
ENDPROC
|
|
|
|
//-------------------------------------------------
|
|
// TRANSFORM FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// Resets an transformation to identity (zero pos, zero rot, 1:1 scale)
|
|
PROC GGSM_IDENTITY_TRANSFORM(GGSM_TRANSFORM &trans)
|
|
trans.vPosition.x = 0
|
|
trans.vPosition.y = 0
|
|
trans.fRotation = 0
|
|
trans.vScale.x = 1
|
|
trans.vScale.y = 1
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Transforms a local vector into world space given a parent
|
|
FUNC VECTOR_2D GGSM_TRANSFORM_LOCAL_POS_TO_WORLD_POS(GGSM_TRANSFORM &parent, VECTOR_2D vLocalPos)
|
|
vLocalPos.x *= parent.vScale.x
|
|
vLocalPos.y *= parent.vScale.y
|
|
|
|
VECTOR_2D vWorldPos = GGSM_ROTATE_VECTOR_2D_ABOUT_Z(vLocalPos, parent.fRotation)
|
|
vWorldPos.x += parent.vPosition.x
|
|
vWorldPos.y += parent.vPosition.y
|
|
RETURN vWorldPos
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Transforms a world vector into local space given a parent
|
|
FUNC VECTOR_2D GGSM_TRANSFORM_WORLD_POS_TO_LOCAL_POS(GGSM_TRANSFORM &parent, VECTOR_2D vWorldPos)
|
|
VECTOR_2D rel = SUBTRACT_VECTOR_2D(vWorldPos, parent.vPosition)
|
|
VECTOR_2D pos = GGSM_ROTATE_VECTOR_2D_ABOUT_Z(rel, -parent.fRotation)
|
|
RETURN pos
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Transforms a local transform into world space given a parent
|
|
PROC GGSM_TRANSFORM_LOCAL_TO_WORLD(GGSM_TRANSFORM &parent, GGSM_TRANSFORM &local, GGSM_TRANSFORM &world)
|
|
VECTOR_2D vLocal = local.vPosition
|
|
|
|
vLocal.x *= parent.vScale.x
|
|
vLocal.y *= parent.vScale.y
|
|
|
|
world.vPosition = GGSM_ROTATE_VECTOR_2D_ABOUT_Z(vLocal, parent.fRotation)
|
|
world.vPosition.x += parent.vPosition.x
|
|
world.vPosition.y += parent.vPosition.y
|
|
world.fRotation = parent.fRotation + local.fRotation
|
|
world.vScale.x = parent.vScale.x * local.vScale.x
|
|
world.vScale.y = parent.vScale.y * local.vScale.y
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Transforms a world transform into local space given a parent
|
|
PROC GGSM_TRANSFORM_WORLD_TO_LOCAL(GGSM_TRANSFORM &parent, GGSM_TRANSFORM &world, GGSM_TRANSFORM &local)
|
|
VECTOR_2D rel = SUBTRACT_VECTOR_2D(world.vPosition, parent.vPosition)
|
|
rel.x *= world.vScale.x
|
|
rel.y *= world.vScale.y
|
|
local.vPosition = GGSM_ROTATE_VECTOR_2D_ABOUT_Z(rel, -parent.fRotation)
|
|
local.fRotation = world.fRotation - parent.fRotation
|
|
local.vScale = INIT_VECTOR_2D(1, 1)
|
|
ENDPROC
|
|
|
|
//-------------------------------------------------
|
|
// PLANE FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// Tells us what side of a plane a point is on given the plane origin and normal
|
|
FUNC GGSM_PLANESIDE GGSM_GET_SIDE_OF_PLANE(VECTOR_2D vPlanePos, VECTOR_2D vPlaneNormal, VECTOR_2D vTestPoint)
|
|
FLOAT dot = DOT_PRODUCT_VECTOR_2D(SUBTRACT_VECTOR_2D(vTestPoint, vPlanePos), vPlaneNormal)
|
|
IF (dot < 0)
|
|
RETURN GGSM_PLANESIDE_BEHIND
|
|
ELIF (dot > 0)
|
|
RETURN GGSM_PLANESIDE_FRONT
|
|
ENDIF
|
|
|
|
RETURN GGSM_PLANESIDE_ON
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Tells us what side of a plane a point is on given the plane origin and norma
|
|
FUNC BOOL GGSM_IS_POINT_BEHIND_PLANE(VECTOR_2D vPlanePos, VECTOR_2D vPlaneNormal, VECTOR_2D vTestPoint)
|
|
RETURN (DOT_PRODUCT_VECTOR_2D(SUBTRACT_VECTOR_2D(vTestPoint, vPlanePos), vPlaneNormal) <= 0.0)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// 2D Wrapper for Get Closest Point On Line
|
|
FUNC VECTOR_2D GGSM_GET_CLOSEST_POINT_ON_LINE(VECTOR_2D vTestPoint, VECTOR_2D vStart, VECTOR_2D vEnd, BOOL bClampLine = TRUE)
|
|
VECTOR out = GET_CLOSEST_POINT_ON_LINE(<<vTestPoint.x, vTestPoint.y, 0>>, <<vStart.x, vStart.y, 0>>, <<vEnd.x, vEnd.y, 0>>, bClampLine)
|
|
RETURN INIT_VECTOR_2D(out.x, out.y)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if 2 lines intersect
|
|
/// PARAMS:
|
|
/// p1 - line 1 point 0
|
|
/// p2 - line 1 point 1
|
|
/// p3 - line 2 point 0
|
|
/// p4 - line 2 point 1
|
|
/// pa - intersect point on line 1
|
|
/// pb - intersect point on line 2
|
|
/// RETURNS:
|
|
/// TRUE if intersect
|
|
FUNC BOOL GGSM_LINE_LINE_INTERSECT(VECTOR_2D p1, VECTOR_2D p2, VECTOR_2D p3, VECTOR_2D p4, VECTOR_2D &pa, VECTOR_2D &pb)
|
|
VECTOR_2D p13, p43, p21
|
|
FLOAT d1343, d4321, d4343, d2121
|
|
FLOAT numer, denom
|
|
FLOAT mua, mub
|
|
|
|
p43 = SUBTRACT_VECTOR_2D(p4, p3)
|
|
IF (ABSF(p43.x) < GGSM_EPSILON AND ABSF(p43.y) < GGSM_EPSILON)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
p21 = SUBTRACT_VECTOR_2D(p2, p1)
|
|
IF (ABSF(p21.x) < GGSM_EPSILON AND ABSF(p21.y) < GGSM_EPSILON)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
p13 = SUBTRACT_VECTOR_2D(p1, p3)
|
|
|
|
d1343 = DOT_PRODUCT_VECTOR_2D(p13, p43)
|
|
d4321 = DOT_PRODUCT_VECTOR_2D(p43, p21)
|
|
d4343 = DOT_PRODUCT_VECTOR_2D(p43, p43)
|
|
d2121 = DOT_PRODUCT_VECTOR_2D(p21, p21)
|
|
|
|
denom = d2121 * d4343 - d4321 * d4321
|
|
IF (ABSF(denom) < GGSM_EPSILON)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
numer = d1343 * d4343 - d4321 * d4321
|
|
mua = numer / denom
|
|
mub = (d1343 + d4321 * mua) / d4343
|
|
|
|
pa.x = p1.x + mua * p21.x
|
|
pa.y = p1.y + mua * p21.y
|
|
|
|
pb.x = p3.x + mub * p43.x
|
|
pb.y = p3.y + mua * p43.y
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Checks if 2 lines intersect
|
|
/// PARAMS:
|
|
/// p1 - line 1 point 0
|
|
/// p2 - line 1 point 1
|
|
/// p3 - line 2 point 0
|
|
/// p4 - line 2 point 1
|
|
/// pa - intersect point on line 1
|
|
/// pb - intersect point on line 2
|
|
/// RETURNS:
|
|
/// TRUE if intersect
|
|
FUNC BOOL GGSM_LINE_LINE_INTERSECT_QUICK(VECTOR_2D p1, VECTOR_2D p2, VECTOR_2D p3, VECTOR_2D p4)
|
|
VECTOR_2D p43, p21
|
|
FLOAT d4321, d4343, d2121
|
|
FLOAT denom
|
|
|
|
p43 = SUBTRACT_VECTOR_2D(p4, p3)
|
|
IF (ABSF(p43.x) < GGSM_EPSILON AND ABSF(p43.y) < GGSM_EPSILON)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
p21 = SUBTRACT_VECTOR_2D(p2, p1)
|
|
IF (ABSF(p21.x) < GGSM_EPSILON AND ABSF(p21.y) < GGSM_EPSILON)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
d4321 = DOT_PRODUCT_VECTOR_2D(p43, p21)
|
|
d4343 = DOT_PRODUCT_VECTOR_2D(p43, p43)
|
|
d2121 = DOT_PRODUCT_VECTOR_2D(p21, p21)
|
|
|
|
denom = d2121 * d4343 - d4321 * d4321
|
|
IF (ABSF(denom) < GGSM_EPSILON)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Returns squared distance between point c and segment ab
|
|
/// PARAMS:
|
|
/// a - line point 1
|
|
/// b - line point 2
|
|
/// c - point to rest
|
|
/// RETURNS:
|
|
/// Squared Distance for point to closest point on line ab
|
|
FUNC FLOAT GGSM_SQDIST_POINT_SEGMENT(VECTOR_2D a, VECTOR_2D b, VECTOR_2D c)
|
|
VECTOR_2D ab = SUBTRACT_VECTOR_2D(b, a)
|
|
FLOAT u = GET_RATIO_OF_CLOSEST_POINT_ON_LINE(c, a, b, TRUE)
|
|
VECTOR_2D p
|
|
p.x = a.x + u * ab.x
|
|
p.y = a.y + u * ab.y
|
|
RETURN DOT_PRODUCT_VECTOR_2D(a, p)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Gets the closest squared distance between two lines
|
|
/// PARAMS:
|
|
/// p1 - line 1 point 1
|
|
/// p2 - line 1 point 2
|
|
/// q1 - line 2 point 1
|
|
/// q2 - line 2 point 2
|
|
/// RETURNS:
|
|
/// Squared distance
|
|
FUNC FLOAT GGSM_SEGMENT_DISTANCE_SQUARED(VECTOR_2D p1, VECTOR_2D p2, VECTOR_2D q1, VECTOR_2D q2)
|
|
VECTOR_2D u = SUBTRACT_VECTOR_2D(p2, p1)
|
|
VECTOR_2D v = SUBTRACT_VECTOR_2D(q2, q1)
|
|
VECTOR_2D w = SUBTRACT_VECTOR_2D(p1, q1)
|
|
|
|
FLOAT a = DOT_PRODUCT_VECTOR_2D(u, u)
|
|
FLOAT b = DOT_PRODUCT_VECTOR_2D(u, v)
|
|
FLOAT c = DOT_PRODUCT_VECTOR_2D(v, v)
|
|
FLOAT d = DOT_PRODUCT_VECTOR_2D(u, w)
|
|
FLOAT e = DOT_PRODUCT_VECTOR_2D(v, w)
|
|
|
|
FLOAT disc = a * c - b * b
|
|
FLOAT sc, sN, sD = disc
|
|
FLOAT tc, tN, tD = disc
|
|
|
|
// compute the line parameters of the two closest points
|
|
IF (disc < GGSM_EPSILON) // the lines are almost parallel
|
|
sN = 0.0 // force using point P0 on segment S1
|
|
sD = 1.0 // to prevent possible division by 0.0 later
|
|
tN = e
|
|
tD = c
|
|
ELSE
|
|
sN = (b * e - c * d)
|
|
IF (sN < 0.0) // sc < 0 => the s=0 edge is visible
|
|
sN = 0.0
|
|
tN = e
|
|
tD = c
|
|
ELIF (sN > sD) // sc > 1 => the s=1 edge is visible
|
|
sN = sD
|
|
tN = e + b
|
|
tD = c
|
|
ELSE
|
|
tN = (a * e - b * d)
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF (tN < 0.0) // tc < 0 => the t=0 edge is visible
|
|
tN = 0.0
|
|
|
|
// recompute sc for this edge
|
|
IF (-d < 0.0)
|
|
sN = 0.0
|
|
ELIF (-d > a)
|
|
sN = sD
|
|
ELSE
|
|
sN = -d
|
|
sD = a
|
|
ENDIF
|
|
ELIF (tN > tD) // tc > 1 => the t=1 edge is visible
|
|
tN = tD
|
|
|
|
// recompute sc for this edge
|
|
IF ((-d + b) < 0.0)
|
|
sN = 0
|
|
ELIF ((-d + b) > a)
|
|
sN = sD
|
|
ELSE
|
|
sN = (-d + b)
|
|
sD = a
|
|
ENDIF
|
|
ENDIF
|
|
|
|
// finally do the division to get sc and tc
|
|
IF (ABSF(sN) < GGSM_EPSILON)
|
|
sc = 0.0
|
|
ELSE
|
|
sc = sN / sD
|
|
ENDIF
|
|
|
|
IF (ABSF(tN) < GGSM_EPSILON)
|
|
tc = 0.0
|
|
ELSE
|
|
tc = tN / tD
|
|
ENDIF
|
|
|
|
// get the difference of the two closest points
|
|
VECTOR_2D dP
|
|
|
|
dp.x = w.x + (sc * u.x) - (tc * v.x) // = S1(sc) - S2(tc)
|
|
dp.y = w.y + (sc * u.y) - (tc * v.y)
|
|
|
|
RETURN DOT_PRODUCT_VECTOR_2D(dP, dP)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Tells us if a point is in a polygon
|
|
/// PARAMS:
|
|
/// p - point to check
|
|
/// points - array of points
|
|
/// iNumPoints - num of points in array
|
|
/// RETURNS:
|
|
///
|
|
FUNC BOOL GGSM_IS_POINT_IN_POLYGON(VECTOR_2D p, VECTOR_2D &points[], INT iNumPoints)
|
|
INT i, j
|
|
BOOL bInside = FALSE
|
|
|
|
i = 0
|
|
j = iNumPoints - 1
|
|
|
|
WHILE (i < iNumPoints)
|
|
IF ( ((points[i].y > p.y) <> (points[j].y > p.y)) AND
|
|
(p.x < (points[j].x - points[i].x) * (p.y - points[i].y) / (points[j].y - points[i].y) + points[i].x) )
|
|
bInside = NOT bInside
|
|
ENDIF
|
|
|
|
j = i
|
|
i ++
|
|
ENDWHILE
|
|
|
|
RETURN bInside
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Tells us if a sprite is within the draw area
|
|
/// PARAMS:
|
|
/// vPos - Sprite Pos
|
|
/// vSize - Sprite Size
|
|
/// RETURNS:
|
|
/// TRUE if it is on screen
|
|
FUNC BOOL GGSM_IS_POINT_ON_SCREEN(VECTOR_2D vPos, VECTOR_2D vSize)
|
|
VECTOR_2D halfScale
|
|
|
|
halfScale.x = vSize.x / 2.0
|
|
halfScale.y = vSize.y / 2.0
|
|
|
|
IF (vPos.x < (GGSM_PX_OVERSCAN_MIN_X - halfScale.x)) OR (vPos.x > (GGSM_PX_OVERSCAN_MAX_X + halfScale.x))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (vPos.y < (GGSM_PX_OVERSCAN_MIN_Y - halfScale.y)) OR (vPos.y > (GGSM_PX_OVERSCAN_MAX_Y + halfScale.y))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
FUNC BOOL GGSM_IS_POINT_FULLY_ON_SCREEN(VECTOR_2D vPos, VECTOR_2D vSize, FLOAT fBorder = 30.0)
|
|
VECTOR_2D halfScale
|
|
vSize.x = ABSF(vSize.x) + fBorder
|
|
vSize.y = ABSF(vSize.y) + fBorder
|
|
halfScale.x = vSize.x / 2.0
|
|
halfScale.y = vSize.y / 2.0
|
|
|
|
IF (vPos.x <= (GGSM_PX_OVERSCAN_MIN_X + halfScale.x)) OR (vPos.x >= (GGSM_PX_OVERSCAN_MAX_X - halfScale.x))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (vPos.y <= (GGSM_PX_OVERSCAN_MIN_Y + halfScale.y)) OR (vPos.y >= (GGSM_PX_OVERSCAN_MAX_Y - halfScale.y))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
//-------------------------------------------------
|
|
// SPLINE FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// 2D Catmull Rom Spline - Will give an interpolation between p1 and p2
|
|
/// PARAMS:
|
|
/// p0 - point 0
|
|
/// p1 - point 1
|
|
/// p2 - point 2
|
|
/// p3 - point 3
|
|
/// t - interpolate value
|
|
/// RETURNS:
|
|
/// Interpolated Point
|
|
FUNC VECTOR_2D GMMR_CALCULATE_SPLINE_POINT(VECTOR_2D& p0, VECTOR_2D& p1, VECTOR_2D& p2, VECTOR_2D& p3, FLOAT t)
|
|
VECTOR_2D ret
|
|
FLOAT t2 = t * t
|
|
FLOAT t3 = t2 * t
|
|
|
|
ret.x = 0.5 * ((2.0 * p1.x) +
|
|
(-p0.x + p2.x) * t +
|
|
(2.0 * p0.x - 5.0 * p1.x + 4 * p2.x - p3.x) * t2 +
|
|
(-p0.x + 3.0 * p1.x - 3.0 * p2.x + p3.x) * t3)
|
|
|
|
ret.y = 0.5 * ((2.0 * p1.y) +
|
|
(-p0.y + p2.y) * t +
|
|
(2.0 * p0.y - 5.0 * p1.y + 4 * p2.y - p3.y) * t2 +
|
|
(-p0.y + 3.0 * p1.y - 3.0 * p2.y + p3.y) * t3)
|
|
|
|
RETURN ret
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Gets the point on a spline
|
|
/// PARAMS:
|
|
/// vPoints - array of points on the spline (this will break if there are less than 2)
|
|
/// iTotalPointsInSpline - # of points in the spline
|
|
/// t - interpolate value (ranges from 0 to iTotalPoints
|
|
/// RETURNS:
|
|
///
|
|
FUNC VECTOR_2D GGMR_GET_SPLINE_POINT(VECTOR_2D &vPoints[], INT iTotalPointsInSpline, FLOAT t)
|
|
VECTOR_2D v[4]
|
|
INT ti = FLOOR(t)
|
|
INT ind, i
|
|
|
|
IF (iTotalPointsInSpline < 2)
|
|
RETURN 0
|
|
ENDIF
|
|
|
|
// get the points - such that v1 and v2 are the ones we need
|
|
REPEAT 4 i
|
|
ind = CLAMP_INT(ti - 1, 0, iTotalPointsInSpline - 1)
|
|
v[i] = vPoints[ind]
|
|
i ++
|
|
ti ++
|
|
ENDREPEAT
|
|
|
|
// get the section we need
|
|
ti = FLOOR(t)
|
|
t -= TO_FLOAT(ti)
|
|
|
|
RETURN GMMR_CALCULATE_SPLINE_POINT(v[0], v[1], v[2], v[3], t)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Get Spline Segment Length
|
|
/// PARAMS:
|
|
/// vPoints - Array of Points
|
|
/// iTotalPointsInSpline - Total # of Spline Points
|
|
/// iNode - Node To Check
|
|
/// fStep -
|
|
/// RETURNS:
|
|
///
|
|
FUNC FLOAT GGMR_GET_SPLINE_SEGMENT_LENGTH(VECTOR_2D &vPoints[], INT iTotalPointsInSpline, INT iNode, FLOAT fStep = 0.005)
|
|
FLOAT t
|
|
FLOAT len = 0.0
|
|
VECTOR_2D newPoint
|
|
VECTOR_2D oldPoint = GGMR_GET_SPLINE_POINT(vPoints, iTotalPointsInSpline, TO_FLOAT(iNode))
|
|
|
|
WHILE (t < 1.0)
|
|
newPoint = GGMR_GET_SPLINE_POINT(vPoints, iTotalPointsInSpline, TO_FLOAT(iNode) + t)
|
|
len += VECTOR_2D_DIST(newPoint, oldPoint)
|
|
oldPoint = newPoint
|
|
t += fStep
|
|
ENDWHILE
|
|
|
|
RETURN len
|
|
ENDFUNC
|
|
|
|
//-------------------------------------------------
|
|
// COLLISION DATA FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// Sets Collsion Data as a circle
|
|
/// PARAMS:
|
|
/// data - data
|
|
/// vCenter - center circle
|
|
/// fRadius - radius
|
|
PROC GGSM_COLLISION_DATA_SET_AS_CIRCLE(GGSM_COLLISION_DATA &data, VECTOR_2D vCenter, FLOAT fRadius)
|
|
data.eType = GGSM_COLLISION_CIRCLE
|
|
data.vCollisionVectors[0] = vCenter
|
|
data.vCollisionVectors[1] = vCenter
|
|
data.fColRadius = fRadius
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Set Collision Data as a capsule
|
|
/// PARAMS:
|
|
/// data - data
|
|
/// v1 - point 1 (this generally should be the leading point)
|
|
/// v2 - point 2
|
|
/// fRadius - radius
|
|
PROC GGSM_COLLISION_DATA_SET_AS_CAPSULE(GGSM_COLLISION_DATA &data, VECTOR_2D v1, VECTOR_2D v2, FLOAT fRadius)
|
|
data.eType = GGSM_COLLISION_CAPSULE
|
|
data.vCollisionVectors[0] = v1
|
|
data.vCollisionVectors[1] = v2
|
|
data.fColRadius = fRadius
|
|
ENDPROC
|
|
|
|
//-------------------------------------------------
|
|
// COLLIDER DATA FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// Generate AABB from Collision Data -
|
|
/// PARAMS:
|
|
/// d1 -
|
|
PROC GGSM_COLLIDER_CALCULATE_AABB(GGSM_COLLIDER &d1)
|
|
VECTOR_2D vMin, vMax
|
|
|
|
IF (d1.sData.eType = GGSM_COLLISION_CIRCLE)
|
|
d1.sAABB.vCenter = d1.sData.vCollisionVectors[0]
|
|
d1.sAABB.vHalfSize.x = d1.sData.fColRadius
|
|
d1.sAABB.vHalfSize.y = d1.sData.fColRadius
|
|
EXIT
|
|
ENDIF
|
|
|
|
IF (d1.sData.eType = GGSM_COLLISION_CAPSULE)
|
|
// get min and max
|
|
vMin.x = FMIN(d1.sData.vCollisionVectors[0].x, d1.sData.vCollisionVectors[1].x) - d1.sData.fColRadius
|
|
vMin.y = FMIN(d1.sData.vCollisionVectors[0].y, d1.sData.vCollisionVectors[1].y) - d1.sData.fColRadius
|
|
vMax.x = FMAX(d1.sData.vCollisionVectors[0].x, d1.sData.vCollisionVectors[1].x) + d1.sData.fColRadius
|
|
vMax.y = FMAX(d1.sData.vCollisionVectors[0].y, d1.sData.vCollisionVectors[1].y) + d1.sData.fColRadius
|
|
|
|
// calculate half widths
|
|
d1.sAABB.vHalfSize.x = (vMax.x - vMin.x) / 2.0
|
|
d1.sAABB.vHalfSize.y = (vMax.y - vMin.y) / 2.0
|
|
|
|
// calculate center
|
|
d1.sAABB.vCenter.x = vMin.x + d1.sAABB.vHalfSize.x
|
|
d1.sAABB.vCenter.y = vMin.y + d1.sAABB.vHalfSize.y
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Transforms a collider
|
|
/// PARAMS:
|
|
/// col -
|
|
/// vPos - translation
|
|
/// fRot - rotation
|
|
/// baseData - base collider data
|
|
PROC GGSM_COLLIDER_TRANSFORM(GGSM_COLLIDER &col, GGSM_TRANSFORM &trans, GGSM_COLLISION_DATA &baseData)
|
|
col.sData = baseData
|
|
col.sData.fColRadius *= ABSF(GGSM_GET_DOMINANT_AXIS(trans.vScale))
|
|
|
|
IF (col.sData.eType = GGSM_COLLISION_CIRCLE)
|
|
col.sData.vCollisionVectors[0] = GGSM_TRANSFORM_LOCAL_POS_TO_WORLD_POS(trans, baseData.vCollisionVectors[0])
|
|
ELSE
|
|
col.sData.vCollisionVectors[0] = GGSM_TRANSFORM_LOCAL_POS_TO_WORLD_POS(trans, baseData.vCollisionVectors[0])
|
|
col.sData.vCollisionVectors[1] = GGSM_TRANSFORM_LOCAL_POS_TO_WORLD_POS(trans, baseData.vCollisionVectors[1])
|
|
ENDIF
|
|
|
|
GGSM_COLLIDER_CALCULATE_AABB(col)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Determines if two circles have collided
|
|
/// Note - Only use this with transformed collision data
|
|
/// PARAMS:
|
|
/// d1 - Collision Data 1
|
|
/// d2 - Collision Data 2
|
|
/// RETURNS:
|
|
/// TRUE if collision occurs
|
|
FUNC BOOL GGSM_COLLIDER_CIRCLE_CIRCLE_INTERSECT(GGSM_COLLIDER &d1, GGSM_COLLIDER &d2)
|
|
FLOAT fRad
|
|
VECTOR_2D vec
|
|
|
|
// get distance between both circle centers squared
|
|
fRad = (d1.sData.fColRadius + d2.sData.fColRadius) * (d1.sData.fColRadius + d2.sData.fColRadius)
|
|
|
|
// get the vector between the 2 centers
|
|
vec.x = d2.sData.vCollisionVectors[0].x - d1.sData.vCollisionVectors[0].x
|
|
vec.y = d2.sData.vCollisionVectors[0].y - d1.sData.vCollisionVectors[0].y
|
|
|
|
// do a distance check
|
|
RETURN ((vec.x * vec.x) + (vec.y * vec.y)) < fRad
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Determines if two rects have collided
|
|
/// Note - Only use this with transformed collision data
|
|
/// PARAMS:
|
|
/// d1 - Collision Data 1
|
|
/// d2 - Collision Data 2
|
|
/// RETURNS:
|
|
/// TRUE if collision occurs
|
|
FUNC BOOL GGSM_COLLIDER_AABB_AABB_INTERSECT(GGSM_COLLIDER &d1, GGSM_COLLIDER &d2)
|
|
IF (ABSF(d1.sAABB.vCenter.x - d2.sAABB.vCenter.x) > (d1.sAABB.vHalfSize.x + d2.sAABB.vHalfSize.x))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (ABSF(d1.sAABB.vCenter.y - d2.sAABB.vCenter.y) > (d1.sAABB.vHalfSize.y + d2.sAABB.vHalfSize.y))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Tells us if a sprite is within the draw area
|
|
/// PARAMS:
|
|
/// vPos - Sprite Pos
|
|
/// vSize - Sprite Size
|
|
/// RETURNS:
|
|
/// TRUE if it is on screen
|
|
FUNC BOOL GGSM_IS_COLLIDER_AABB_ON_SCREEN(GGSM_COLLIDER &d1)
|
|
IF (d1.sAABB.vCenter.x < (GGSM_PX_OVERSCAN_MIN_X - d1.sAABB.vHalfSize.x)) OR (d1.sAABB.vCenter.x > (GGSM_PX_OVERSCAN_MAX_X + d1.sAABB.vHalfSize.x))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (d1.sAABB.vCenter.y < (GGSM_PX_OVERSCAN_MIN_Y - d1.sAABB.vHalfSize.y)) OR (d1.sAABB.vCenter.y > (GGSM_PX_OVERSCAN_MAX_Y + d1.sAABB.vHalfSize.y))
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Returns true is capsule and circle intersect
|
|
/// PARAMS:
|
|
/// ca1 -
|
|
/// c2 -
|
|
/// RETURNS:
|
|
///
|
|
FUNC BOOL GGSM_COLLIDER_CAPSULE_CIRCLE_INTERSECT(GGSM_COLLIDER &ca1, GGSM_COLLIDER &c2)
|
|
FLOAT r = c2.sData.fColRadius + ca1.sData.fColRadius
|
|
VECTOR v = GET_CLOSEST_POINT_ON_LINE(<<c2.sData.vCollisionVectors[0].x, c2.sData.vCollisionVectors[0].y, 0>>, <<ca1.sData.vCollisionVectors[0].x, ca1.sData.vCollisionVectors[0].y, 0>>, <<ca1.sData.vCollisionVectors[1].x, ca1.sData.vCollisionVectors[1].y, 0>>, TRUE)
|
|
RETURN VECTOR_2D_DIST2(INIT_VECTOR_2D(v.x, v.y), c2.sData.vCollisionVectors[0]) <= (r * r)
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Determines if two rects have collided
|
|
/// Note - Only use this with transformed collision data
|
|
/// PARAMS:
|
|
/// d1 - Collision Data 1
|
|
/// d2 - Collision Data 2
|
|
/// RETURNS:
|
|
/// TRUE if collision occurs
|
|
FUNC BOOL GGSM_COLLIDER_CAPSULE_CAPSULE_INTERSECT(GGSM_COLLIDER &d1, GGSM_COLLIDER &d2)
|
|
FLOAT distSQ = GGSM_SEGMENT_DISTANCE_SQUARED(d1.sData.vCollisionVectors[0], d1.sData.vCollisionVectors[1], d2.sData.vCollisionVectors[0], d2.sData.vCollisionVectors[1])
|
|
IF (distSQ < GGSM_EPSILON)
|
|
RETURN TRUE
|
|
ENDIF
|
|
|
|
FLOAT rsq = (d1.sData.fColRadius + d2.sData.fColRadius)
|
|
RETURN (distSQ <= (rsq * rsq))
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
/// Determines if two collision datas have collided
|
|
/// Note - Only use this with transformed collision data
|
|
/// PARAMS:
|
|
/// d1 - Collision Data 1
|
|
/// d2 - Collision Data 2
|
|
/// RETURNS:
|
|
/// TRUE if collision occurs
|
|
FUNC BOOL GGSM_COLLIDER_INTERSECT(GGSM_COLLIDER &d1, GGSM_COLLIDER &d2)
|
|
|
|
IF NOT GGSM_COLLIDER_AABB_AABB_INTERSECT(d1, d2)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// d1 is a circle
|
|
IF (d1.sData.eType = GGSM_COLLISION_CIRCLE)
|
|
IF (d2.sData.eType = GGSM_COLLISION_CIRCLE)
|
|
RETURN GGSM_COLLIDER_CIRCLE_CIRCLE_INTERSECT(d1, d2)
|
|
ELIF (d2.sData.eType = GGSM_COLLISION_CAPSULE)
|
|
RETURN GGSM_COLLIDER_CAPSULE_CIRCLE_INTERSECT(d2, d1)
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
// d1 is a capsule
|
|
IF (d1.sData.eType = GGSM_COLLISION_CAPSULE)
|
|
IF (d2.sData.eType = GGSM_COLLISION_CIRCLE)
|
|
RETURN GGSM_COLLIDER_CAPSULE_CIRCLE_INTERSECT(d1, d2)
|
|
ELIF (d2.sData.eType = GGSM_COLLISION_CAPSULE)
|
|
RETURN GGSM_COLLIDER_CAPSULE_CAPSULE_INTERSECT(d1, d2)
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
//-------------------------------------------------
|
|
// TILE COLLISION DATA FUNCTIONS
|
|
//-------------------------------------------------
|
|
|
|
/// PURPOSE:
|
|
/// Wrapper function as at a some point I'll need to pack these
|
|
/// PARAMS:
|
|
/// data -
|
|
/// i -
|
|
/// fx -
|
|
/// fy -
|
|
PROC GGSM_TILE_COLLISION_DATA_SET_COLLISION_VECTOR(GGSM_TILE_COLLISION_DATA &data, INT i, FLOAT fx, FLOAT fy)
|
|
data.vCollisionVectors[i].x = fx
|
|
data.vCollisionVectors[i].y = fy
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Wrapper function as at a some point I'll need to pack these
|
|
/// PARAMS:
|
|
/// data -
|
|
/// i -
|
|
/// RETURNS:
|
|
///
|
|
FUNC VECTOR_2D GGSM_TILE_COLLISION_DATA_GET_COLLISION_VECTOR(GGSM_TILE_COLLISION_DATA &data, INT i)
|
|
RETURN data.vCollisionVectors[i]
|
|
ENDFUNC
|
|
|
|
/// PURPOSE:
|
|
///
|
|
/// PARAMS:
|
|
/// data -
|
|
/// vCenter - This center is relative to the top left corner of the tile
|
|
/// fRadius - Radius
|
|
PROC GGSM_TILE_COLLISION_DATA_SET_AS_BOX(GGSM_TILE_COLLISION_DATA &data, VECTOR_2D vCenter, VECTOR_2D vSize)
|
|
data.vCollisionVectors[0] = vCenter
|
|
data.vCollisionVectors[1].x = vSize.x / 2.0
|
|
data.vCollisionVectors[1].y = vSize.y / 2.0
|
|
data.eType = GGSM_TILE_COLLISION_BOX
|
|
data.vCollisionVectors[2].x = vCenter.x - data.vCollisionVectors[1].x
|
|
data.vCollisionVectors[2].y = vCenter.y - data.vCollisionVectors[1].y
|
|
data.vCollisionVectors[3].x = vCenter.x + data.vCollisionVectors[1].x
|
|
data.vCollisionVectors[3].y = vCenter.y + data.vCollisionVectors[1].y
|
|
data.iNumPoints = 1
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
///
|
|
/// PARAMS:
|
|
/// data -
|
|
/// vMin - Min Corner Of Box
|
|
/// vMax - Max Corner of Box
|
|
PROC GGSM_TILE_COLLISION_DATA_SET_AS_BOX_MIN_MAX(GGSM_TILE_COLLISION_DATA &data, VECTOR_2D vMin, VECTOR_2D vMax)
|
|
VECTOR_2D vSize = INIT_VECTOR_2D((vMax.x - vMin.x) / 2.0, (vMax.y - vMin.y) / 2.0)
|
|
|
|
data.eType = GGSM_TILE_COLLISION_BOX
|
|
data.vCollisionVectors[0] = vMin
|
|
data.vCollisionVectors[0].x += vSize.x
|
|
data.vCollisionVectors[0].y += vSize.y
|
|
|
|
data.vCollisionVectors[1] = vSize
|
|
data.vCollisionVectors[2] = vMin
|
|
data.vCollisionVectors[3] = vMax
|
|
data.iNumPoints = 1
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Wrapper to Set Tile Collision as Line
|
|
/// PARAMS:
|
|
/// data -
|
|
/// vPoint1 - Position is relative to the top left corner of tile
|
|
/// vPoint2 - Position is relative to the top left corner of tile
|
|
PROC GGSM_TILE_COLLISION_DATA_SET_AS_LINE(GGSM_TILE_COLLISION_DATA &data, VECTOR_2D vPoint1, VECTOR_2D vPoint2)
|
|
data.eType = GGSM_TILE_COLLISION_LINE
|
|
data.vCollisionVectors[0] = vPoint1
|
|
data.vCollisionVectors[1] = vPoint2
|
|
data.iNumPoints = 2
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Wrapper to Set Tile Collision as Triangle
|
|
/// PARAMS:
|
|
/// data -
|
|
/// vPoint1 - Position is relative to the top left corner of tile
|
|
/// vPoint2 - Position is relative to the top left corner of tile
|
|
/// vPoint3 - Position is relative to the top left corner of tile
|
|
PROC GGSM_TILE_COLLISION_DATA_SET_AS_TRIANGLE(GGSM_TILE_COLLISION_DATA &data, VECTOR_2D vPoint1, VECTOR_2D vPoint2, VECTOR_2D vPoint3)
|
|
data.eType = GGSM_TILE_COLLISION_POLYGON
|
|
data.vCollisionVectors[0] = vPoint1
|
|
data.vCollisionVectors[1] = vPoint2
|
|
data.vCollisionVectors[2] = vPoint3
|
|
data.iNumPoints = 3
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Wrapper to Set Tile Collision as Polygon
|
|
/// PARAMS:
|
|
/// data -
|
|
/// vPoints - Position is relative to the top left corner of tile
|
|
/// iNumPoints - Num of Points
|
|
PROC GGSM_TILE_COLLISION_DATA_SET_AS_POLYGON(GGSM_TILE_COLLISION_DATA &data, VECTOR_2D &vPoints[], INT iNumPoints)
|
|
IF (iNumPoints > GGSM_MAX_TILE_POLYPOINTS)
|
|
SCRIPT_ASSERT("TOO MANY POINTS MAX IS 6")
|
|
EXIT
|
|
ENDIF
|
|
|
|
INT i
|
|
|
|
REPEAT iNumPoints i
|
|
data.vCollisionVectors[i] = vPoints[i]
|
|
ENDREPEAT
|
|
|
|
data.eType = GGSM_TILE_COLLISION_POLYGON
|
|
data.iNumPoints = iNumPoints
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Flips Tile Collision and
|
|
/// PARAMS:
|
|
/// tm -
|
|
/// iTileIndex -
|
|
/// dest -
|
|
/// bHFlip -
|
|
/// bVFlip -
|
|
PROC GGSM_TILEMAP_FLIP_COLLISION(GGSM_TILEMAP &tm, INT iTileIndex, GGSM_TILE_COLLISION_DATA &dest, BOOL bHFlip, BOOL bVFlip)
|
|
INT i
|
|
|
|
dest = tm.sCollisionData[iTileIndex]
|
|
REPEAT dest.iNumPoints i
|
|
IF (bHFlip)
|
|
dest.vCollisionVectors[i].x = tm.fTileSize - dest.vCollisionVectors[i].x
|
|
ENDIF
|
|
|
|
IF (bVFlip)
|
|
dest.vCollisionVectors[i].y = tm.fTileSize - dest.vCollisionVectors[i].y
|
|
ENDIF
|
|
ENDREPEAT
|
|
ENDPROC
|
|
|
|
FUNC BOOL GGSM_TILE_COLLISION_IN_POINT_IN_TILE(VECTOR_2D vTestPoint, VECTOR_2D vTileTopLeft, GGSM_TILE_COLLISION_DATA &data)
|
|
VECTOR_2D vCenter
|
|
|
|
SWITCH (data.eType)
|
|
CASE GGSM_TILE_COLLISION_BOX
|
|
vCenter = ADD_VECTOR_2D(vTileTopLeft, data.vCollisionVectors[0])
|
|
IF (ABSF(vCenter.x - vTestPoint.x) > data.vCollisionVectors[1].x)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
IF (ABSF(vCenter.y - vTestPoint.y) > data.vCollisionVectors[1].y)
|
|
RETURN FALSE
|
|
ENDIF
|
|
|
|
RETURN TRUE
|
|
BREAK
|
|
|
|
CASE GGSM_TILE_COLLISION_POLYGON
|
|
vTestPoint = SUBTRACT_VECTOR_2D(vTestPoint, vTileTopLeft) // move test point in tile space
|
|
RETURN GGSM_IS_POINT_IN_POLYGON(vTestPoint, data.vCollisionVectors, data.iNumPoints)
|
|
BREAK
|
|
ENDSWITCH
|
|
|
|
RETURN FALSE
|
|
ENDFUNC
|
|
|
|
/*
|
|
/// PURPOSE:
|
|
/// Calculate which tile a particular position in screen coords is over
|
|
/// PARAMS:
|
|
/// cam - camera struct
|
|
/// vScreenPos - screen pos
|
|
/// tx - tile x
|
|
/// ty - tile y
|
|
PROC GGSM_CAMERA_GET_SCREEN_POSITION_IN_TILE_MAP(GGSM_CAMERA &cam, GGSM_TILEMAP &tm, VECTOR_2D vScreenPos, INT &tx, INT &ty)
|
|
tx = FLOOR((vScreenPos.x + cam.vWorldPosition.x) / tm.fTileSize)
|
|
ty = FLOOR((vScreenPos.y + cam.vWorldPosition.y) / tm.fTileSize)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Calculate which tile a particular position in screen coords is over
|
|
/// PARAMS:
|
|
/// cam - camera struct
|
|
/// vScreenPos - screen pos
|
|
/// tx - tile x
|
|
/// ty - tile y
|
|
PROC GGSM_WORLD_POSITION_IN_TILE_MAP(GGSM_TILEMAP &tm, VECTOR_2D vPos, INT &tx, INT &ty)
|
|
tx = FLOOR(vPos.x / tm.fTileSize)
|
|
ty = FLOOR(vPos.y / tm.fTileSize)
|
|
ENDPROC
|
|
|
|
/// PURPOSE:
|
|
/// Give a tilemap coord give us the top left pos in world sapce
|
|
/// PARAMS:
|
|
/// tm - tilemap
|
|
/// iMx - map coord x
|
|
/// iMy - map coord y
|
|
/// RETURNS:
|
|
/// World Position of Top Left Corner of tile
|
|
FUNC VECTOR_2D GGSM_TILEMAP_GET_TOP_LEFT_WORLD_POSITION_FOR_TILE(GGSM_TILEMAP &tm, INT iMx, INT iMy)
|
|
VECTOR_2D vec
|
|
vec.x = iMx * tm.fTileSize
|
|
vec.y = iMy * tm.fTileSize
|
|
RETURN vec
|
|
ENDFUNC
|
|
*/
|
|
|