Skip to main content

murrelet_common/
lib.rs

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//
37// TIME UTILS
38//
39
40// just a wrapper..
41// since i can't use SystemTime in wasm.
42// this isn't as clever with duration vs systemtime, but it gets the job done..
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
44pub struct MurreletTime(u128); // millis
45
46impl 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    // f32 for historical reasons, can change at some point
72    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        //use wasm_bindgen::JsCast;
101
102        #[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
148//
149// RUN ID
150//
151
152pub fn run_id() -> u64 {
153    MurreletTime::now().as_secs()
154}
155
156// todo, this has something funny happening at the end where it jumps
157pub 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
187// excluding start/end
188pub 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
205// inclusive
206pub 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    // recenter to one/zero
225
226    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
258// creates the points from [0, 1)
259pub 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    // make the plan
268    let dist = (to - start).length();
269
270    // average the prev to start and start and to
271    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            // first move to center
435            SimpleTransform2dStep::translate(-self.center()),
436            // scale
437            SimpleTransform2dStep::scale_both(scale),
438            // then move to target
439            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) // just a convenience thing
497    }
498}
499
500// I use this to send data back to LiveCodeSrc's, e.g. make a MIDI controller
501// LED glow when it's used in the config.
502#[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    // this is a way to give usage feedback to the livecode src, e.g. tell a MIDI controller
523    // we're using a parameter, or what value to set indicator lights to.
524    fn feedback(
525        &mut self,
526        _variables: &HashMap<String, LivecodeUsage>,
527        _outgoing_msgs: &[(String, String, LivecodeValue)],
528    ) {
529        // default don't do anything
530    }
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        // basically update adds, and you can never delete >:D
559        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// what is sent from apps (like nannou)
568#[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
624// some special global things go in here
625// like app (javascript input or nannou), config, (and potentially time).
626// other Livecode sources will get their info
627// from threads
628pub 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        // todo, use debug
663        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}
705// from chatgpt
706impl 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    // ah, doesn't have to be that random
726    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        // Format the Identifier using its string representation
740        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        // hopefully will be unique enough..
876        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 = &sy[sy.len() - 8..];
885
886        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    // manhattan
910    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// hrmm, wrapper types for glam and evalexpr and such
922
923#[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// todo, did i end up using this?
1021#[derive(Clone, Copy, Debug)]
1022pub struct Dim2d {
1023    x: usize, // e.g. rows
1024    y: usize, // e.g. cols
1025}
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}