// ============================================================================
// Basic shapes drawing (all wrappers — every function takes Color/Vector2/Rectangle)
// ============================================================================
///|
/// Draw a pixel using geometry. Can be slow, use with care.
pub fn draw_pixel(pos_x : Int, pos_y : Int, color : Color) -> Unit {
@ffi.draw_pixel(pos_x, pos_y, color.to_bytes())
}
///|
/// Draw a pixel using geometry (Vector version). Can be slow, use with care.
pub fn draw_pixel_v(position : Vector2, color : Color) -> Unit {
@ffi.draw_pixel_v(position.to_bytes(), color.to_bytes())
}
///|
/// Draw a line.
pub fn draw_line(
start_x : Int,
start_y : Int,
end_x : Int,
end_y : Int,
color : Color,
) -> Unit {
@ffi.draw_line(start_x, start_y, end_x, end_y, color.to_bytes())
}
///|
/// Draw a line (using gl lines).
pub fn draw_line_v(
start_pos : Vector2,
end_pos : Vector2,
color : Color,
) -> Unit {
@ffi.draw_line_v(start_pos.to_bytes(), end_pos.to_bytes(), color.to_bytes())
}
///|
/// Draw a line (using triangles/quads).
pub fn draw_line_ex(
start_pos : Vector2,
end_pos : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_line_ex(
start_pos.to_bytes(),
end_pos.to_bytes(),
thick,
color.to_bytes(),
)
}
///|
/// Draw line segment cubic-bezier in-out interpolation.
pub fn draw_line_bezier(
start_pos : Vector2,
end_pos : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_line_bezier(
start_pos.to_bytes(),
end_pos.to_bytes(),
thick,
color.to_bytes(),
)
}
///|
/// Draw a color-filled circle.
pub fn draw_circle(
center_x : Int,
center_y : Int,
radius : Float,
color : Color,
) -> Unit {
@ffi.draw_circle(center_x, center_y, radius, color.to_bytes())
}
///|
/// Draw a piece of a circle.
pub fn draw_circle_sector(
center : Vector2,
radius : Float,
start_angle : Float,
end_angle : Float,
segments : Int,
color : Color,
) -> Unit {
@ffi.draw_circle_sector(
center.to_bytes(),
radius,
start_angle,
end_angle,
segments,
color.to_bytes(),
)
}
///|
/// Draw a gradient-filled circle.
pub fn draw_circle_gradient(
center : Vector2,
radius : Float,
inner : Color,
outer : Color,
) -> Unit {
@ffi.draw_circle_gradient(
center.to_bytes(),
radius,
inner.to_bytes(),
outer.to_bytes(),
)
}
///|
/// Draw a color-filled circle (Vector version).
pub fn draw_circle_v(center : Vector2, radius : Float, color : Color) -> Unit {
@ffi.draw_circle_v(center.to_bytes(), radius, color.to_bytes())
}
///|
/// Draw circle outline.
pub fn draw_circle_lines(
center_x : Int,
center_y : Int,
radius : Float,
color : Color,
) -> Unit {
@ffi.draw_circle_lines(center_x, center_y, radius, color.to_bytes())
}
///|
/// Draw circle outline (Vector version).
pub fn draw_circle_lines_v(
center : Vector2,
radius : Float,
color : Color,
) -> Unit {
@ffi.draw_circle_lines_v(center.to_bytes(), radius, color.to_bytes())
}
///|
/// Draw ellipse.
pub fn draw_ellipse(
center_x : Int,
center_y : Int,
radius_h : Float,
radius_v : Float,
color : Color,
) -> Unit {
@ffi.draw_ellipse(center_x, center_y, radius_h, radius_v, color.to_bytes())
}
///|
/// Draw ellipse outline.
pub fn draw_ellipse_lines(
center_x : Int,
center_y : Int,
radius_h : Float,
radius_v : Float,
color : Color,
) -> Unit {
@ffi.draw_ellipse_lines(
center_x,
center_y,
radius_h,
radius_v,
color.to_bytes(),
)
}
///|
/// Draw ring.
pub fn draw_ring(
center : Vector2,
inner_radius : Float,
outer_radius : Float,
start_angle : Float,
end_angle : Float,
segments : Int,
color : Color,
) -> Unit {
@ffi.draw_ring(
center.to_bytes(),
inner_radius,
outer_radius,
start_angle,
end_angle,
segments,
color.to_bytes(),
)
}
///|
/// Draw ring outline.
pub fn draw_ring_lines(
center : Vector2,
inner_radius : Float,
outer_radius : Float,
start_angle : Float,
end_angle : Float,
segments : Int,
color : Color,
) -> Unit {
@ffi.draw_ring_lines(
center.to_bytes(),
inner_radius,
outer_radius,
start_angle,
end_angle,
segments,
color.to_bytes(),
)
}
///|
/// Draw a color-filled rectangle.
pub fn draw_rectangle(
pos_x : Int,
pos_y : Int,
width : Int,
height : Int,
color : Color,
) -> Unit {
@ffi.draw_rectangle(pos_x, pos_y, width, height, color.to_bytes())
}
///|
/// Draw a color-filled rectangle (Vector version).
pub fn draw_rectangle_v(
position : Vector2,
size : Vector2,
color : Color,
) -> Unit {
@ffi.draw_rectangle_v(position.to_bytes(), size.to_bytes(), color.to_bytes())
}
///|
/// Draw a color-filled rectangle.
pub fn draw_rectangle_rec(rec : Rectangle, color : Color) -> Unit {
@ffi.draw_rectangle_rec(rec.to_bytes(), color.to_bytes())
}
///|
/// Draw a color-filled rectangle with pro parameters.
pub fn draw_rectangle_pro(
rec : Rectangle,
origin : Vector2,
rotation : Float,
color : Color,
) -> Unit {
@ffi.draw_rectangle_pro(
rec.to_bytes(),
origin.to_bytes(),
rotation,
color.to_bytes(),
)
}
///|
/// Draw a vertical-gradient-filled rectangle.
pub fn draw_rectangle_gradient_v(
pos_x : Int,
pos_y : Int,
width : Int,
height : Int,
top : Color,
bottom : Color,
) -> Unit {
@ffi.draw_rectangle_gradient_v(
pos_x,
pos_y,
width,
height,
top.to_bytes(),
bottom.to_bytes(),
)
}
///|
/// Draw a horizontal-gradient-filled rectangle.
pub fn draw_rectangle_gradient_h(
pos_x : Int,
pos_y : Int,
width : Int,
height : Int,
left : Color,
right : Color,
) -> Unit {
@ffi.draw_rectangle_gradient_h(
pos_x,
pos_y,
width,
height,
left.to_bytes(),
right.to_bytes(),
)
}
///|
/// Draw a gradient-filled rectangle with custom vertex colors.
pub fn draw_rectangle_gradient_ex(
rec : Rectangle,
top_left : Color,
bottom_left : Color,
top_right : Color,
bottom_right : Color,
) -> Unit {
@ffi.draw_rectangle_gradient_ex(
rec.to_bytes(),
top_left.to_bytes(),
bottom_left.to_bytes(),
top_right.to_bytes(),
bottom_right.to_bytes(),
)
}
///|
/// Draw rectangle outline.
pub fn draw_rectangle_lines(
pos_x : Int,
pos_y : Int,
width : Int,
height : Int,
color : Color,
) -> Unit {
@ffi.draw_rectangle_lines(pos_x, pos_y, width, height, color.to_bytes())
}
///|
/// Draw rectangle outline with extended parameters.
pub fn draw_rectangle_lines_ex(
rec : Rectangle,
line_thick : Float,
color : Color,
) -> Unit {
@ffi.draw_rectangle_lines_ex(rec.to_bytes(), line_thick, color.to_bytes())
}
///|
/// Draw rectangle with rounded edges.
pub fn draw_rectangle_rounded(
rec : Rectangle,
roundness : Float,
segments : Int,
color : Color,
) -> Unit {
@ffi.draw_rectangle_rounded(
rec.to_bytes(),
roundness,
segments,
color.to_bytes(),
)
}
///|
/// Draw rectangle lines with rounded edges.
pub fn draw_rectangle_rounded_lines(
rec : Rectangle,
roundness : Float,
segments : Int,
color : Color,
) -> Unit {
@ffi.draw_rectangle_rounded_lines(
rec.to_bytes(),
roundness,
segments,
color.to_bytes(),
)
}
///|
/// Draw rectangle with rounded edges outline.
pub fn draw_rectangle_rounded_lines_ex(
rec : Rectangle,
roundness : Float,
segments : Int,
line_thick : Float,
color : Color,
) -> Unit {
@ffi.draw_rectangle_rounded_lines_ex(
rec.to_bytes(),
roundness,
segments,
line_thick,
color.to_bytes(),
)
}
///|
/// Draw a color-filled triangle (vertex in counter-clockwise order!).
pub fn draw_triangle(
v1 : Vector2,
v2 : Vector2,
v3 : Vector2,
color : Color,
) -> Unit {
@ffi.draw_triangle(
v1.to_bytes(),
v2.to_bytes(),
v3.to_bytes(),
color.to_bytes(),
)
}
///|
/// Draw triangle outline (vertex in counter-clockwise order!).
pub fn draw_triangle_lines(
v1 : Vector2,
v2 : Vector2,
v3 : Vector2,
color : Color,
) -> Unit {
@ffi.draw_triangle_lines(
v1.to_bytes(),
v2.to_bytes(),
v3.to_bytes(),
color.to_bytes(),
)
}
///|
/// Draw a regular polygon (Vector version).
pub fn draw_poly(
center : Vector2,
sides : Int,
radius : Float,
rotation : Float,
color : Color,
) -> Unit {
@ffi.draw_poly(center.to_bytes(), sides, radius, rotation, color.to_bytes())
}
///|
/// Draw a polygon outline of n sides.
pub fn draw_poly_lines(
center : Vector2,
sides : Int,
radius : Float,
rotation : Float,
color : Color,
) -> Unit {
@ffi.draw_poly_lines(
center.to_bytes(),
sides,
radius,
rotation,
color.to_bytes(),
)
}
///|
/// Draw a polygon outline of n sides with extended parameters.
pub fn draw_poly_lines_ex(
center : Vector2,
sides : Int,
radius : Float,
rotation : Float,
line_thick : Float,
color : Color,
) -> Unit {
@ffi.draw_poly_lines_ex(
center.to_bytes(),
sides,
radius,
rotation,
line_thick,
color.to_bytes(),
)
}
// ============================================================================
// Collision detection (pure MoonBit)
// ============================================================================
///|
/// Check collision between two rectangles.
pub fn check_collision_recs(rec1 : Rectangle, rec2 : Rectangle) -> Bool {
rec1.x < rec2.x + rec2.width &&
rec1.x + rec1.width > rec2.x &&
rec1.y < rec2.y + rec2.height &&
rec1.y + rec1.height > rec2.y
}
///|
/// Check collision between two circles.
pub fn check_collision_circles(
center1 : Vector2,
radius1 : Float,
center2 : Vector2,
radius2 : Float,
) -> Bool {
let dx = center2.x - center1.x
let dy = center2.y - center1.y
let distance_squared = dx * dx + dy * dy
let radius_sum = radius1 + radius2
distance_squared <= radius_sum * radius_sum
}
///|
/// Check collision between circle and rectangle.
pub fn check_collision_circle_rec(
center : Vector2,
radius : Float,
rec : Rectangle,
) -> Bool {
let rec_center_x = rec.x + rec.width / 2.0
let rec_center_y = rec.y + rec.height / 2.0
let dx = fabsf(center.x - rec_center_x)
let dy = fabsf(center.y - rec_center_y)
if dx > rec.width / 2.0 + radius {
return false
}
if dy > rec.height / 2.0 + radius {
return false
}
if dx <= rec.width / 2.0 {
return true
}
if dy <= rec.height / 2.0 {
return true
}
let corner_dist_sq = (dx - rec.width / 2.0) * (dx - rec.width / 2.0) +
(dy - rec.height / 2.0) * (dy - rec.height / 2.0)
corner_dist_sq <= radius * radius
}
///|
/// Check if point is inside rectangle.
pub fn check_collision_point_rec(point : Vector2, rec : Rectangle) -> Bool {
point.x >= rec.x &&
point.x < rec.x + rec.width &&
point.y >= rec.y &&
point.y < rec.y + rec.height
}
///|
/// Check if point is inside circle.
pub fn check_collision_point_circle(
point : Vector2,
center : Vector2,
radius : Float,
) -> Bool {
let distance_squared = (point.x - center.x) * (point.x - center.x) +
(point.y - center.y) * (point.y - center.y)
distance_squared <= radius * radius
}
///|
/// Check if point is inside a triangle.
pub fn check_collision_point_triangle(
point : Vector2,
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
) -> Bool {
let alpha = (
(p2.y - p3.y) * (point.x - p3.x) + (p3.x - p2.x) * (point.y - p3.y)
) /
((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y))
let beta = (
(p3.y - p1.y) * (point.x - p3.x) + (p1.x - p3.x) * (point.y - p3.y)
) /
((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y))
let gamma = (1.0 : Float) - alpha - beta
alpha > 0.0 && beta > 0.0 && gamma > 0.0
}
///|
/// Get collision rectangle for two rectangles collision.
pub fn get_collision_rec(rec1 : Rectangle, rec2 : Rectangle) -> Rectangle {
let left = if rec1.x > rec2.x { rec1.x } else { rec2.x }
let right1 = rec1.x + rec1.width
let right2 = rec2.x + rec2.width
let right = if right1 < right2 { right1 } else { right2 }
let top = if rec1.y > rec2.y { rec1.y } else { rec2.y }
let bottom1 = rec1.y + rec1.height
let bottom2 = rec2.y + rec2.height
let bottom = if bottom1 < bottom2 { bottom1 } else { bottom2 }
if left < right && top < bottom {
{ x: left, y: top, width: right - left, height: bottom - top }
} else {
{ x: 0.0, y: 0.0, width: 0.0, height: 0.0 }
}
}
// ============================================================================
// Missing basic shapes (array-based + circle sector lines)
// ============================================================================
///|
/// Draw circle sector outline.
pub fn draw_circle_sector_lines(
center : Vector2,
radius : Float,
start_angle : Float,
end_angle : Float,
segments : Int,
color : Color,
) -> Unit {
@ffi.draw_circle_sector_lines(
center.to_bytes(),
radius,
start_angle,
end_angle,
segments,
color.to_bytes(),
)
}
///|
fn vector2_array_to_bytes(points : Array[Vector2]) -> Bytes {
let buf = @buffer.new(size_hint=points.length() * 8)
for p in points {
buf.write_float_le(p.x)
buf.write_float_le(p.y)
}
buf.to_bytes()
}
///|
/// Draw lines sequence (using gl lines).
pub fn draw_line_strip(points : Array[Vector2], color : Color) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_line_strip(bytes, points.length(), color.to_bytes())
}
///|
/// Draw a triangle fan defined by points (first vertex is the center).
pub fn draw_triangle_fan(points : Array[Vector2], color : Color) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_triangle_fan(bytes, points.length(), color.to_bytes())
}
///|
/// Draw a triangle strip defined by points.
pub fn draw_triangle_strip(points : Array[Vector2], color : Color) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_triangle_strip(bytes, points.length(), color.to_bytes())
}
// ============================================================================
// Spline drawing (array-based)
// ============================================================================
///|
/// Draw spline: Linear, minimum 2 points.
pub fn draw_spline_linear(
points : Array[Vector2],
thick : Float,
color : Color,
) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_spline_linear(bytes, points.length(), thick, color.to_bytes())
}
///|
/// Draw spline: B-Spline, minimum 4 points.
pub fn draw_spline_basis(
points : Array[Vector2],
thick : Float,
color : Color,
) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_spline_basis(bytes, points.length(), thick, color.to_bytes())
}
///|
/// Draw spline: Catmull-Rom, minimum 4 points.
pub fn draw_spline_catmull_rom(
points : Array[Vector2],
thick : Float,
color : Color,
) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_spline_catmull_rom(bytes, points.length(), thick, color.to_bytes())
}
///|
/// Draw spline: Quadratic Bezier, minimum 3 points (1 control point).
pub fn draw_spline_bezier_quadratic(
points : Array[Vector2],
thick : Float,
color : Color,
) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_spline_bezier_quadratic(
bytes,
points.length(),
thick,
color.to_bytes(),
)
}
///|
/// Draw spline: Cubic Bezier, minimum 4 points (2 control points).
pub fn draw_spline_bezier_cubic(
points : Array[Vector2],
thick : Float,
color : Color,
) -> Unit {
let bytes = vector2_array_to_bytes(points)
@ffi.draw_spline_bezier_cubic(bytes, points.length(), thick, color.to_bytes())
}
// ============================================================================
// Spline segments
// ============================================================================
///|
/// Draw spline segment: Linear, 2 points.
pub fn draw_spline_segment_linear(
p1 : Vector2,
p2 : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_spline_segment_linear(
p1.to_bytes(),
p2.to_bytes(),
thick,
color.to_bytes(),
)
}
///|
/// Draw spline segment: B-Spline, 4 points.
pub fn draw_spline_segment_basis(
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
p4 : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_spline_segment_basis(
p1.to_bytes(),
p2.to_bytes(),
p3.to_bytes(),
p4.to_bytes(),
thick,
color.to_bytes(),
)
}
///|
/// Draw spline segment: Catmull-Rom, 4 points.
pub fn draw_spline_segment_catmull_rom(
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
p4 : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_spline_segment_catmull_rom(
p1.to_bytes(),
p2.to_bytes(),
p3.to_bytes(),
p4.to_bytes(),
thick,
color.to_bytes(),
)
}
///|
/// Draw spline segment: Quadratic Bezier, 2 points, 1 control point.
pub fn draw_spline_segment_bezier_quadratic(
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_spline_segment_bezier_quadratic(
p1.to_bytes(),
p2.to_bytes(),
p3.to_bytes(),
thick,
color.to_bytes(),
)
}
///|
/// Draw spline segment: Cubic Bezier, 2 points, 2 control points.
pub fn draw_spline_segment_bezier_cubic(
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
p4 : Vector2,
thick : Float,
color : Color,
) -> Unit {
@ffi.draw_spline_segment_bezier_cubic(
p1.to_bytes(),
p2.to_bytes(),
p3.to_bytes(),
p4.to_bytes(),
thick,
color.to_bytes(),
)
}
// ============================================================================
// Spline point evaluation (pure MoonBit)
// ============================================================================
///|
/// Get (evaluate) spline point: Linear.
pub fn get_spline_point_linear(
start_pos : Vector2,
end_pos : Vector2,
t : Float,
) -> Vector2 {
let one_minus_t : Float = 1.0 - t
Vector2::new(
start_pos.x * one_minus_t + end_pos.x * t,
start_pos.y * one_minus_t + end_pos.y * t,
)
}
///|
/// Get (evaluate) spline point: B-Spline.
pub fn get_spline_point_basis(
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
p4 : Vector2,
t : Float,
) -> Vector2 {
let a0 : Float = (-p1.x + 3.0 * p2.x - 3.0 * p3.x + p4.x) / 6.0
let a1 : Float = (3.0 * p1.x - 6.0 * p2.x + 3.0 * p3.x) / 6.0
let a2 : Float = (-3.0 * p1.x + 3.0 * p3.x) / 6.0
let a3 : Float = (p1.x + 4.0 * p2.x + p3.x) / 6.0
let b0 : Float = (-p1.y + 3.0 * p2.y - 3.0 * p3.y + p4.y) / 6.0
let b1 : Float = (3.0 * p1.y - 6.0 * p2.y + 3.0 * p3.y) / 6.0
let b2 : Float = (-3.0 * p1.y + 3.0 * p3.y) / 6.0
let b3 : Float = (p1.y + 4.0 * p2.y + p3.y) / 6.0
Vector2::new(
a3 + t * (a2 + t * (a1 + t * a0)),
b3 + t * (b2 + t * (b1 + t * b0)),
)
}
///|
/// Get (evaluate) spline point: Catmull-Rom.
pub fn get_spline_point_catmull_rom(
p1 : Vector2,
p2 : Vector2,
p3 : Vector2,
p4 : Vector2,
t : Float,
) -> Vector2 {
let t2 = t * t
let t3 = t2 * t
let q0 : Float = -t3 + 2.0 * t2 - t
let q1 : Float = 3.0 * t3 - 5.0 * t2 + 2.0
let q2 : Float = -3.0 * t3 + 4.0 * t2 + t
let q3 = t3 - t2
Vector2::new(
(0.5 : Float) * (p1.x * q0 + p2.x * q1 + p3.x * q2 + p4.x * q3),
(0.5 : Float) * (p1.y * q0 + p2.y * q1 + p3.y * q2 + p4.y * q3),
)
}
///|
/// Get (evaluate) spline point: Quadratic Bezier.
pub fn get_spline_point_bezier_quad(
start_pos : Vector2,
control_pos : Vector2,
end_pos : Vector2,
t : Float,
) -> Vector2 {
let one_minus_t : Float = 1.0 - t
let a = one_minus_t * one_minus_t
let b : Float = 2.0 * one_minus_t * t
let c = t * t
Vector2::new(
a * start_pos.x + b * control_pos.x + c * end_pos.x,
a * start_pos.y + b * control_pos.y + c * end_pos.y,
)
}
///|
/// Get (evaluate) spline point: Cubic Bezier.
pub fn get_spline_point_bezier_cubic(
start_pos : Vector2,
start_control_pos : Vector2,
end_control_pos : Vector2,
end_pos : Vector2,
t : Float,
) -> Vector2 {
let one_minus_t : Float = 1.0 - t
let a = one_minus_t * one_minus_t * one_minus_t
let b : Float = 3.0 * one_minus_t * one_minus_t * t
let c : Float = 3.0 * one_minus_t * t * t
let d = t * t * t
Vector2::new(
a * start_pos.x +
b * start_control_pos.x +
c * end_control_pos.x +
d * end_pos.x,
a * start_pos.y +
b * start_control_pos.y +
c * end_control_pos.y +
d * end_pos.y,
)
}
// ============================================================================
// Additional 2D collision detection (pure MoonBit)
// ============================================================================
///|
/// Check if circle collides with a line created between two points.
pub fn check_collision_circle_line(
center : Vector2,
radius : Float,
p1 : Vector2,
p2 : Vector2,
) -> Bool {
let flt_epsilon : Float = 1.1920929e-7
let dx = p1.x - p2.x
let dy = p1.y - p2.y
if fabsf(dx) + fabsf(dy) <= flt_epsilon {
return check_collision_circles(p1, 0.0, center, radius)
}
let length_sq = dx * dx + dy * dy
let mut dot_product = (
(center.x - p1.x) * (p2.x - p1.x) + (center.y - p1.y) * (p2.y - p1.y)
) /
length_sq
if dot_product > 1.0 {
dot_product = 1.0
} else if dot_product < 0.0 {
dot_product = 0.0
}
let dx2 = p1.x - dot_product * dx - center.x
let dy2 = p1.y - dot_product * dy - center.y
let distance_sq = dx2 * dx2 + dy2 * dy2
distance_sq <= radius * radius
}
///|
/// Check if point belongs to line created between two points with defined margin in pixels.
pub fn check_collision_point_line(
point : Vector2,
p1 : Vector2,
p2 : Vector2,
threshold : Int,
) -> Bool {
let dxc = point.x - p1.x
let dyc = point.y - p1.y
let dxl = p2.x - p1.x
let dyl = p2.y - p1.y
let cross = dxc * dyl - dyc * dxl
if fabsf(cross) < Float::from_int(threshold) * fmaxf(fabsf(dxl), fabsf(dyl)) {
if fabsf(dxl) >= fabsf(dyl) {
if dxl > 0.0 {
p1.x <= point.x && point.x <= p2.x
} else {
p2.x <= point.x && point.x <= p1.x
}
} else if dyl > 0.0 {
p1.y <= point.y && point.y <= p2.y
} else {
p2.y <= point.y && point.y <= p1.y
}
} else {
false
}
}
// ============================================================================
// 3D triangle strip
// ============================================================================
///|
fn vector3_array_to_bytes(points : Array[Vector3]) -> Bytes {
let buf = @buffer.new(size_hint=points.length() * 12)
for p in points {
buf.write_float_le(p.x)
buf.write_float_le(p.y)
buf.write_float_le(p.z)
}
buf.to_bytes()
}
///|
/// Draw a triangle strip defined by points in 3D space.
pub fn draw_triangle_strip_3d(points : Array[Vector3], color : Color) -> Unit {
let bytes = vector3_array_to_bytes(points)
@ffi.draw_triangle_strip_3d(bytes, points.length(), color.to_bytes())
}
// ============================================================================
// Additional collision detection (pure MoonBit)
// ============================================================================
///|
/// Check if point is within a polygon described by array of vertices.
pub fn check_collision_point_poly(
point : Vector2,
points : Array[Vector2],
) -> Bool {
let point_count = points.length()
if point_count <= 2 {
return false
}
let mut inside = false
let mut j = point_count - 1
for i in 0.. point.y) != (points[j].y > point.y) &&
point.x <
(points[j].x - points[i].x) *
(point.y - points[i].y) /
(points[j].y - points[i].y) +
points[i].x {
inside = !inside
}
j = i
}
inside
}
///|
/// Check the collision between two lines defined by two points each, returns collision point.
pub fn check_collision_lines(
start_pos1 : Vector2,
end_pos1 : Vector2,
start_pos2 : Vector2,
end_pos2 : Vector2,
) -> Vector2? {
let flt_epsilon : Float = 1.1920929e-7
let div = (end_pos2.y - start_pos2.y) * (end_pos1.x - start_pos1.x) -
(end_pos2.x - start_pos2.x) * (end_pos1.y - start_pos1.y)
if fabsf(div) < flt_epsilon {
return None
}
let cross1 = start_pos1.x * end_pos1.y - start_pos1.y * end_pos1.x
let cross2 = start_pos2.x * end_pos2.y - start_pos2.y * end_pos2.x
let xi = (
(start_pos2.x - end_pos2.x) * cross1 -
(start_pos1.x - end_pos1.x) * cross2
) /
div
let yi = (
(start_pos2.y - end_pos2.y) * cross1 -
(start_pos1.y - end_pos1.y) * cross2
) /
div
if fabsf(start_pos1.x - end_pos1.x) > flt_epsilon &&
(
xi < fminf(start_pos1.x, end_pos1.x) ||
xi > fmaxf(start_pos1.x, end_pos1.x)
) {
return None
}
if fabsf(start_pos2.x - end_pos2.x) > flt_epsilon &&
(
xi < fminf(start_pos2.x, end_pos2.x) ||
xi > fmaxf(start_pos2.x, end_pos2.x)
) {
return None
}
if fabsf(start_pos1.y - end_pos1.y) > flt_epsilon &&
(
yi < fminf(start_pos1.y, end_pos1.y) ||
yi > fmaxf(start_pos1.y, end_pos1.y)
) {
return None
}
if fabsf(start_pos2.y - end_pos2.y) > flt_epsilon &&
(
yi < fminf(start_pos2.y, end_pos2.y) ||
yi > fmaxf(start_pos2.y, end_pos2.y)
) {
return None
}
Some({ x: xi, y: yi })
}