1use crate::{prelude::*, scalar};
2use skia_bindings::SkPoint3;
3use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
4
5pub type Vector3 = Point3;
6pub type Color3f = Point3;
7
8#[repr(C)]
9#[derive(Copy, Clone, PartialEq, Default, Debug)]
10pub struct Point3 {
11 pub x: scalar,
12 pub y: scalar,
13 pub z: scalar,
14}
15
16native_transmutable!(SkPoint3, Point3, point3_layout);
17
18impl From<(scalar, scalar, scalar)> for Point3 {
19 fn from((x: f32, y: f32, z: f32): (scalar, scalar, scalar)) -> Self {
20 Self::new(x, y, z)
21 }
22}
23
24impl Neg for Point3 {
25 type Output = Self;
26 fn neg(self) -> Self::Output {
27 Self::new(-self.x, -self.y, -self.z)
28 }
29}
30
31impl Add for Point3 {
32 type Output = Self;
33 fn add(self, rhs: Self) -> Self::Output {
34 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
35 }
36}
37
38impl AddAssign for Point3 {
39 fn add_assign(&mut self, rhs: Point3) {
40 *self = *self + rhs;
41 }
42}
43
44impl Sub for Point3 {
45 type Output = Self;
46 fn sub(self, rhs: Self) -> Self::Output {
47 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
48 }
49}
50
51impl SubAssign for Point3 {
52 fn sub_assign(&mut self, rhs: Point3) {
53 *self = *self - rhs;
54 }
55}
56
57impl Mul<Point3> for scalar {
58 type Output = Point3;
59
60 fn mul(self, p: Point3) -> Self::Output {
61 Point3::new(self * p.x, self * p.y, self * p.z)
62 }
63}
64
65impl Point3 {
66 pub const fn new(x: scalar, y: scalar, z: scalar) -> Self {
67 Self { x, y, z }
68 }
69
70 pub fn set(&mut self, x: scalar, y: scalar, z: scalar) {
71 *self = Self::new(x, y, z);
72 }
73
74 pub fn length_xyz(x: scalar, y: scalar, z: scalar) -> scalar {
75 unsafe { SkPoint3::Length(x, y, z) }
76 }
77
78 pub fn length(&self) -> scalar {
79 unsafe { SkPoint3::Length(self.x, self.y, self.z) }
80 }
81
82 pub fn normalize(&mut self) -> bool {
83 unsafe { self.native_mut().normalize() }
84 }
85
86 #[must_use]
87 pub fn normalized(&self) -> Option<Self> {
88 let mut normalized = *self;
89 unsafe { normalized.native_mut().normalize() }.if_true_some(normalized)
90 }
91
92 // TODO: with_scale()?
93 #[must_use]
94 pub fn scaled(&self, scale: scalar) -> Self {
95 Self::new(scale * self.x, scale * self.y, scale * self.z)
96 }
97
98 pub fn scale(&mut self, value: scalar) {
99 *self = self.scaled(value);
100 }
101
102 pub fn is_finite(&self) -> bool {
103 let mut accum = 0.0;
104 accum *= self.x;
105 accum *= self.y;
106 accum *= self.z;
107
108 // accum is either NaN or it is finite (zero).
109 debug_assert!(accum == 0.0 || accum.is_nan());
110
111 // value==value will be true iff value is not NaN
112 // TODO: is it faster to say !accum or accum==accum?
113 !accum.is_nan()
114 }
115
116 pub fn dot_product(a: Self, b: Self) -> scalar {
117 a.x * b.x + a.y * b.y + a.z * b.z
118 }
119
120 pub fn dot(&self, vec: Self) -> scalar {
121 Self::dot_product(*self, vec)
122 }
123
124 #[allow(clippy::many_single_char_names)]
125 pub fn cross_product(a: Self, b: Self) -> Self {
126 let x = a.y * b.z - a.z * b.y;
127 let y = a.z * b.x - a.x * b.z;
128 let z = a.x * b.y - a.y * b.x;
129 Self { x, y, z }
130 }
131
132 #[must_use]
133 pub fn cross(&self, vec: Self) -> Self {
134 Self::cross_product(*self, vec)
135 }
136}
137