use crate::{DitherFloat, DitherFloatConversion, LinearRng};
#[cfg(not(feature = "nightly_f16"))]
use common_traits::{CastableFrom, Number};
#[cfg(feature = "nightly_f16")]
use common_traits_f16::{CastableFrom, Number};
use enum_dispatch::enum_dispatch;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Hash {
seed: u32,
}
impl Hash {
pub fn new(seed: u32) -> Self {
Self { seed }
}
}
impl LinearRng for Hash {
#[inline(always)]
fn compute(&self, index: u32) -> f32 {
let mut hash = index;
hash = hash.wrapping_mul(1664525).wrapping_add(self.seed);
hash = hash.wrapping_mul(1664525).wrapping_add(1013904223);
hash ^= hash >> 16;
hash = hash.wrapping_mul(0x85ebca6b);
hash ^= hash >> 13;
hash = hash.wrapping_mul(0xc2b2ae35);
hash ^= hash >> 16;
(hash as f32 / u32::MAX as f32) * 2.0 - 1.0
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct R2 {
seed: f32,
}
impl Eq for R2 {}
impl core::hash::Hash for R2 {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.seed.to_bits().hash(state);
}
}
impl R2 {
pub fn new(seed: u32) -> Self {
Self {
seed: seed as f32 * 0.618_034,
}
}
}
impl LinearRng for R2 {
#[inline(always)]
fn compute(&self, index: u32) -> f32 {
const ALPHA: f32 = 0.754_877_7;
let value = (self.seed + ALPHA * index as f32).fract();
value * 2.0 - 1.0
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct GoldenRatio {
seed: f32,
}
impl Eq for GoldenRatio {}
impl core::hash::Hash for GoldenRatio {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.seed.to_bits().hash(state);
}
}
impl GoldenRatio {
pub fn new(seed: u32) -> Self {
Self {
seed: seed as f32 * 0.381_966_02,
}
}
}
impl LinearRng for GoldenRatio {
#[inline(always)]
fn compute(&self, index: u32) -> f32 {
const INV_GOLDEN: f32 = 0.618_034;
let value = (self.seed + INV_GOLDEN * index as f32).fract();
value * 2.0 - 1.0
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[enum_dispatch(LinearRng)]
pub enum LinearDither {
Hash(Hash),
R2(R2),
GoldenRatio(GoldenRatio),
}