1use serde::{Deserialize, Serialize};
9use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
15pub struct Fp32(pub i32);
16
17impl Fp32 {
18 pub const SHIFT: usize = 16;
19 pub const ONE_RAW: i32 = 1 << Self::SHIFT;
20
21 pub const ZERO: Self = Self(0);
22 pub const ONE: Self = Self(Self::ONE_RAW);
23 pub const MINUS_ONE: Self = Self(-Self::ONE_RAW);
24 pub const MAX: Self = Self(i32::MAX);
25 pub const MIN: Self = Self(i32::MIN);
26
27 pub const PI: Self = Self(205887); pub const TWO_PI: Self = Self(411774); pub const HALF_PI: Self = Self(102943); #[inline]
33 pub const fn from_raw(raw: i32) -> Self {
34 Self(raw)
35 }
36
37 #[inline]
38 pub fn from_i32(val: i32) -> Self {
39 Self(val << Self::SHIFT)
40 }
41
42 #[inline]
43 pub fn from_f32(val: f32) -> Self {
44 Self((val * (Self::ONE_RAW as f32)) as i32)
45 }
46
47 #[inline]
48 pub fn to_f32(self) -> f32 {
49 self.0 as f32 / Self::ONE_RAW as f32
50 }
51
52 #[inline]
53 pub fn to_i32(self) -> i32 {
54 self.0 >> Self::SHIFT
55 }
56
57 #[inline]
58 pub fn abs(self) -> Self {
59 Self(self.0.abs())
60 }
61
62 pub fn sqrt(self) -> Self {
64 if self.0 <= 0 {
65 return Self::ZERO;
66 }
67 let mut bit = 1u32 << 30; let mut x = self.0 as u32;
69
70 while bit > x {
71 bit >>= 2;
72 }
73
74 let mut res = 0u32;
75 while bit != 0 {
76 if x >= res + bit {
77 x -= res + bit;
78 res = (res >> 1) + bit;
79 } else {
80 res >>= 1;
81 }
82 bit >>= 2;
83 }
84 Self((res << 8) as i32)
87 }
88
89 pub fn sin(self) -> Self {
91 let mut x = self % Self::TWO_PI;
95 if x < Self::ZERO {
96 x += Self::TWO_PI;
97 }
98 let sign = if x > Self::PI {
99 x -= Self::PI;
100 -1
101 } else {
102 1
103 };
104
105 let pi_minus_x = Self::PI - x;
106 let num = Self::from_i32(16) * x * pi_minus_x;
107 let den = Self::from_i32(5) * Self::PI * Self::PI - Self::from_i32(4) * x * pi_minus_x;
108
109 let res = num / den;
110 if sign < 0 {
111 -res
112 } else {
113 res
114 }
115 }
116
117 pub fn cos(self) -> Self {
118 (self + Self::HALF_PI).sin()
119 }
120}
121
122impl Add for Fp32 {
123 type Output = Self;
124 #[inline]
125 fn add(self, rhs: Self) -> Self {
126 Self(self.0 + rhs.0)
127 }
128}
129
130impl Sub for Fp32 {
131 type Output = Self;
132 #[inline]
133 fn sub(self, rhs: Self) -> Self {
134 Self(self.0 - rhs.0)
135 }
136}
137
138impl Mul for Fp32 {
139 type Output = Self;
140 #[inline]
141 fn mul(self, rhs: Self) -> Self {
142 let val = (self.0 as i64 * rhs.0 as i64) >> Fp32::SHIFT;
143 Self(val as i32)
144 }
145}
146
147impl Div for Fp32 {
148 type Output = Self;
149 #[inline]
150 fn div(self, rhs: Self) -> Self {
151 debug_assert!(rhs.0 != 0, "Fp32: division by zero");
152 let val = ((self.0 as i64) << Fp32::SHIFT) / (rhs.0 as i64);
153 Self(val as i32)
154 }
155}
156
157impl Neg for Fp32 {
158 type Output = Self;
159 #[inline]
160 fn neg(self) -> Self {
161 Self(-self.0)
162 }
163}
164
165impl std::ops::Rem for Fp32 {
166 type Output = Self;
167 #[inline]
168 fn rem(self, rhs: Self) -> Self {
169 Self(self.0 % rhs.0)
170 }
171}
172
173impl AddAssign for Fp32 {
174 #[inline]
175 fn add_assign(&mut self, rhs: Self) {
176 self.0 += rhs.0;
177 }
178}
179impl SubAssign for Fp32 {
180 #[inline]
181 fn sub_assign(&mut self, rhs: Self) {
182 self.0 -= rhs.0;
183 }
184}
185impl MulAssign for Fp32 {
186 #[inline]
187 fn mul_assign(&mut self, rhs: Self) {
188 *self = *self * rhs;
189 }
190}
191impl DivAssign for Fp32 {
192 #[inline]
193 fn div_assign(&mut self, rhs: Self) {
194 *self = *self / rhs;
195 }
196}
197
198#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
201pub struct FpVec3 {
202 pub x: Fp32,
203 pub y: Fp32,
204 pub z: Fp32,
205}
206
207impl FpVec3 {
208 pub const ZERO: Self = Self {
209 x: Fp32::ZERO,
210 y: Fp32::ZERO,
211 z: Fp32::ZERO,
212 };
213
214 #[inline]
215 pub fn new(x: Fp32, y: Fp32, z: Fp32) -> Self {
216 Self { x, y, z }
217 }
218
219 pub fn dot(self, rhs: Self) -> Fp32 {
220 self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
221 }
222
223 pub fn cross(self, rhs: Self) -> Self {
224 Self {
225 x: self.y * rhs.z - self.z * rhs.y,
226 y: self.z * rhs.x - self.x * rhs.z,
227 z: self.x * rhs.y - self.y * rhs.x,
228 }
229 }
230
231 pub fn length_squared(self) -> Fp32 {
232 self.dot(self)
233 }
234
235 pub fn length(self) -> Fp32 {
236 self.length_squared().sqrt()
237 }
238
239 pub fn normalize(self) -> Self {
240 let len = self.length();
241 if len.0 > 0 {
242 self / len
243 } else {
244 Self::ZERO
245 }
246 }
247}
248
249impl Add for FpVec3 {
250 type Output = Self;
251 fn add(self, rhs: Self) -> Self {
252 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
253 }
254}
255
256impl Sub for FpVec3 {
257 type Output = Self;
258 fn sub(self, rhs: Self) -> Self {
259 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
260 }
261}
262
263impl Mul<Fp32> for FpVec3 {
264 type Output = Self;
265 fn mul(self, rhs: Fp32) -> Self {
266 Self::new(self.x * rhs, self.y * rhs, self.z * rhs)
267 }
268}
269
270impl Div<Fp32> for FpVec3 {
271 type Output = Self;
272 fn div(self, rhs: Fp32) -> Self {
273 Self::new(self.x / rhs, self.y / rhs, self.z / rhs)
274 }
275}
276
277#[cfg(test)]
282mod tests {
283 use super::*;
284
285 const FP_EPS: f32 = 0.01; fn fp_approx(a: Fp32, expected: f32) -> bool {
290 (a.to_f32() - expected).abs() < FP_EPS
291 }
292
293 #[test]
298 fn fp32_from_i32_roundtrip() {
299 for val in [-100, -1, 0, 1, 42, 1000] {
300 let fp = Fp32::from_i32(val);
301 assert_eq!(fp.to_i32(), val, "from_i32({val}).to_i32() roundtrip failed");
302 }
303 }
304
305 #[test]
306 fn fp32_from_f32_roundtrip() {
307 for val in [0.0f32, 1.0, -1.0, 0.5, -0.25, 3.14, 100.75] {
308 let fp = Fp32::from_f32(val);
309 let back = fp.to_f32();
310 assert!(
311 (back - val).abs() < 0.001,
312 "from_f32({val}).to_f32() = {back}, expected ~{val}"
313 );
314 }
315 }
316
317 #[test]
318 fn fp32_from_raw() {
319 let fp = Fp32::from_raw(65536);
320 assert_eq!(fp, Fp32::ONE);
321 assert_eq!(fp.to_f32(), 1.0);
322 }
323
324 #[test]
329 fn fp32_constants_consistency() {
330 assert_eq!(Fp32::TWO_PI.0, Fp32::PI.0 * 2, "TWO_PI != 2 * PI");
332
333 assert_eq!(Fp32::HALF_PI.0, Fp32::PI.0 / 2, "HALF_PI != PI / 2");
335
336 assert_eq!(Fp32::ONE, Fp32::from_i32(1));
338
339 assert_eq!(Fp32::MINUS_ONE, -Fp32::ONE);
341
342 assert_eq!(Fp32::ZERO.0, 0);
344 }
345
346 #[test]
347 fn fp32_pi_accuracy() {
348 let pi_f32 = Fp32::PI.to_f32();
349 assert!(
350 (pi_f32 - std::f32::consts::PI).abs() < 0.0001,
351 "PI as f32 = {pi_f32}, expected ~3.14159"
352 );
353 }
354
355 #[test]
360 fn fp32_add() {
361 let a = Fp32::from_f32(1.5);
362 let b = Fp32::from_f32(2.25);
363 assert!(fp_approx(a + b, 3.75));
364 }
365
366 #[test]
367 fn fp32_sub() {
368 let a = Fp32::from_f32(5.0);
369 let b = Fp32::from_f32(3.5);
370 assert!(fp_approx(a - b, 1.5));
371 }
372
373 #[test]
374 fn fp32_mul() {
375 let a = Fp32::from_f32(3.0);
376 let b = Fp32::from_f32(4.0);
377 assert!(fp_approx(a * b, 12.0));
378
379 let c = Fp32::from_f32(2.5);
381 let d = Fp32::from_f32(1.5);
382 assert!(fp_approx(c * d, 3.75));
383 }
384
385 #[test]
386 fn fp32_div() {
387 let a = Fp32::from_f32(10.0);
388 let b = Fp32::from_f32(4.0);
389 assert!(fp_approx(a / b, 2.5));
390 }
391
392 #[test]
393 fn fp32_neg() {
394 let a = Fp32::from_f32(3.14);
395 assert!(fp_approx(-a, -3.14));
396 assert!(fp_approx(-(-a), 3.14));
397 }
398
399 #[test]
400 fn fp32_rem() {
401 let a = Fp32::from_f32(7.0);
402 let b = Fp32::from_f32(3.0);
403 assert!(fp_approx(a % b, 1.0));
404 }
405
406 #[test]
407 fn fp32_abs() {
408 assert!(fp_approx(Fp32::from_f32(-5.0).abs(), 5.0));
409 assert!(fp_approx(Fp32::from_f32(5.0).abs(), 5.0));
410 assert!(fp_approx(Fp32::ZERO.abs(), 0.0));
411 }
412
413 #[test]
418 fn fp32_add_assign() {
419 let mut a = Fp32::from_f32(1.0);
420 a += Fp32::from_f32(2.0);
421 assert!(fp_approx(a, 3.0));
422 }
423
424 #[test]
425 fn fp32_sub_assign() {
426 let mut a = Fp32::from_f32(5.0);
427 a -= Fp32::from_f32(3.0);
428 assert!(fp_approx(a, 2.0));
429 }
430
431 #[test]
432 fn fp32_mul_assign() {
433 let mut a = Fp32::from_f32(3.0);
434 a *= Fp32::from_f32(4.0);
435 assert!(fp_approx(a, 12.0));
436 }
437
438 #[test]
439 fn fp32_div_assign() {
440 let mut a = Fp32::from_f32(10.0);
441 a /= Fp32::from_f32(2.0);
442 assert!(fp_approx(a, 5.0));
443 }
444
445 #[test]
450 fn fp32_sqrt_perfect_squares() {
451 for val in [1.0f32, 4.0, 9.0, 16.0, 25.0, 100.0] {
452 let result = Fp32::from_f32(val).sqrt().to_f32();
453 let expected = val.sqrt();
454 assert!(
455 (result - expected).abs() < 0.05,
456 "sqrt({val}) = {result}, expected {expected}"
457 );
458 }
459 }
460
461 #[test]
462 fn fp32_sqrt_fractional() {
463 let result = Fp32::from_f32(2.0).sqrt().to_f32();
464 assert!(
465 (result - std::f32::consts::SQRT_2).abs() < 0.05,
466 "sqrt(2) = {result}, expected ~1.414"
467 );
468 }
469
470 #[test]
471 fn fp32_sqrt_zero() {
472 assert_eq!(Fp32::ZERO.sqrt(), Fp32::ZERO);
473 }
474
475 #[test]
476 fn fp32_sqrt_negative_returns_zero() {
477 assert_eq!(Fp32::from_f32(-4.0).sqrt(), Fp32::ZERO);
478 assert_eq!(Fp32::MINUS_ONE.sqrt(), Fp32::ZERO);
479 }
480
481 #[test]
486 fn fp32_sin_known_values() {
487 assert!(fp_approx(Fp32::ZERO.sin(), 0.0));
489
490 assert!(
492 Fp32::PI.sin().to_f32().abs() < 0.02,
493 "sin(PI) = {}, expected ~0",
494 Fp32::PI.sin().to_f32()
495 );
496
497 assert!(
499 fp_approx(Fp32::HALF_PI.sin(), 1.0),
500 "sin(PI/2) = {}, expected ~1.0",
501 Fp32::HALF_PI.sin().to_f32()
502 );
503
504 let three_half_pi = Fp32::PI + Fp32::HALF_PI;
506 assert!(
507 fp_approx(three_half_pi.sin(), -1.0),
508 "sin(3PI/2) = {}, expected ~-1.0",
509 three_half_pi.sin().to_f32()
510 );
511 }
512
513 #[test]
514 fn fp32_cos_known_values() {
515 assert!(
517 fp_approx(Fp32::ZERO.cos(), 1.0),
518 "cos(0) = {}, expected ~1.0",
519 Fp32::ZERO.cos().to_f32()
520 );
521
522 assert!(
524 fp_approx(Fp32::PI.cos(), -1.0),
525 "cos(PI) = {}, expected ~-1.0",
526 Fp32::PI.cos().to_f32()
527 );
528
529 assert!(
531 Fp32::HALF_PI.cos().to_f32().abs() < 0.02,
532 "cos(PI/2) = {}, expected ~0",
533 Fp32::HALF_PI.cos().to_f32()
534 );
535 }
536
537 #[test]
538 fn fp32_sin_negative_angle() {
539 let x = Fp32::from_f32(1.0);
541 let sin_x = x.sin().to_f32();
542 let sin_neg_x = (-x).sin().to_f32();
543 assert!(
544 (sin_x + sin_neg_x).abs() < 0.02,
545 "sin(x) + sin(-x) = {}, expected ~0",
546 sin_x + sin_neg_x
547 );
548 }
549
550 #[test]
551 fn fp32_sin_cos_pythagorean_identity() {
552 for angle_f32 in [0.5f32, 1.0, 1.5, 2.0, 2.5, 3.0, 4.5, 5.5] {
554 let x = Fp32::from_f32(angle_f32);
555 let s = x.sin().to_f32();
556 let c = x.cos().to_f32();
557 let identity = s * s + c * c;
558 assert!(
559 (identity - 1.0).abs() < 0.05,
560 "sin²({angle_f32}) + cos²({angle_f32}) = {identity}, expected ~1.0"
561 );
562 }
563 }
564
565 #[test]
566 fn fp32_sin_wrap_around() {
567 let x = Fp32::from_f32(1.23);
569 let s1 = x.sin().to_f32();
570 let s2 = (x + Fp32::TWO_PI).sin().to_f32();
571 assert!(
572 (s1 - s2).abs() < 0.02,
573 "sin(x) = {s1}, sin(x + 2PI) = {s2}, expected equal"
574 );
575 }
576
577 #[test]
582 fn fp32_ordering() {
583 assert!(Fp32::ZERO < Fp32::ONE);
584 assert!(Fp32::MINUS_ONE < Fp32::ZERO);
585 assert!(Fp32::ONE > Fp32::MINUS_ONE);
586 assert_eq!(Fp32::ONE, Fp32::ONE);
587 }
588
589 #[test]
594 fn fpvec3_add_sub() {
595 let a = FpVec3::new(Fp32::from_f32(1.0), Fp32::from_f32(2.0), Fp32::from_f32(3.0));
596 let b = FpVec3::new(Fp32::from_f32(4.0), Fp32::from_f32(5.0), Fp32::from_f32(6.0));
597
598 let sum = a + b;
599 assert!(fp_approx(sum.x, 5.0));
600 assert!(fp_approx(sum.y, 7.0));
601 assert!(fp_approx(sum.z, 9.0));
602
603 let diff = b - a;
604 assert!(fp_approx(diff.x, 3.0));
605 assert!(fp_approx(diff.y, 3.0));
606 assert!(fp_approx(diff.z, 3.0));
607 }
608
609 #[test]
610 fn fpvec3_scalar_mul_div() {
611 let v = FpVec3::new(Fp32::from_f32(2.0), Fp32::from_f32(4.0), Fp32::from_f32(6.0));
612 let scaled = v * Fp32::from_f32(0.5);
613 assert!(fp_approx(scaled.x, 1.0));
614 assert!(fp_approx(scaled.y, 2.0));
615 assert!(fp_approx(scaled.z, 3.0));
616
617 let divided = v / Fp32::from_f32(2.0);
618 assert!(fp_approx(divided.x, 1.0));
619 assert!(fp_approx(divided.y, 2.0));
620 assert!(fp_approx(divided.z, 3.0));
621 }
622
623 #[test]
628 fn fpvec3_dot() {
629 let a = FpVec3::new(Fp32::from_f32(1.0), Fp32::from_f32(2.0), Fp32::from_f32(3.0));
630 let b = FpVec3::new(Fp32::from_f32(4.0), Fp32::from_f32(5.0), Fp32::from_f32(6.0));
631 assert!(fp_approx(a.dot(b), 32.0));
633 }
634
635 #[test]
636 fn fpvec3_dot_perpendicular_is_zero() {
637 let x = FpVec3::new(Fp32::ONE, Fp32::ZERO, Fp32::ZERO);
638 let y = FpVec3::new(Fp32::ZERO, Fp32::ONE, Fp32::ZERO);
639 assert_eq!(x.dot(y), Fp32::ZERO);
640 }
641
642 #[test]
643 fn fpvec3_cross_basis_vectors() {
644 let x = FpVec3::new(Fp32::ONE, Fp32::ZERO, Fp32::ZERO);
645 let y = FpVec3::new(Fp32::ZERO, Fp32::ONE, Fp32::ZERO);
646 let z = FpVec3::new(Fp32::ZERO, Fp32::ZERO, Fp32::ONE);
647
648 let xy = x.cross(y);
650 assert_eq!(xy.x, Fp32::ZERO);
651 assert_eq!(xy.y, Fp32::ZERO);
652 assert_eq!(xy.z, Fp32::ONE);
653
654 let yz = y.cross(z);
656 assert_eq!(yz.x, Fp32::ONE);
657 assert_eq!(yz.y, Fp32::ZERO);
658 assert_eq!(yz.z, Fp32::ZERO);
659
660 let zx = z.cross(x);
662 assert_eq!(zx.x, Fp32::ZERO);
663 assert_eq!(zx.y, Fp32::ONE);
664 assert_eq!(zx.z, Fp32::ZERO);
665 }
666
667 #[test]
668 fn fpvec3_cross_anti_commutative() {
669 let a = FpVec3::new(Fp32::from_f32(1.0), Fp32::from_f32(2.0), Fp32::from_f32(3.0));
671 let b = FpVec3::new(Fp32::from_f32(4.0), Fp32::from_f32(5.0), Fp32::from_f32(6.0));
672 let ab = a.cross(b);
673 let ba = b.cross(a);
674 assert_eq!(ab.x, Fp32::from_raw(-ba.x.0));
675 assert_eq!(ab.y, Fp32::from_raw(-ba.y.0));
676 assert_eq!(ab.z, Fp32::from_raw(-ba.z.0));
677 }
678
679 #[test]
680 fn fpvec3_length_squared() {
681 let v = FpVec3::new(Fp32::from_f32(3.0), Fp32::from_f32(4.0), Fp32::ZERO);
683 assert!(fp_approx(v.length_squared(), 25.0));
684 }
685
686 #[test]
687 fn fpvec3_length() {
688 let v = FpVec3::new(Fp32::from_f32(3.0), Fp32::from_f32(4.0), Fp32::ZERO);
690 let len = v.length().to_f32();
691 assert!(
692 (len - 5.0).abs() < 0.1,
693 "length of (3,4,0) = {len}, expected ~5.0"
694 );
695 }
696
697 #[test]
698 fn fpvec3_normalize() {
699 let v = FpVec3::new(Fp32::from_f32(3.0), Fp32::from_f32(4.0), Fp32::ZERO);
700 let n = v.normalize();
701 let len = n.length().to_f32();
702 assert!(
703 (len - 1.0).abs() < 0.1,
704 "normalized length = {len}, expected ~1.0"
705 );
706 }
707
708 #[test]
709 fn fpvec3_normalize_zero_vector() {
710 let v = FpVec3::ZERO;
711 let n = v.normalize();
712 assert_eq!(n, FpVec3::ZERO, "normalizing zero vector should return zero");
713 }
714
715 #[test]
716 fn fpvec3_zero_constant() {
717 assert_eq!(FpVec3::ZERO.x, Fp32::ZERO);
718 assert_eq!(FpVec3::ZERO.y, Fp32::ZERO);
719 assert_eq!(FpVec3::ZERO.z, Fp32::ZERO);
720 }
721}