crystal_ball 0.3.0

A path tracing library written in Rust.
Documentation
//! Utility data types and functions used throughout Crystal Ball.

use std::{error, fmt, io};

use gltf::image::Format;
use image::ImageError;
use nanorand::tls::TlsWyRand;
use nanorand::Rng;
#[cfg(feature = "oidn")]
use oidn::FilterError;

#[cfg(test)]
pub const EPSILON_F64: f64 = f64::EPSILON * 100.0;
#[cfg(test)]
pub const EPSILON_F32: f32 = f32::EPSILON * 100.0;

/// Factor for converting random u64 to uniformly distributed double.
const FACTOR: f64 = 5.421010862427522e-20; // 2.0_f64.powi(-64)

/// Generate a random floating point number between min and max.
pub fn random_float(rng: &mut TlsWyRand, min: f64, max: f64) -> f64 {
    // Casting to signed before casting to float can be faster depending on your hardware.
    // See Doornik, J.A.: Conversion of high-period random numbers to floating point,
    // CM transactions on modeling and computer simulation, 17(1) (2007)
    (rng.generate::<u64>() as i64 as f64 * FACTOR + 0.5) * (max - min) + min
}

// TODO: Use some crate to do this
/// The various types of errors which can occur when using Crystal Ball.
#[derive(Debug)]
pub enum Error {
    Image(ImageError),
    Io(io::Error),
    Gltf(gltf::Error),
    #[cfg(feature = "oidn")]
    Filter(FilterError),
    UnsupportedColorFormat(Format),
    Custom(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Image(e) => e.fmt(f),
            Error::Io(e) => e.fmt(f),
            Error::Gltf(e) => e.fmt(f),
            #[cfg(feature = "oidn")]
            Error::Filter(e) => write!(f, "{:?}", e),
            Error::UnsupportedColorFormat(format) => {
                write!(f, "unsupported color format '{:?}'", format)
            }
            Error::Custom(e) => write!(f, "{}", e),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            Error::Image(e) => Some(e),
            Error::Io(e) => Some(e),
            Error::Gltf(e) => Some(e),
            #[cfg(feature = "oidn")]
            Error::Filter(_) => None,
            Error::UnsupportedColorFormat(_) | Error::Custom(_) => None,
        }
    }
}

impl From<ImageError> for Error {
    fn from(e: ImageError) -> Self {
        Self::Image(e)
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Self::Io(e)
    }
}

impl From<gltf::Error> for Error {
    fn from(e: gltf::Error) -> Self {
        Self::Gltf(e)
    }
}

#[cfg(feature = "oidn")]
impl From<FilterError> for Error {
    fn from(e: FilterError) -> Self {
        Self::Filter(e)
    }
}

impl From<String> for Error {
    fn from(e: String) -> Self {
        Self::Custom(e)
    }
}

/// A struct containing common index of refraction values as constants.
#[non_exhaustive]
pub struct IOR;

impl IOR {
    pub const ACRYLIC_GLASS: f64 = 1.491;
    pub const AIR: f64 = 1.0;
    pub const ALCOHOL: f64 = 1.36;
    pub const BEER: f64 = 1.345;
    pub const CRYSTAL: f64 = 2.0;
    pub const DIAMOND: f64 = 2.418;
    pub const EMERALD: f64 = 1.583;
    pub const GLASS: f64 = 1.5;
    pub const ICE: f64 = 1.309;
    pub const LUCITE: f64 = 1.495;
    pub const MERCURY: f64 = 1.62;
    pub const PEARL: f64 = 1.61;
    pub const VODKA: f64 = 1.363;
    pub const WATER: f64 = 1.325;
}