pbrt_r3/core/base/
functions.rs1use crate::core::base::Float;
2
3pub const MACHINE_EPSILON: Float = Float::EPSILON * 0.5;
4
5#[inline]
6pub fn gamma(n: Float) -> Float {
7 let e = n * MACHINE_EPSILON;
9 return e / (1.0 - e);
10}
11
12#[inline]
13pub fn gamma_correct(value: Float) -> Float {
14 if value <= 0.0031308 {
15 return 12.92 * value;
16 } else {
17 return 1.055 * Float::powf(value, 1.0 / 2.4) - 0.055;
18 }
19}
20
21#[inline]
22pub fn inverse_gamma_correct(value: Float) -> Float {
23 if value <= 0.04045 {
24 return value * 1.0 / 12.92;
25 } else {
26 return Float::powf((value + 0.055) * 1.0 / 1.055, 2.4);
27 }
28}
29
30#[inline]
31pub fn lerp(t: Float, v1: Float, v2: Float) -> Float {
32 return (1.0 - t) * v1 + t * v2;
33}
34
35#[inline]
36pub fn quadratic(a: Float, b: Float, c: Float) -> Option<(Float, Float)> {
37 let a = a as f64;
38 let b = b as f64;
39 let c = c as f64;
40 let discrim: f64 = b * b - 4.0 * a * c;
42 if discrim < 0.0 {
43 return None;
44 }
45 let root_discrim = f64::sqrt(discrim);
46 let q = if b < 0.0 {
48 -0.5 * (b - root_discrim)
49 } else {
50 -0.5 * (b + root_discrim)
51 };
52 let t0 = q / a;
53 let t1 = c / q;
54 if t0 > t1 {
55 std::mem::swap(&mut &t0, &mut &t1);
56 }
57
58 let t0 = t0 as Float;
59 let t1 = t1 as Float;
60 return Some((t0, t1));
61}
62
63#[inline]
64pub fn is_power_of_2(v: u32) -> bool {
65 return (v != 0) && ((v & (v - 1)) == 0);
66}
67
68#[inline]
69pub fn round_up_pow2(v: u32) -> u32 {
70 let mut v = v;
71 v -= 1;
72 v |= v >> 1;
73 v |= v >> 2;
74 v |= v >> 4;
75 v |= v >> 8;
76 v |= v >> 16;
77 return v + 1;
78}
79
80#[inline]
81pub fn is_power_of_2_64(v: u64) -> bool {
82 return (v != 0) && ((v & (v - 1)) == 0);
83}
84
85#[inline]
86pub fn round_up_pow2_64(v: u64) -> u64 {
87 let mut v = v;
88 v -= 1;
89 v |= v >> 1;
90 v |= v >> 2;
91 v |= v >> 4;
92 v |= v >> 8;
93 v |= v >> 16;
94 v |= v >> 32;
95 return v + 1;
96}
97
98#[inline]
99pub fn count_trailing_zeros(v: u32) -> u32 {
100 return v.trailing_zeros();
101}
102
103#[inline]
105pub fn find_interval(v: &[Float], pred: &dyn Fn(&[Float], usize) -> bool) -> usize {
106 let mut first = 0;
107 let mut len = v.len() as i64;
108 while len > 0 {
109 let half = len.wrapping_shr(1);
110 let middle = first + half;
111 if pred(v, middle as usize) {
113 first = middle + 1;
114 len -= half + 1;
115 } else {
116 len = half;
117 }
118 }
119 return i64::clamp(first - 1, 0, v.len() as i64 - 2) as usize;
120}
121
122#[inline]
123pub fn find_interval_range(
124 range: (usize, usize),
125 v: &[Float],
126 pred: &dyn Fn(&[Float], usize) -> bool,
127) -> usize {
128 let mut first = range.0;
129 let mut len = range.1;
130 while len > 0 {
131 let half = len.wrapping_shr(1);
132 let middle = first + half;
133 if pred(v, middle) {
135 first = middle + 1;
136 len -= half + 1;
137 } else {
138 len = half;
139 }
140 }
141 return usize::clamp(first - 1, 0, range.1 - 2);
142}
143
144#[inline]
145pub fn log2int(v: u32) -> u32 {
146 return 31 - v.leading_zeros();
147}
148
149#[inline]
150pub fn log2_int_64(v: u64) -> u32 {
151 return 63 - v.leading_zeros();
152}
153
154#[inline]
155pub fn erf_inv(x: Float) -> Float {
156 let x = Float::clamp(x, -0.99999, 0.99999);
157 let mut w = -Float::ln((1.0 - x) * (1.0 + x));
158 let mut p;
159 if w < 5.0 {
160 w -= 2.5;
161 p = 2.81022636e-08;
162 p = 3.43273939e-07 + p * w;
163 p = -3.5233877e-06 + p * w;
164 p = -4.39150654e-06 + p * w;
165 p = 0.00021858087 + p * w;
166 p = -0.00125372503 + p * w;
167 p = -0.00417768164 + p * w;
168 p = 0.246640727 + p * w;
169 p = 1.50140941 + p * w;
170 } else {
171 w = Float::sqrt(w) - 3.0;
172 p = -0.000200214257;
173 p = 0.000100950558 + p * w;
174 p = 0.00134934322 + p * w;
175 p = -0.00367342844 + p * w;
176 p = 0.00573950773 + p * w;
177 p = -0.0076224613 + p * w;
178 p = 0.00943887047 + p * w;
179 p = 1.00167406 + p * w;
180 p = 2.83297682 + p * w;
181 }
182 return p * x;
183}
184
185#[inline]
186pub fn erf(x: Float) -> Float {
187 const A1: Float = 0.254829592;
189 const A2: Float = -0.284496736;
190 const A3: Float = 1.421413741;
191 const A4: Float = -1.453152027;
192 const A5: Float = 1.061405429;
193 const P: Float = 0.3275911;
194
195 let sign = if x >= 0.0 { 1.0 } else { -1.0 };
197 let x = Float::abs(x);
198
199 let t = 1.0 / (1.0 + P * x);
201 let y = 1.0 - (((((A5 * t + A4) * t) + A3) * t + A2) * t + A1) * t * Float::exp(-x * x);
202
203 return sign * y;
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209
210 #[test]
211 pub fn test_001() {
212 let r1 = round_up_pow2(1);
213 let r2 = round_up_pow2(2);
214 let r3 = round_up_pow2(3);
215 let r4 = round_up_pow2(4);
216 let r5 = round_up_pow2(5);
217 assert_eq!(r1, 1);
218 assert_eq!(r2, 2);
219 assert_eq!(r3, 4);
220 assert_eq!(r4, 4);
221 assert_eq!(r5, 8);
222 }
223
224 #[test]
225 pub fn test_002() {
226 let r2 = log2int(2);
227 let r3 = log2int(3);
228 let r4 = log2int(4);
229 assert_eq!(r2, 1);
230 assert_eq!(r3, 1);
231 assert_eq!(r4, 2);
232 }
233}