1#[allow(dead_code)]
2use glam::{Vec2, vec2};
3use glam::{Vec3, vec3};
4use itertools::Itertools;
5use lerpable::{IsLerpingMethod, Lerpable};
6use num_traits::NumCast;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::hash::DefaultHasher;
10use std::hash::{Hash, Hasher};
11
12pub mod intersection;
13
14mod assets;
15mod color;
16mod geometry;
17mod idx;
18mod iter;
19mod metric;
20mod polyline;
21mod transform;
22pub mod triangulate;
23
24pub use assets::*;
25pub use color::*;
26pub use geometry::*;
27pub use idx::*;
28pub use iter::*;
29pub use metric::*;
30pub use polyline::*;
31pub use transform::*;
32
33#[cfg(target_arch = "wasm32")]
34use wasm_bindgen::prelude::*;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
44pub struct MurreletTime(u128); impl MurreletTime {
47 pub fn now() -> Self {
48 MurreletTime(epoch_time_us())
49 }
50
51 pub fn epoch() -> Self {
52 Self(0)
53 }
54
55 pub fn from_epoch_time(t: u128) -> Self {
56 Self(t)
57 }
58
59 pub fn in_x_ms(x: u128) -> Self {
60 MurreletTime(epoch_time_ms() + x)
61 }
62
63 pub fn in_one_sec() -> Self {
64 MurreletTime::in_x_ms(1000)
65 }
66
67 pub fn as_secs(&self) -> u64 {
68 (self.as_millis_u128() / 1000) as u64
69 }
70
71 pub fn as_secs_f32(&self) -> f32 {
73 (self.as_millis()) / 1000.0
74 }
75
76 pub fn as_millis_u128(&self) -> u128 {
77 self.0 / 1000
78 }
79
80 pub fn as_millis(&self) -> f32 {
81 self.0 as f32 / 1000.0
82 }
83
84 pub fn as_micro(&self) -> u128 {
85 self.0
86 }
87}
88
89impl std::ops::Sub for MurreletTime {
90 type Output = Self;
91
92 fn sub(self, other: Self) -> Self {
93 Self(self.0 - other.0)
94 }
95}
96
97pub fn epoch_time_ms() -> u128 {
98 #[cfg(target_arch = "wasm32")]
99 {
100 #[wasm_bindgen]
103 extern "C" {
104 #[wasm_bindgen(js_namespace = Date)]
105 fn now() -> f64;
106 }
107
108 now() as u128
109 }
110
111 #[cfg(not(target_arch = "wasm32"))]
112 {
113 use std::time::SystemTime;
114 use std::time::UNIX_EPOCH;
115 let s = SystemTime::now()
116 .duration_since(UNIX_EPOCH)
117 .expect("wat")
118 .as_millis() as f64
119 / 1000.0;
120 (s * 1000.0) as u128
121 }
122}
123
124pub fn epoch_time_us() -> u128 {
125 #[cfg(target_arch = "wasm32")]
126 {
127 #[wasm_bindgen]
128 extern "C" {
129 #[wasm_bindgen(js_namespace = Date)]
130 fn now() -> f64;
131 }
132
133 (now() * 1000.0) as u128
134 }
135
136 #[cfg(not(target_arch = "wasm32"))]
137 {
138 use std::time::SystemTime;
139 use std::time::UNIX_EPOCH;
140
141 SystemTime::now()
142 .duration_since(UNIX_EPOCH)
143 .expect("wat")
144 .as_micros()
145 }
146}
147
148pub fn run_id() -> u64 {
153 MurreletTime::now().as_secs()
154}
155
156pub fn ease(src: f64, mult: f64, offset: f64) -> f64 {
158 let raw = ((src * mult + offset) % 2.0 - 1.0).abs();
159 raw * raw * (3.0 - 2.0 * raw)
160}
161
162pub fn smoothstep(t: f64, edge0: f64, edge1: f64) -> f64 {
163 let raw = clamp((t - edge0) / (edge1 - edge0), 0.0, 1.0);
164 raw * raw * (3.0 - 2.0 * raw)
165}
166
167pub fn lerp<T>(start: T, end: T, pct: f32) -> T
168where
169 T: std::ops::Mul<f32, Output = T> + std::ops::Add<Output = T>,
170 f32: std::ops::Mul<T, Output = T>,
171{
172 (1.0 - pct) * start + pct * end
173}
174
175pub fn lerp_vec<T>(start: &[T], end: &[T], pct: f32) -> Vec<T>
176where
177 T: std::ops::Mul<f32, Output = T> + std::ops::Add<Output = T> + Copy,
178 f32: std::ops::Mul<T, Output = T>,
179{
180 start
181 .iter()
182 .zip(end.iter())
183 .map(|(a, b)| lerp(*a, *b, pct))
184 .collect_vec()
185}
186
187pub fn lerp_x_points_between<T>(start: T, end: T, point_count: usize) -> Vec<T>
189where
190 T: std::ops::Mul<f32, Output = T> + std::ops::Add<Output = T> + Copy,
191 f32: std::ops::Mul<T, Output = T>,
192{
193 let mut result = Vec::with_capacity(point_count);
194 for i in 1..point_count {
195 let pct: f32 = i as f32 / (point_count - 1) as f32;
196 result.push(lerp(start, end, pct));
197 }
198 result
199}
200
201pub fn vec_lerp(a: &Vec2, b: &Vec2, pct: f32) -> Vec2 {
202 vec2(lerp(a.x, b.x, pct), lerp(a.y, b.y, pct))
203}
204
205pub fn clamp<T>(v: T, start: T, end: T) -> T
207where
208 T: PartialOrd,
209{
210 if v < start {
211 start
212 } else if v > end {
213 end
214 } else {
215 v
216 }
217}
218
219pub fn map_range<T, U>(v: T, in_min: T, in_max: T, out_min: U, out_max: U) -> U
220where
221 T: NumCast,
222 U: NumCast,
223{
224 let v_num: f64 = NumCast::from(v).expect("v didn't convert");
227 let in_min_num: f64 = NumCast::from(in_min).expect("in_min didn't convert");
228 let in_max_num: f64 = NumCast::from(in_max).expect("in_max didn't convert");
229 let out_min_num: f64 = NumCast::from(out_min).expect("out_min didn't convert");
230 let out_max_num: f64 = NumCast::from(out_max).expect("out_max didn't convert");
231
232 let pct = (v_num - in_min_num) / (in_max_num - in_min_num);
233 NumCast::from(out_min_num + pct * (out_max_num - out_min_num)).expect("map_range failed")
234}
235
236pub fn print_expect<T, E>(result: Result<T, E>, msg: &str) -> Option<T>
237where
238 E: std::fmt::Debug,
239{
240 match result {
241 Ok(val) => Some(val),
242 Err(e) => {
243 println!("{}: {:?}", msg, e);
244 None
245 }
246 }
247}
248
249pub fn cubic_bezier(start: Vec2, ctrl1: Vec2, ctrl2: Vec2, to: Vec2, t: f32) -> Vec2 {
250 let a = lerp(start, ctrl1, t);
251 let b = lerp(ctrl1, ctrl2, t);
252 let c = lerp(ctrl2, to, t);
253 let d = lerp(a, b, t);
254 let e = lerp(b, c, t);
255 lerp(d, e, t)
256}
257
258pub fn smooth_interpolate(
260 prev: Vec2,
261 start: Vec2,
262 to: Vec2,
263 next: Vec2,
264 length_perc: f32,
265 smooth_count: usize,
266) -> Vec<Vec2> {
267 let dist = (to - start).length();
269
270 let start_tangent = (0.5 * ((start - prev) + (to - start))).normalize();
272 let to_tangent = -(0.5 * ((next - to) + (to - start))).normalize();
273
274 let ctrl1 = start + length_perc * dist * start_tangent;
275 let ctrl2 = to + length_perc * dist * to_tangent;
276
277 let mut v = Vec::with_capacity(smooth_count);
278
279 for i in 0..smooth_count {
280 let t = i as f32 / smooth_count as f32;
281 let p = cubic_bezier(start, ctrl1, ctrl2, to, t);
282 v.push(p);
283 }
284 v
285}
286
287#[derive(Debug, Clone, Copy)]
288pub struct Rect {
289 xy: Vec2,
290 wh: Vec2,
291}
292impl Rect {
293 pub fn new(xy: Vec2, wh: Vec2) -> Self {
294 Self { xy, wh }
295 }
296
297 pub fn from_xy_wh(xy: Vec2, wh: Vec2) -> Self {
298 Self::new(xy, wh)
299 }
300
301 pub fn from_corners(corner1: Vec2, corner2: Vec2) -> Rect {
302 let xy = 0.5 * (corner1 + corner2);
303 let w = (corner1.x - corner2.x).abs();
304 let h = (corner1.y - corner2.y).abs();
305 Rect { xy, wh: vec2(w, h) }
306 }
307
308 pub fn contains(&self, v: Vec2) -> bool {
309 v.x >= self.xy.x - 0.5 * self.wh.x
310 && v.x <= self.xy.x + 0.5 * self.wh.x
311 && v.y >= self.xy.y - 0.5 * self.wh.y
312 && v.y <= self.xy.y + 0.5 * self.wh.y
313 }
314
315 pub fn new_centered_square(rad: f32) -> Self {
316 Rect {
317 xy: Vec2::ZERO,
318 wh: vec2(rad * 2.0, rad * 2.0),
319 }
320 }
321
322 pub fn to_vec2(&self) -> Vec<Vec2> {
323 vec![
324 self.bottom_left(),
325 self.top_left(),
326 self.top_right(),
327 self.bottom_right(),
328 ]
329 }
330
331 pub fn to_polyline(&self) -> Polyline {
332 Polyline::new(self.to_vec2())
333 }
334
335 pub fn bottom_left(&self) -> Vec2 {
336 vec2(self.left(), self.bottom())
337 }
338
339 pub fn bottom_right(&self) -> Vec2 {
340 vec2(self.right(), self.bottom())
341 }
342
343 pub fn top_left(&self) -> Vec2 {
344 vec2(self.left(), self.top())
345 }
346
347 pub fn top_right(&self) -> Vec2 {
348 vec2(self.right(), self.top())
349 }
350
351 pub fn bottom(&self) -> f32 {
352 self.xy.y - 0.5 * self.wh.y
353 }
354
355 pub fn top(&self) -> f32 {
356 self.xy.y + 0.5 * self.wh.y
357 }
358
359 pub fn left(&self) -> f32 {
360 self.xy.x - 0.5 * self.wh.x
361 }
362
363 pub fn right(&self) -> f32 {
364 self.xy.x + 0.5 * self.wh.x
365 }
366
367 pub fn w(&self) -> f32 {
368 self.wh.x
369 }
370
371 pub fn h(&self) -> f32 {
372 self.wh.y
373 }
374
375 pub fn wh(&self) -> Vec2 {
376 self.wh
377 }
378
379 pub fn pad(&self, amount: f32) -> Self {
380 Self {
381 xy: self.xy + 2.0 * Vec2::ONE * amount,
382 wh: self.wh,
383 }
384 }
385
386 pub fn shift_y(&self, amount: f32) -> Self {
387 Self {
388 xy: self.xy + vec2(0.0, 1.0) * amount,
389 wh: self.wh,
390 }
391 }
392
393 pub fn overlap(&self, other: Rect) -> Option<Rect> {
394 let has_overlap = self.right() > other.left()
395 && self.left() < other.right()
396 && self.top() > other.bottom()
397 && self.bottom() < other.top();
398
399 if has_overlap {
400 let new_left = self.left().min(other.left());
401 let new_right = self.right().min(other.right());
402 let new_top = self.top().min(other.top());
403 let new_bottom = self.bottom().min(other.bottom());
404
405 let new_wh = vec2(new_right - new_left, new_top - new_bottom);
406
407 let new_xy = vec2(new_left + new_wh.x * 0.5, new_bottom + new_wh.y * 0.5);
408
409 Some(Rect::new(new_xy, new_wh))
410 } else {
411 None
412 }
413 }
414
415 pub fn xy(&self) -> Vec2 {
416 self.xy
417 }
418
419 pub fn center(&self) -> Vec2 {
420 self.xy()
421 }
422
423 pub fn pos(&self, s: Vec2) -> Vec2 {
424 vec2(
425 (s.x - self.left()) / self.w(),
426 (s.y - self.bottom()) / self.h(),
427 )
428 }
429
430 pub fn transform_to_other_rect(&self, target_rect: Rect) -> SimpleTransform2d {
431 let scale = target_rect.w() / self.w();
432
433 SimpleTransform2d::new(vec![
434 SimpleTransform2dStep::translate(-self.center()),
436 SimpleTransform2dStep::scale_both(scale),
438 SimpleTransform2dStep::translate(target_rect.center()),
440 ])
441 }
442}
443
444#[derive(Debug, Clone, Copy)]
445pub struct Circle {
446 pub center: Vec2,
447 pub radius: f32,
448}
449impl Circle {
450 pub fn new(center: Vec2, radius: f32) -> Self {
451 Self { center, radius }
452 }
453
454 pub fn new_centered(radius: f32) -> Self {
455 Self {
456 center: Vec2::ZERO,
457 radius,
458 }
459 }
460
461 pub fn diameter(&self) -> f32 {
462 AnglePi::new(2.0).scale(self.radius).angle()
463 }
464
465 pub fn move_center<A: IsAngle>(&self, amount: Vec2, a_to_b_dir: &A) -> Self {
466 let a: Angle = a_to_b_dir.as_angle_pi().into();
467
468 Self {
469 center: a.to_mat3().transform_point2(self.center) + amount,
470 radius: self.radius,
471 }
472 }
473
474 pub fn set_center(&self, center: Vec2) -> Circle {
475 Circle {
476 center,
477 radius: self.radius,
478 }
479 }
480
481 pub fn move_center_mat4(&self, transform: glam::Mat4) -> Circle {
482 self.set_center(transform.transform_vec2(self.center))
483 }
484}
485
486#[derive(Clone, Copy, Debug)]
487pub enum LivecodeValue {
488 Float(f64),
489 Bool(bool),
490 Int(i64),
491}
492
493impl LivecodeValue {
494 #[inline]
495 pub fn float(f: f32) -> Self {
496 Self::Float(f as f64) }
498}
499
500#[derive(Debug, Clone)]
503pub struct LivecodeUsage {
504 pub name: String,
505 pub is_used: bool,
506 pub value: Option<f32>,
507}
508
509impl LivecodeUsage {
510 pub fn new(name: String, is_used: bool, value: Option<f32>) -> Self {
511 Self {
512 name,
513 is_used,
514 value,
515 }
516 }
517}
518
519pub trait IsLivecodeSrc {
520 fn update(&mut self, input: &LivecodeSrcUpdateInput);
521 fn to_exec_funcs(&self) -> Vec<(String, LivecodeValue)>;
522 fn feedback(
525 &mut self,
526 _variables: &HashMap<String, LivecodeUsage>,
527 _outgoing_msgs: &[(String, String, LivecodeValue)],
528 ) {
529 }
531}
532
533pub struct LivecodeSrc {
534 vs: Vec<Box<dyn IsLivecodeSrc>>,
535}
536
537#[derive(Default, Debug, Clone)]
538pub struct CustomVars(Option<HashMap<String, f32>>);
539
540impl CustomVars {
541 pub fn new(hash_map: HashMap<String, f32>) -> Self {
542 Self(Some(hash_map))
543 }
544
545 pub fn to_exec_funcs(&self) -> Vec<(String, LivecodeValue)> {
546 if let Some(hm) = &self.0 {
547 let mut v = vec![];
548 for (key, value) in hm.iter() {
549 v.push((key.clone(), LivecodeValue::float(*value)))
550 }
551 v
552 } else {
553 vec![]
554 }
555 }
556
557 pub fn update(&mut self, new: &Self) {
558 if let Some(o) = &new.0 {
560 self.0
561 .get_or_insert_with(Default::default)
562 .extend(o.iter().map(|(k, v)| (k.clone(), *v)));
563 }
564 }
565}
566
567#[derive(Default)]
569pub struct MurreletAppInput {
570 pub keys: Option<[bool; 26]>,
571 pub window_dims: Vec2,
572 pub mouse_position: Vec2,
573 pub mouse_left_is_down: bool,
574 pub elapsed_frames: u64,
575 pub custom_vars: CustomVars,
576}
577
578impl MurreletAppInput {
579 pub fn new(
580 keys: [bool; 26],
581 window_dims: Vec2,
582 mouse_position: Vec2,
583 mouse_left_is_down: bool,
584 elapsed_frames: u64,
585 ) -> Self {
586 Self {
587 keys: Some(keys),
588 window_dims,
589 mouse_position,
590 mouse_left_is_down,
591 elapsed_frames,
592 custom_vars: CustomVars::default(),
593 }
594 }
595
596 pub fn new_no_key(
597 window_dims: Vec2,
598 mouse_position: Vec2,
599 mouse_left_is_down: bool,
600 elapsed_frames: u64,
601 custom_vars: HashMap<String, f32>,
602 ) -> Self {
603 Self {
604 keys: None,
605 window_dims,
606 mouse_position,
607 mouse_left_is_down,
608 elapsed_frames,
609 custom_vars: CustomVars::new(custom_vars),
610 }
611 }
612
613 pub fn default_with_frames(elapsed_frames: u64) -> Self {
614 let mut d = Self::default();
615 d.elapsed_frames = elapsed_frames;
616 d
617 }
618
619 pub fn elapsed_frames(&self) -> u64 {
620 self.elapsed_frames
621 }
622}
623
624pub struct LivecodeSrcUpdateInput<'a> {
629 is_debug: bool,
630 app: &'a MurreletAppInput,
631 should_reset: bool,
632}
633
634impl<'a> LivecodeSrcUpdateInput<'a> {
635 pub fn new(is_debug: bool, app: &'a MurreletAppInput, should_reset: bool) -> Self {
636 Self {
637 is_debug,
638 app,
639 should_reset,
640 }
641 }
642
643 pub fn app(&self) -> &MurreletAppInput {
644 self.app
645 }
646
647 pub fn should_reset(&self) -> bool {
648 self.should_reset
649 }
650
651 pub fn is_debug(&self) -> bool {
652 self.is_debug
653 }
654}
655
656impl LivecodeSrc {
657 pub fn new(vs: Vec<Box<dyn IsLivecodeSrc>>) -> Self {
658 Self { vs }
659 }
660
661 pub fn update(&mut self, input: &LivecodeSrcUpdateInput) {
662 for v in self.vs.iter_mut() {
664 v.update(input)
665 }
666 }
667
668 pub fn to_world_vals(&self) -> Vec<(String, LivecodeValue)> {
669 self.vs.iter().flat_map(|v| v.to_exec_funcs()).collect_vec()
670 }
671
672 pub fn feedback(
673 &mut self,
674 variables: &HashMap<String, LivecodeUsage>,
675 outgoing_msgs: &[(String, String, LivecodeValue)],
676 ) {
677 for v in self.vs.iter_mut() {
678 v.feedback(variables, outgoing_msgs);
679 }
680 }
681}
682
683const MAX_STRID_LEN: usize = 16;
684
685#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
686pub struct StrId([u8; MAX_STRID_LEN]);
687impl Serialize for StrId {
688 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
689 where
690 S: serde::Serializer,
691 {
692 serializer.serialize_str(self.as_str())
693 }
694}
695
696impl<'de> Deserialize<'de> for StrId {
697 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
698 where
699 D: serde::Deserializer<'de>,
700 {
701 let s = String::deserialize(deserializer)?;
702 Ok(StrId::new(&s))
703 }
704}
705impl StrId {
707 pub fn new(s: &str) -> Self {
708 let mut bytes = [0u8; MAX_STRID_LEN];
709 let len = s.len().min(MAX_STRID_LEN);
710 bytes[..len].copy_from_slice(&s.as_bytes()[..len]);
711 StrId(bytes)
712 }
713
714 pub fn as_str(&self) -> &str {
715 let len = self.0.iter().position(|&x| x == 0).unwrap_or(MAX_STRID_LEN);
716 std::str::from_utf8(&self.0[..len]).unwrap()
717 }
718
719 pub fn to_seed(&self) -> u64 {
720 let mut hasher = DefaultHasher::new();
721 self.0.hash(&mut hasher);
722 hasher.finish()
723 }
724
725 pub fn to_rn(&self) -> f32 {
727 (self.to_seed() as f64 / u64::MAX as f64) as f32
728 }
729}
730
731impl std::fmt::Display for StrId {
732 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
733 write!(f, "{}", self.as_str())
734 }
735}
736
737impl std::fmt::Debug for StrId {
738 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
739 write!(f, "StrId({})", self.as_str())
741 }
742}
743
744pub fn fixed_pt_f32_to_str(x: f32) -> String {
745 FixedPointF32::new(x).to_str()
746}
747
748#[derive(Debug, Copy, Clone, Ord, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
749pub struct FixedPointF32 {
750 pub x: i64,
751}
752
753impl FixedPointF32 {
754 pub fn abs(&self) -> Self {
755 Self { x: self.x.abs() }
756 }
757
758 pub fn decode(s: &str) -> Self {
759 Self {
760 x: s.parse::<i64>().unwrap_or(0),
761 }
762 }
763
764 pub fn encode(&self) -> String {
765 self.x.to_string()
766 }
767}
768
769impl std::ops::Sub for FixedPointF32 {
770 type Output = Self;
771
772 fn sub(self, other: Self) -> Self {
773 Self {
774 x: self.x - other.x,
775 }
776 }
777}
778
779impl std::ops::Add for FixedPointF32 {
780 type Output = Self;
781
782 fn add(self, other: Self) -> Self {
783 Self {
784 x: self.x + other.x,
785 }
786 }
787}
788impl FixedPointF32 {
789 pub const MAX: Self = FixedPointF32 { x: i64::MAX };
790 pub const MIN: Self = FixedPointF32 { x: i64::MIN };
791
792 pub const GRANULARITY: f32 = 1e4f32;
793
794 fn f32_to_i64(f: f32) -> i64 {
795 (f * Self::GRANULARITY).round() as i64
796 }
797
798 fn i64_to_f32(f: i64) -> f32 {
799 f as f32 / Self::GRANULARITY
800 }
801
802 pub fn to_i64(&self) -> i64 {
803 self.x
804 }
805
806 pub fn round(&self, n: i64) -> Self {
807 let x = self.x / n;
808 Self { x }
809 }
810
811 pub fn new(x: f32) -> Self {
812 Self {
813 x: Self::f32_to_i64(x),
814 }
815 }
816
817 fn new_from_i64(x: i64) -> Self {
818 Self { x }
819 }
820
821 pub fn to_f32(&self) -> f32 {
822 Self::i64_to_f32(self.x)
823 }
824
825 pub fn to_str(&self) -> String {
826 self.x.to_string()
827 }
828
829 pub fn nudge(&self, x: i64) -> Self {
830 Self { x: self.x + x }
831 }
832}
833
834#[derive(Copy, Clone, Ord, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
835pub struct FixedPointVec2 {
836 pub x: FixedPointF32,
837 pub y: FixedPointF32,
838}
839
840impl std::fmt::Debug for FixedPointVec2 {
841 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
842 let vec2_representation = self.to_vec2();
843 write!(f, "FixedPointVec2({:?})", vec2_representation)
844 }
845}
846
847impl FixedPointVec2 {
848 pub fn round(&self, n: i64) -> FixedPointVec2 {
849 FixedPointVec2::new_from_fixed_point(self.x.round(n), self.y.round(n))
850 }
851
852 pub fn new_from_i64(x: i64, y: i64) -> FixedPointVec2 {
853 FixedPointVec2 {
854 x: FixedPointF32::new_from_i64(x),
855 y: FixedPointF32::new_from_i64(y),
856 }
857 }
858
859 pub fn new(x: f32, y: f32) -> FixedPointVec2 {
860 FixedPointVec2 {
861 x: FixedPointF32::new(x),
862 y: FixedPointF32::new(y),
863 }
864 }
865
866 pub fn from_vec2(v: Vec2) -> FixedPointVec2 {
867 FixedPointVec2::new(v.x, v.y)
868 }
869
870 pub fn to_vec2(&self) -> Vec2 {
871 vec2(self.x.to_f32(), self.y.to_f32())
872 }
873
874 pub fn id(&self) -> StrId {
875 let sx = self.x.to_i64().to_string();
877
878 let sx8 = if sx.len() > 7 {
879 &sx[sx.len() - 7..]
880 } else {
881 &sx
882 };
883 let sy = self.y.to_i64().to_string();
884 let sy8 = if sy.len() > 7 {
887 &sy[sy.len() - 7..]
888 } else {
889 &sy
890 };
891
892 let result = format!("{:0>8}{:0>8}", sx8, sy8);
893
894 StrId::new(&result)
895 }
896
897 fn new_from_fixed_point(x: FixedPointF32, y: FixedPointF32) -> FixedPointVec2 {
898 Self { x, y }
899 }
900
901 pub fn as_tuple(&self) -> (i64, i64) {
902 (self.x.to_i64(), self.y.to_i64())
903 }
904
905 pub fn nudge(&self, x: i64, y: i64) -> Self {
906 Self::new_from_fixed_point(self.x.nudge(x), self.y.nudge(y))
907 }
908
909 pub fn dist_man(&self, other: FixedPointVec2) -> i64 {
911 let dx = (self.x - other.x).abs();
912 let dy = (self.y - other.y).abs();
913 (dx + dy).to_i64()
914 }
915}
916
917pub fn approx_eq_eps(x: f32, y: f32, eps: f32) -> bool {
918 (x - y).abs() <= eps
919}
920
921#[macro_export]
924macro_rules! newtype_wrapper {
925 ($wrapper:ident, $wrapped:ty) => {
926 #[derive(Copy, Clone, Debug, Default)]
927 pub struct $wrapper(pub $wrapped);
928
929 impl std::ops::Deref for $wrapper {
930 type Target = $wrapped;
931 fn deref(&self) -> &Self::Target {
932 &self.0
933 }
934 }
935
936 impl std::ops::DerefMut for $wrapper {
937 fn deref_mut(&mut self) -> &mut Self::Target {
938 &mut self.0
939 }
940 }
941
942 impl From<$wrapped> for $wrapper {
943 fn from(value: $wrapped) -> Self {
944 $wrapper(value)
945 }
946 }
947
948 impl From<$wrapper> for $wrapped {
949 fn from(wrapper: $wrapper) -> Self {
950 wrapper.0
951 }
952 }
953 };
954}
955
956newtype_wrapper!(MVec2, Vec2);
957newtype_wrapper!(MVec3, Vec3);
958
959impl Lerpable for MVec2 {
960 fn lerpify<T: IsLerpingMethod>(&self, other: &Self, method: &T) -> Self {
961 vec2(
962 self.x.lerpify(&other.x, method),
963 self.y.lerpify(&other.y, method),
964 )
965 .into()
966 }
967}
968
969pub fn lerpify_vec2<T: lerpable::IsLerpingMethod>(this: &Vec2, other: &Vec2, pct: &T) -> Vec2 {
970 let this: MVec2 = (*this).into();
971 let other: MVec2 = (*other).into();
972
973 this.lerpify(&other, pct).into()
974}
975
976pub fn lerpify_vec_vec2<T: lerpable::IsLerpingMethod>(
977 this: &[Vec2],
978 other: &[Vec2],
979 pct: &T,
980) -> Vec<Vec2> {
981 let this_vec: Vec<MVec2> = this.iter().map(|x| (*x).into()).collect_vec();
982 let other_vec: Vec<MVec2> = other.iter().map(|x| (*x).into()).collect_vec();
983
984 let lerped = this_vec.lerpify(&other_vec, pct);
985
986 lerped.into_iter().map(|v| v.into()).collect_vec()
987}
988
989impl Lerpable for MVec3 {
990 fn lerpify<T: IsLerpingMethod>(&self, other: &Self, method: &T) -> Self {
991 vec3(
992 self.x.lerpify(&other.x, method),
993 self.y.lerpify(&other.y, method),
994 self.z.lerpify(&other.z, method),
995 )
996 .into()
997 }
998}
999
1000pub fn lerpify_vec3<T: lerpable::IsLerpingMethod>(this: &Vec3, other: &Vec3, pct: &T) -> Vec3 {
1001 let this: MVec3 = (*this).into();
1002 let other: MVec3 = (*other).into();
1003
1004 this.lerpify(&other, pct).into()
1005}
1006
1007pub fn lerpify_vec_vec3<T: lerpable::IsLerpingMethod>(
1008 this: &[Vec3],
1009 other: &[Vec3],
1010 pct: &T,
1011) -> Vec<Vec3> {
1012 let this_vec: Vec<MVec3> = this.iter().map(|x| (*x).into()).collect_vec();
1013 let other_vec: Vec<MVec3> = other.iter().map(|x| (*x).into()).collect_vec();
1014
1015 let lerped = this_vec.lerpify(&other_vec, pct);
1016
1017 lerped.into_iter().map(|v| v.into()).collect_vec()
1018}
1019
1020#[derive(Clone, Copy, Debug)]
1022pub struct Dim2d {
1023 x: usize, y: usize, }
1026
1027impl Dim2d {
1028 pub fn new(x: usize, y: usize) -> Self {
1029 Self { x, y }
1030 }
1031
1032 pub fn x(&self) -> usize {
1033 self.x
1034 }
1035
1036 pub fn y(&self) -> usize {
1037 self.y
1038 }
1039
1040 pub fn row(&self) -> usize {
1041 self.y
1042 }
1043
1044 pub fn col(&self) -> usize {
1045 self.x
1046 }
1047
1048 pub fn i(&self) -> usize {
1049 self.y
1050 }
1051
1052 pub fn j(&self) -> usize {
1053 self.x
1054 }
1055
1056 pub fn i_plus_1(&self) -> Self {
1057 let i = self.i();
1058 let j = self.j();
1059 Self::from_i_j(i + 1, j)
1060 }
1061
1062 pub fn j_plus_1(&self) -> Self {
1063 let i = self.i();
1064 let j = self.j();
1065 Self::from_i_j(i, j + 1)
1066 }
1067
1068 pub fn from_x_y<T: TryInto<u64>>(x: T, y: T) -> Self
1069 where
1070 T::Error: std::fmt::Debug,
1071 {
1072 Self {
1073 x: x.try_into().expect("Conversion failed") as usize,
1074 y: y.try_into().expect("Conversion failed") as usize,
1075 }
1076 }
1077
1078 pub fn from_row_col<T: TryInto<u64>>(row: T, col: T) -> Self
1079 where
1080 T::Error: std::fmt::Debug,
1081 {
1082 Self::from_x_y(col, row)
1083 }
1084
1085 pub fn from_i_j<T: TryInto<u64>>(i: T, j: T) -> Self
1086 where
1087 T::Error: std::fmt::Debug,
1088 {
1089 Self::from_x_y(j, i)
1090 }
1091}
1092
1093pub fn rgb_to_hex(r: f32, g: f32, b: f32) -> String {
1094 let r = clamp(r, 0.0, 1.0);
1095 let g = clamp(g, 0.0, 1.0);
1096 let b = clamp(b, 0.0, 1.0);
1097
1098 let r = (r * 255.0) as u8;
1099 let g = (g * 255.0) as u8;
1100 let b = (b * 255.0) as u8;
1101
1102 format!("#{:02X}{:02X}{:02X}", r, g, b)
1103}
1104
1105pub trait MurreletIterHelpers {
1106 type T: Clone;
1107 fn to_iter<'a>(&'a self) -> std::slice::Iter<'a, Self::T>;
1108 fn as_vec_ref(&self) -> &Vec<Self::T>;
1109
1110 fn map_iter_collect<F, U>(&self, f: F) -> Vec<U>
1111 where
1112 F: Fn(&Self::T) -> U,
1113 {
1114 self.to_iter().map(f).collect_vec()
1115 }
1116
1117 fn owned_iter(&self) -> std::vec::IntoIter<Self::T> {
1118 self.to_iter().cloned().collect_vec().into_iter()
1119 }
1120
1121 fn take_count(&self, amount: usize) -> Vec<Self::T> {
1122 self.owned_iter().take(amount).collect::<Vec<Self::T>>()
1123 }
1124
1125 fn prev_curr_next_loop_iter<'a>(
1126 &'a self,
1127 ) -> Box<dyn Iterator<Item = (&'a Self::T, &'a Self::T, &'a Self::T)> + 'a> {
1128 prev_curr_next_loop_iter(self.as_vec_ref())
1129 }
1130
1131 fn prev_curr_next_no_loop_iter<'a>(
1132 &'a self,
1133 ) -> Box<dyn Iterator<Item = (&'a Self::T, &'a Self::T, &'a Self::T)> + 'a> {
1134 prev_curr_next_no_loop_iter(self.as_vec_ref())
1135 }
1136
1137 fn curr_next_loop_iter<'a>(
1138 &'a self,
1139 ) -> Box<dyn Iterator<Item = (&'a Self::T, &'a Self::T)> + 'a> {
1140 curr_next_loop_iter(self.as_vec_ref())
1141 }
1142
1143 fn curr_next_no_loop_iter<'a>(
1144 &'a self,
1145 ) -> Box<dyn Iterator<Item = (&'a Self::T, &'a Self::T)> + 'a> {
1146 curr_next_no_loop_iter(self.as_vec_ref())
1147 }
1148}
1149
1150impl<T: Clone> MurreletIterHelpers for Vec<T> {
1151 type T = T;
1152 fn to_iter<'a>(&'a self) -> std::slice::Iter<'a, T> {
1153 self.iter()
1154 }
1155
1156 fn as_vec_ref(&self) -> &Vec<Self::T> {
1157 self
1158 }
1159}