1use super::{rect::Rectangle, vector2::Vector2};
2
3pub fn fract(x: f32) -> f32 {
15 x - x.floor()
16}
17
18pub fn noise(x: f32, y: f32) -> f32 {
41 fract(((x * 12.9898 + y * 78.233).sin()) * 43758.5453)
42}
43
44pub fn bresenham(a: Vector2, b: Vector2) -> Vec<Vector2> {
58 let (mut x0, mut y0) = (a[0] as i32, a[1] as i32);
59 let (x1, y1) = (b[0] as i32, b[1] as i32);
60 let mut pixels = Vec::new();
61
62 let dx = (x1 - x0).abs();
63 let sx = if x0 < x1 { 1 } else { -1 };
64 let dy = -(y1 - y0).abs();
65 let sy = if y0 < y1 { 1 } else { -1 };
66 let mut err = dx + dy;
67
68 loop {
69 pixels.push([x0 as f32, y0 as f32]);
70 if x0 == x1 && y0 == y1 {
71 break;
72 }
73 let e2 = 2 * err;
74 if e2 >= dy {
75 err += dy;
76 x0 += sx;
77 }
78 if e2 <= dx {
79 err += dx;
80 y0 += sy;
81 }
82 }
83
84 pixels
85}
86
87pub fn rectangle(rect: &Rectangle) -> Vec<Vector2> {
101 let start_x = rect.x.ceil() as i32;
102 let end_x = (rect.x + rect.width).floor() as i32;
103 let start_y = rect.y.ceil() as i32;
104 let end_y = (rect.y + rect.height).floor() as i32;
105 let mut points = Vec::new();
106 for y in start_y..=end_y {
107 for x in start_x..=end_x {
108 points.push([x as f32, y as f32]);
109 }
110 }
111 points
112}
113
114#[derive(Clone, Debug, PartialEq)]
116pub struct Bitmap {
117 pub width: usize,
118 pub height: usize,
119 pub data: Vec<u8>,
120}
121
122pub fn tile(source: &Bitmap, width: usize, height: usize) -> Bitmap {
124 let mut out = vec![0u8; width * height * 4];
125 for y in 0..height {
126 for x in 0..width {
127 let sx = x % source.width;
128 let sy = y % source.height;
129 let src = (sy * source.width + sx) * 4;
130 let dst = (y * width + x) * 4;
131 out[dst..dst + 4].copy_from_slice(&source.data[src..src + 4]);
132 }
133 }
134 Bitmap {
135 width,
136 height,
137 data: out,
138 }
139}
140
141pub fn scale(bitmap: &Bitmap, factor: Vector2) -> Bitmap {
143 let (factor_x, factor_y) = (factor[0], factor[1]);
144 assert!(factor_x > 0.0 && factor_y > 0.0, "factors must be positive");
145 let width = ((bitmap.width as f32 * factor_x).floor().max(1.0)) as usize;
146 let height = ((bitmap.height as f32 * factor_y).floor().max(1.0)) as usize;
147 let mut out = vec![0u8; width * height * 4];
148 for y in 0..height {
149 for x in 0..width {
150 let sx = ((x as f32) / factor_x).floor() as usize;
151 let sy = ((y as f32) / factor_y).floor() as usize;
152 let src = (sy * bitmap.width + sx) * 4;
153 let dst = (y * width + x) * 4;
154 out[dst..dst + 4].copy_from_slice(&bitmap.data[src..src + 4]);
155 }
156 }
157 Bitmap {
158 width,
159 height,
160 data: out,
161 }
162}
163
164pub fn resize(bitmap: &Bitmap, dst: Vector2) -> Bitmap {
166 let (w2, h2) = (dst[0] as f32, dst[1] as f32);
167 let fx = w2 / bitmap.width as f32;
168 let fy = h2 / bitmap.height as f32;
169 scale(bitmap, [fx, fy])
170}
171
172pub fn pad(bitmap: &Bitmap, dst: Vector2, bg: super::vector4::Vector4) -> Bitmap {
174 let width = dst[0] as usize;
175 let height = dst[1] as usize;
176 let mut out = vec![0u8; width * height * 4];
177 for i in 0..width * height {
178 let idx = i * 4;
179 out[idx] = bg[0] as u8;
180 out[idx + 1] = bg[1] as u8;
181 out[idx + 2] = bg[2] as u8;
182 out[idx + 3] = bg[3] as u8;
183 }
184 let offset_x = ((width as i32 - bitmap.width as i32) / 2) as isize;
185 let offset_y = ((height as i32 - bitmap.height as i32) / 2) as isize;
186 for y in 0..bitmap.height {
187 for x in 0..bitmap.width {
188 let dst_x = x as isize + offset_x;
189 let dst_y = y as isize + offset_y;
190 if dst_x < 0 || dst_y < 0 || dst_x >= width as isize || dst_y >= height as isize {
191 continue;
192 }
193 let src = (y * bitmap.width + x) * 4;
194 let dst = (dst_y as usize * width + dst_x as usize) * 4;
195 out[dst..dst + 4].copy_from_slice(&bitmap.data[src..src + 4]);
196 }
197 }
198 Bitmap {
199 width,
200 height,
201 data: out,
202 }
203}
204
205pub fn floodfill(bitmap: &mut Bitmap, pos: Vector2, fill: super::vector4::Vector4) {
207 let x = pos[0] as i32;
208 let y = pos[1] as i32;
209 if x < 0 || y < 0 || x >= bitmap.width as i32 || y >= bitmap.height as i32 {
210 return;
211 }
212 let idx = (y as usize * bitmap.width + x as usize) * 4;
213 let target = [
214 bitmap.data[idx],
215 bitmap.data[idx + 1],
216 bitmap.data[idx + 2],
217 bitmap.data[idx + 3],
218 ];
219 if target == [fill[0] as u8, fill[1] as u8, fill[2] as u8, fill[3] as u8] {
220 return;
221 }
222 let mut stack = vec![(x, y)];
223 while let Some((cx, cy)) = stack.pop() {
224 if cx < 0 || cy < 0 || cx >= bitmap.width as i32 || cy >= bitmap.height as i32 {
225 continue;
226 }
227 let i = (cy as usize * bitmap.width + cx as usize) * 4;
228 let cur = [
229 bitmap.data[i],
230 bitmap.data[i + 1],
231 bitmap.data[i + 2],
232 bitmap.data[i + 3],
233 ];
234 if cur != target {
235 continue;
236 }
237 bitmap.data[i..i + 4].copy_from_slice(&[
238 fill[0] as u8,
239 fill[1] as u8,
240 fill[2] as u8,
241 fill[3] as u8,
242 ]);
243 stack.push((cx - 1, cy));
244 stack.push((cx + 1, cy));
245 stack.push((cx, cy - 1));
246 stack.push((cx, cy + 1));
247 }
248}
249
250pub fn circle(center: Vector2, radius: f32, clip: Option<Rectangle>) -> Vec<Vector2> {
252 let (cx, cy) = (center[0], center[1]);
253 let r_sq = radius * radius;
254 let mut results = Vec::new();
255 let (min_x, min_y, max_x, max_y) = if let Some(c) = clip {
256 (c.x, c.y, c.x + c.width - 1.0, c.y + c.height - 1.0)
257 } else {
258 (
259 f32::NEG_INFINITY,
260 f32::NEG_INFINITY,
261 f32::INFINITY,
262 f32::INFINITY,
263 )
264 };
265 let y_start = (cy - radius).floor() as i32;
266 let y_end = (cy + radius).floor() as i32;
267 for y in y_start..=y_end {
268 let dy = y as f32 - cy;
269 let span = (r_sq - dy * dy).sqrt();
270 if span.is_nan() {
271 continue;
272 }
273 let left = (cx - span).floor() as i32;
274 let right = (cx + span).floor() as i32;
275 for x in left..=right {
276 let xf = x as f32;
277 let yf = y as f32;
278 if xf < min_x || xf > max_x || yf < min_y || yf > max_y {
279 continue;
280 }
281 results.push([xf, yf]);
282 }
283 }
284 results
285}
286
287pub fn ellipse(center: Vector2, radius: Vector2) -> Vec<Vector2> {
289 let (cx, cy) = (center[0], center[1]);
290 let (rx, ry) = (radius[0], radius[1]);
291 let mut pts = Vec::new();
292 let start_x = (cx - rx).ceil() as i32;
293 let end_x = (cx + rx).floor() as i32;
294 let start_y = (cy - ry).ceil() as i32;
295 let end_y = (cy + ry).floor() as i32;
296 for y in start_y..=end_y {
297 for x in start_x..=end_x {
298 let dx = x as f32 - cx;
299 let dy = y as f32 - cy;
300 if (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry) <= 1.0 {
301 pts.push([x as f32, y as f32]);
302 }
303 }
304 }
305 pts
306}
307
308pub fn gaussian(norm_dist: f32, hardness: f32) -> f32 {
310 let k_hard = 2.0_f32;
311 let k_soft = 10.0_f32;
312 let k = hardness * k_hard + (1.0 - hardness) * k_soft;
313 (-k * norm_dist * norm_dist).exp()
314}
315
316pub fn smoothstep(n: i32, mut x: f32) -> f32 {
318 use super::utils::clamp;
319 x = clamp(x, 0.0, 1.0);
320 let mut result = 0.0;
321 for i in 0..=n {
322 result += pascaltriangle(-(n as f32) - 1.0, i)
323 * pascaltriangle(2.0 * n as f32 + 1.0, n - i)
324 * x.powf(n as f32 + i as f32 + 1.0);
325 }
326 result
327}
328
329pub fn pascaltriangle(a: f32, b: i32) -> f32 {
331 let mut result = 1.0;
332 for i in 0..b {
333 result *= (a - i as f32) / (i as f32 + 1.0);
334 }
335 result
336}