use super::{rect::Rectangle, vector2::Vector2};
pub fn fract(x: f32) -> f32 {
x - x.floor()
}
pub fn noise(x: f32, y: f32) -> f32 {
fract(((x * 12.9898 + y * 78.233).sin()) * 43758.5453)
}
pub fn bresenham(a: Vector2, b: Vector2) -> Vec<Vector2> {
let (mut x0, mut y0) = (a[0] as i32, a[1] as i32);
let (x1, y1) = (b[0] as i32, b[1] as i32);
let mut pixels = Vec::new();
let dx = (x1 - x0).abs();
let sx = if x0 < x1 { 1 } else { -1 };
let dy = -(y1 - y0).abs();
let sy = if y0 < y1 { 1 } else { -1 };
let mut err = dx + dy;
loop {
pixels.push([x0 as f32, y0 as f32]);
if x0 == x1 && y0 == y1 {
break;
}
let e2 = 2 * err;
if e2 >= dy {
err += dy;
x0 += sx;
}
if e2 <= dx {
err += dx;
y0 += sy;
}
}
pixels
}
pub fn rectangle(rect: &Rectangle) -> Vec<Vector2> {
let start_x = rect.x.ceil() as i32;
let end_x = (rect.x + rect.width).floor() as i32;
let start_y = rect.y.ceil() as i32;
let end_y = (rect.y + rect.height).floor() as i32;
let mut points = Vec::new();
for y in start_y..=end_y {
for x in start_x..=end_x {
points.push([x as f32, y as f32]);
}
}
points
}
#[derive(Clone, Debug, PartialEq)]
pub struct Bitmap {
pub width: usize,
pub height: usize,
pub data: Vec<u8>,
}
pub fn tile(source: &Bitmap, width: usize, height: usize) -> Bitmap {
let mut out = vec![0u8; width * height * 4];
for y in 0..height {
for x in 0..width {
let sx = x % source.width;
let sy = y % source.height;
let src = (sy * source.width + sx) * 4;
let dst = (y * width + x) * 4;
out[dst..dst + 4].copy_from_slice(&source.data[src..src + 4]);
}
}
Bitmap {
width,
height,
data: out,
}
}
pub fn scale(bitmap: &Bitmap, factor: Vector2) -> Bitmap {
let (factor_x, factor_y) = (factor[0], factor[1]);
assert!(factor_x > 0.0 && factor_y > 0.0, "factors must be positive");
let width = ((bitmap.width as f32 * factor_x).floor().max(1.0)) as usize;
let height = ((bitmap.height as f32 * factor_y).floor().max(1.0)) as usize;
let mut out = vec![0u8; width * height * 4];
for y in 0..height {
for x in 0..width {
let sx = ((x as f32) / factor_x).floor() as usize;
let sy = ((y as f32) / factor_y).floor() as usize;
let src = (sy * bitmap.width + sx) * 4;
let dst = (y * width + x) * 4;
out[dst..dst + 4].copy_from_slice(&bitmap.data[src..src + 4]);
}
}
Bitmap {
width,
height,
data: out,
}
}
pub fn resize(bitmap: &Bitmap, dst: Vector2) -> Bitmap {
let (w2, h2) = (dst[0] as f32, dst[1] as f32);
let fx = w2 / bitmap.width as f32;
let fy = h2 / bitmap.height as f32;
scale(bitmap, [fx, fy])
}
pub fn pad(bitmap: &Bitmap, dst: Vector2, bg: super::vector4::Vector4) -> Bitmap {
let width = dst[0] as usize;
let height = dst[1] as usize;
let mut out = vec![0u8; width * height * 4];
for i in 0..width * height {
let idx = i * 4;
out[idx] = bg[0] as u8;
out[idx + 1] = bg[1] as u8;
out[idx + 2] = bg[2] as u8;
out[idx + 3] = bg[3] as u8;
}
let offset_x = ((width as i32 - bitmap.width as i32) / 2) as isize;
let offset_y = ((height as i32 - bitmap.height as i32) / 2) as isize;
for y in 0..bitmap.height {
for x in 0..bitmap.width {
let dst_x = x as isize + offset_x;
let dst_y = y as isize + offset_y;
if dst_x < 0 || dst_y < 0 || dst_x >= width as isize || dst_y >= height as isize {
continue;
}
let src = (y * bitmap.width + x) * 4;
let dst = (dst_y as usize * width + dst_x as usize) * 4;
out[dst..dst + 4].copy_from_slice(&bitmap.data[src..src + 4]);
}
}
Bitmap {
width,
height,
data: out,
}
}
pub fn floodfill(bitmap: &mut Bitmap, pos: Vector2, fill: super::vector4::Vector4) {
let x = pos[0] as i32;
let y = pos[1] as i32;
if x < 0 || y < 0 || x >= bitmap.width as i32 || y >= bitmap.height as i32 {
return;
}
let idx = (y as usize * bitmap.width + x as usize) * 4;
let target = [
bitmap.data[idx],
bitmap.data[idx + 1],
bitmap.data[idx + 2],
bitmap.data[idx + 3],
];
if target == [fill[0] as u8, fill[1] as u8, fill[2] as u8, fill[3] as u8] {
return;
}
let mut stack = vec![(x, y)];
while let Some((cx, cy)) = stack.pop() {
if cx < 0 || cy < 0 || cx >= bitmap.width as i32 || cy >= bitmap.height as i32 {
continue;
}
let i = (cy as usize * bitmap.width + cx as usize) * 4;
let cur = [
bitmap.data[i],
bitmap.data[i + 1],
bitmap.data[i + 2],
bitmap.data[i + 3],
];
if cur != target {
continue;
}
bitmap.data[i..i + 4].copy_from_slice(&[
fill[0] as u8,
fill[1] as u8,
fill[2] as u8,
fill[3] as u8,
]);
stack.push((cx - 1, cy));
stack.push((cx + 1, cy));
stack.push((cx, cy - 1));
stack.push((cx, cy + 1));
}
}
pub fn circle(center: Vector2, radius: f32, clip: Option<Rectangle>) -> Vec<Vector2> {
let (cx, cy) = (center[0], center[1]);
let r_sq = radius * radius;
let mut results = Vec::new();
let (min_x, min_y, max_x, max_y) = if let Some(c) = clip {
(c.x, c.y, c.x + c.width - 1.0, c.y + c.height - 1.0)
} else {
(
f32::NEG_INFINITY,
f32::NEG_INFINITY,
f32::INFINITY,
f32::INFINITY,
)
};
let y_start = (cy - radius).floor() as i32;
let y_end = (cy + radius).floor() as i32;
for y in y_start..=y_end {
let dy = y as f32 - cy;
let span = (r_sq - dy * dy).sqrt();
if span.is_nan() {
continue;
}
let left = (cx - span).floor() as i32;
let right = (cx + span).floor() as i32;
for x in left..=right {
let xf = x as f32;
let yf = y as f32;
if xf < min_x || xf > max_x || yf < min_y || yf > max_y {
continue;
}
results.push([xf, yf]);
}
}
results
}
pub fn ellipse(center: Vector2, radius: Vector2) -> Vec<Vector2> {
let (cx, cy) = (center[0], center[1]);
let (rx, ry) = (radius[0], radius[1]);
let mut pts = Vec::new();
let start_x = (cx - rx).ceil() as i32;
let end_x = (cx + rx).floor() as i32;
let start_y = (cy - ry).ceil() as i32;
let end_y = (cy + ry).floor() as i32;
for y in start_y..=end_y {
for x in start_x..=end_x {
let dx = x as f32 - cx;
let dy = y as f32 - cy;
if (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry) <= 1.0 {
pts.push([x as f32, y as f32]);
}
}
}
pts
}
pub fn gaussian(norm_dist: f32, hardness: f32) -> f32 {
let k_hard = 2.0_f32;
let k_soft = 10.0_f32;
let k = hardness * k_hard + (1.0 - hardness) * k_soft;
(-k * norm_dist * norm_dist).exp()
}
pub fn smoothstep(n: i32, mut x: f32) -> f32 {
use super::utils::clamp;
x = clamp(x, 0.0, 1.0);
let mut result = 0.0;
for i in 0..=n {
result += pascaltriangle(-(n as f32) - 1.0, i)
* pascaltriangle(2.0 * n as f32 + 1.0, n - i)
* x.powf(n as f32 + i as f32 + 1.0);
}
result
}
pub fn pascaltriangle(a: f32, b: i32) -> f32 {
let mut result = 1.0;
for i in 0..b {
result *= (a - i as f32) / (i as f32 + 1.0);
}
result
}