1use crate::types::I16F16;
19
20pub const FP_SHIFT: u32 = 16;
26
27pub const FP_ONE: i32 = 1_i32 << FP_SHIFT;
29
30pub const Q16_MAX: i32 = i32::MAX;
32
33pub const Q16_MIN: i32 = i32::MIN;
35
36pub type Q16 = i32;
40
41#[inline(always)]
47pub fn to_q16(v: f32) -> Q16 {
48 I16F16::saturating_from_num(v).to_bits()
49}
50
51#[inline(always)]
53pub fn from_q16(v: Q16) -> f32 {
54 I16F16::from_bits(v).to_num::<f32>()
55}
56
57#[inline(always)]
59pub fn from_i16_q16(v: i16) -> Q16 {
60 I16F16::from_num(v).to_bits()
61}
62
63#[inline(always)]
65pub fn to_i16_q16(v: Q16) -> i16 {
66 I16F16::from_bits(v).to_num::<i16>()
67}
68
69#[inline(always)]
71pub fn q31_to_q16(v: i32) -> Q16 {
72 I16F16::from_bits(v >> 15).to_bits()
73}
74
75#[inline(always)]
77pub fn q16_to_q31(v: Q16) -> i64 {
78 (I16F16::from_bits(v).to_bits() as i64) << 16
79}
80
81#[inline(always)]
87pub fn mul_q16(a: Q16, b: Q16) -> Q16 {
88 I16F16::from_bits(a).wrapping_mul(I16F16::from_bits(b)).to_bits()
89}
90
91#[inline(always)]
93pub fn mul_n_q16(a: Q16, n: i32) -> Q16 {
94 I16F16::from_bits(a).wrapping_mul_int(n).to_bits()
95}
96
97#[inline(always)]
99pub fn mul_f_q16(a: Q16, f: f32) -> Q16 {
100 mul_q16(a, to_q16(f))
101}
102
103#[inline(always)]
105pub fn div_q16(a: Q16, b: Q16) -> Q16 {
106 if b == 0 {
107 return 0;
108 }
109 I16F16::from_bits(a).wrapping_div(I16F16::from_bits(b)).to_bits()
110}
111
112#[inline(always)]
114pub fn div_n_q16(a: Q16, n: i32) -> Q16 {
115 if n == 0 {
116 return 0;
117 }
118 I16F16::from_bits(a).wrapping_div_int(n).to_bits()
119}
120
121#[inline(always)]
123pub fn div_f_q16(a: Q16, f: f32) -> Q16 {
124 div_q16(a, to_q16(f))
125}
126
127#[inline(always)]
133pub const fn qadd_q16(a: Q16, b: Q16) -> Q16 {
134 I16F16::from_bits(a).saturating_add(I16F16::from_bits(b)).to_bits()
135}
136
137#[inline(always)]
139pub const fn qsub_q16(a: Q16, b: Q16) -> Q16 {
140 I16F16::from_bits(a).saturating_sub(I16F16::from_bits(b)).to_bits()
141}
142
143#[inline(always)]
145pub fn abs_q16(a: Q16) -> Q16 {
146 I16F16::from_bits(a).abs().to_bits()
147}
148
149#[inline(always)]
158pub fn lerp_q16(a: Q16, b: Q16, t: i32, denom: i32) -> Q16 {
159 if denom == 0 {
160 return a;
161 }
162 let diff = b as i64 - a as i64;
163 (a as i64 + diff * t as i64 / denom as i64) as i32
164}
165
166#[inline(always)]
168pub fn angle_to_q16(degrees: f32) -> Q16 {
169 to_q16(degrees * core::f32::consts::PI / 180.0)
170}
171
172#[inline(always)]
177pub fn recip_q16(v: Q16) -> Q16 {
178 if v == 0 {
179 return Q16_MAX;
180 }
181 I16F16::from_bits(v).recip().to_bits()
182}
183
184#[derive(Debug, Clone, Copy)]
220pub struct ScanlineInterp {
221 z_cur: u32,
222 z_step: i32,
223 u_cur: u32,
224 u_step: i32,
225 v_cur: u32,
226 v_step: i32,
227}
228
229impl ScanlineInterp {
230 #[inline]
238 pub fn new(
239 z_left: u32,
240 z_right: u32,
241 u_left: u32,
242 u_right: u32,
243 v_left: u32,
244 v_right: u32,
245 span: i32,
246 ) -> Self {
247 let (z_step, u_step, v_step) = if span > 0 {
248 let z_step = ((z_right as i64 - z_left as i64) / span as i64) as i32;
249 let u_step = ((u_right as i64 - u_left as i64) / span as i64) as i32;
250 let v_step = ((v_right as i64 - v_left as i64) / span as i64) as i32;
251 (z_step, u_step, v_step)
252 } else {
253 (0, 0, 0)
254 };
255 Self {
256 z_cur: z_left,
257 z_step,
258 u_cur: u_left,
259 u_step,
260 v_cur: v_left,
261 v_step,
262 }
263 }
264
265 #[inline]
267 pub fn depth_only(z_left: u32, z_right: u32, span: i32) -> Self {
268 Self::new(z_left, z_right, 0, 0, 0, 0, span)
269 }
270
271 #[inline(always)]
273 pub fn z(&self) -> u32 {
274 self.z_cur
275 }
276
277 #[inline(always)]
279 pub fn u(&self) -> u32 {
280 self.u_cur
281 }
282
283 #[inline(always)]
285 pub fn v(&self) -> u32 {
286 self.v_cur
287 }
288
289 #[inline(always)]
291 pub fn step(&mut self) {
292 self.z_cur = self.z_cur.wrapping_add_signed(self.z_step);
293 self.u_cur = self.u_cur.wrapping_add_signed(self.u_step);
294 self.v_cur = self.v_cur.wrapping_add_signed(self.v_step);
295 }
296
297 #[inline]
299 pub fn step_n(&mut self, n: i32) {
300 self.z_cur = self.z_cur.wrapping_add_signed(self.z_step.wrapping_mul(n));
301 self.u_cur = self.u_cur.wrapping_add_signed(self.u_step.wrapping_mul(n));
302 self.v_cur = self.v_cur.wrapping_add_signed(self.v_step.wrapping_mul(n));
303 }
304
305 #[inline(always)]
307 pub fn z_f32(&self) -> f32 {
308 self.z_cur as f32 / 65536.0
309 }
310}
311
312#[cfg(test)]
317mod tests {
318 extern crate std;
319 use super::*;
320
321 #[test]
322 fn to_q16_tie_rounding() {
323 let v: f32 = 2.5 / 65536.0;
328 assert_eq!(to_q16(v), 2, "tie value rounds half-to-even under `fixed`");
329 }
330
331 #[test]
332 fn to_i16_q16_negative_fraction_floors() {
333 let q = to_q16(-3.5);
336 assert_eq!(to_i16_q16(q), -4, "negative fraction must floor, not truncate");
337 }
338
339 #[test]
340 fn div_q16_min_by_small_denominator_wraps() {
341 assert_eq!(div_q16(Q16_MIN, 1), 0, "overflow must wrap, not panic");
345 }
346
347 #[test]
348 fn roundtrip_f32_q16() {
349 let values = [0.0f32, 0.25, -0.5, 1.0, core::f32::consts::PI, -100.0, 32767.0];
350 for v in values {
351 let q = to_q16(v);
352 let back = from_q16(q);
353 let lsb = 1.0 / 65536.0_f32;
354 assert!(
355 (back - v).abs() <= lsb,
356 "roundtrip failed for {v}: got {back}"
357 );
358 }
359 }
360
361 #[test]
362 fn roundtrip_i16_q16() {
363 for v in [-32768i16, -1, 0, 1, 100, 32767] {
364 let q = from_i16_q16(v);
365 let back = to_i16_q16(q);
366 assert_eq!(back, v, "i16 roundtrip failed for {v}");
367 }
368 }
369
370 #[test]
371 fn q31_q16_shifts() {
372 let q31_one = 0x7FFF_FFFFi32;
373 let q16 = q31_to_q16(q31_one);
374 let f = from_q16(q16);
375 assert!(
376 (f - 1.0).abs() < 1e-4,
377 "Q31->Q16 should be near 1.0, got {f}"
378 );
379 }
380
381 #[test]
382 fn mul_q16_basic() {
383 let a = to_q16(1.5);
384 let b = to_q16(2.0);
385 let result = from_q16(mul_q16(a, b));
386 assert!((result - 3.0).abs() < 1e-4, "1.5 * 2.0 = {result}");
387 }
388
389 #[test]
390 fn mul_q16_negative() {
391 let a = to_q16(-2.5);
392 let b = to_q16(4.0);
393 let result = from_q16(mul_q16(a, b));
394 assert!((result - (-10.0)).abs() < 1e-4, "-2.5 * 4.0 = {result}");
395 }
396
397 #[test]
398 fn mul_n_q16_integer_scale() {
399 let a = to_q16(3.5);
400 let result = from_q16(mul_n_q16(a, 4));
401 assert!((result - 14.0).abs() < 1e-4, "3.5 * 4 = {result}");
402 }
403
404 #[test]
405 fn mul_f_q16_float_scale() {
406 let a = to_q16(2.0);
407 let result = from_q16(mul_f_q16(a, 1.5));
408 assert!((result - 3.0).abs() < 1e-3, "2.0 * 1.5f = {result}");
409 }
410
411 #[test]
412 fn div_q16_basic() {
413 let result = from_q16(div_q16(to_q16(3.0), to_q16(2.0)));
414 assert!((result - 1.5).abs() < 1e-4, "3.0 / 2.0 = {result}");
415 }
416
417 #[test]
418 fn div_q16_zero_denominator() {
419 let result = div_q16(to_q16(5.0), 0);
420 assert_eq!(result, 0, "division by zero must return 0");
421 }
422
423 #[test]
424 fn div_n_q16_integer_divisor() {
425 let result = from_q16(div_n_q16(to_q16(9.0), 3));
426 assert!((result - 3.0).abs() < 1e-4, "9.0 / 3 = {result}");
427 }
428
429 #[test]
430 fn div_f_q16_float_divisor() {
431 let result = from_q16(div_f_q16(to_q16(6.0), 2.0));
432 assert!((result - 3.0).abs() < 1e-3, "6.0 / 2.0f = {result}");
433 }
434
435 #[test]
436 fn qadd_q16_no_overflow() {
437 assert_eq!(
438 from_q16(qadd_q16(to_q16(1.0), to_q16(2.0))).round() as i32,
439 3
440 );
441 }
442
443 #[test]
444 fn qadd_q16_saturates_at_max() {
445 let result = qadd_q16(Q16_MAX, Q16_MAX);
446 assert_eq!(result, Q16_MAX, "overflow must saturate at Q16_MAX");
447 }
448
449 #[test]
450 fn qsub_q16_saturates_at_min() {
451 let result = qsub_q16(Q16_MIN, Q16_MAX);
452 assert_eq!(result, Q16_MIN, "underflow must saturate at Q16_MIN");
453 }
454
455 #[test]
456 fn abs_q16_positive_unchanged() {
457 let v = to_q16(5.75);
458 assert_eq!(abs_q16(v), v);
459 }
460
461 #[test]
462 fn abs_q16_negated() {
463 let v = to_q16(-core::f32::consts::PI);
464 let expected = to_q16(core::f32::consts::PI);
465 assert_eq!(abs_q16(v), expected);
466 }
467
468 #[test]
469 fn lerp_q16_midpoint() {
470 let a = to_q16(0.0);
471 let b = to_q16(1.0);
472 let mid = from_q16(lerp_q16(a, b, 1, 2));
473 assert!((mid - 0.5).abs() < 1e-4, "lerp mid = {mid}");
474 }
475
476 #[test]
477 fn lerp_q16_endpoints() {
478 let a = to_q16(10.0);
479 let b = to_q16(20.0);
480 assert_eq!(lerp_q16(a, b, 0, 10), a, "t=0 must return left endpoint");
481 assert_eq!(
482 lerp_q16(a, b, 10, 10),
483 b,
484 "t=denom must return right endpoint"
485 );
486 }
487
488 #[test]
489 fn lerp_q16_zero_denom_returns_left() {
490 let a = to_q16(5.0);
491 let b = to_q16(9.0);
492 assert_eq!(lerp_q16(a, b, 0, 0), a, "zero denom must return left");
493 }
494
495 #[test]
496 fn angle_to_q16_90_degrees() {
497 let q = angle_to_q16(90.0);
498 let rad = from_q16(q);
499 assert!(
500 (rad - core::f32::consts::FRAC_PI_2).abs() < 1e-4,
501 "90 deg should be pi/2, got {rad}"
502 );
503 }
504
505 #[test]
506 fn angle_to_q16_360_degrees() {
507 let q = angle_to_q16(360.0);
508 let rad = from_q16(q);
509 assert!(
510 (rad - 2.0 * core::f32::consts::PI).abs() < 1e-4,
511 "360 deg should be 2*pi, got {rad}"
512 );
513 }
514
515 #[test]
516 fn recip_q16_one() {
517 let result = from_q16(recip_q16(FP_ONE));
518 assert!(
519 (result - 1.0).abs() < 0.01,
520 "recip(1.0) approx 1.0, got {result}"
521 );
522 }
523
524 #[test]
525 fn recip_q16_two() {
526 let result = from_q16(recip_q16(to_q16(2.0)));
527 assert!(
528 (result - 0.5).abs() < 0.01,
529 "recip(2.0) approx 0.5, got {result}"
530 );
531 }
532
533 #[test]
534 fn recip_q16_zero_returns_sentinel() {
535 assert_eq!(
536 recip_q16(0),
537 Q16_MAX,
538 "recip(0) must return Q16_MAX sentinel"
539 );
540 }
541
542 #[test]
543 fn scanline_interp_starts_at_left() {
544 let interp = ScanlineInterp::new(100, 200, 0, 65536, 0, 32768, 10);
545 assert_eq!(interp.z(), 100);
546 assert_eq!(interp.u(), 0);
547 assert_eq!(interp.v(), 0);
548 }
549
550 #[test]
551 fn scanline_interp_step_reaches_right() {
552 let mut interp = ScanlineInterp::depth_only(0, 65536, 10);
553 for _ in 0..10 {
554 interp.step();
555 }
556 let diff = (interp.z() as i64 - 65536i64).abs();
557 assert!(
558 diff <= 10,
559 "z after 10 steps should be within 10 of 65536, got {} (diff={})",
560 interp.z(),
561 diff
562 );
563 }
564
565 #[test]
566 fn scanline_interp_uv_reaches_right() {
567 let mut interp = ScanlineInterp::new(0, 0, 0, 65536, 0, 65536, 8);
568 for _ in 0..8 {
569 interp.step();
570 }
571 let u_err = (interp.u() as i64 - 65536i64).abs();
572 let v_err = (interp.v() as i64 - 65536i64).abs();
573 assert!(
574 u_err <= 1,
575 "u after 8 steps should be 65536 +/- 1, got {}",
576 interp.u()
577 );
578 assert!(
579 v_err <= 1,
580 "v after 8 steps should be 65536 +/- 1, got {}",
581 interp.v()
582 );
583 }
584
585 #[test]
586 fn scanline_interp_zero_span() {
587 let mut interp = ScanlineInterp::new(1000, 9999, 0, 65536, 0, 65536, 0);
588 interp.step();
589 interp.step();
590 assert_eq!(interp.z(), 1000, "zero-span z must not move");
591 assert_eq!(interp.u(), 0, "zero-span u must not move");
592 }
593
594 #[test]
595 fn scanline_interp_step_n() {
596 let mut interp = ScanlineInterp::depth_only(0, 100000, 10);
597 interp.step_n(5);
598 let expected = 50000u32;
599 let diff = (interp.z() as i64 - expected as i64).abs();
600 assert!(
601 diff <= 1,
602 "step_n(5) should land at 50000 +/- 1, got {}",
603 interp.z()
604 );
605 }
606
607 #[test]
608 fn scanline_interp_z_f32() {
609 let interp = ScanlineInterp::depth_only(65536, 65536, 0);
610 assert!((interp.z_f32() - 1.0).abs() < 1e-5, "z_f32 should be 1.0");
611 }
612}