1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// pbrt
use crate::core::geometry::{Point3f, Vector3f};
use crate::core::interaction::SurfaceInteraction;
use crate::core::pbrt::{Float, Spectrum};
use crate::core::texture::fbm;
use crate::core::texture::{Texture, TextureMapping3D};

// see marble.h

pub struct MarbleTexture {
    pub mapping: Box<TextureMapping3D>,
    pub octaves: i32,     // default: 8
    pub omega: Float,     // default: 0.5
    pub scale: Float,     // default: 1.0
    pub variation: Float, // default: 0.2
}

impl MarbleTexture {
    pub fn new(
        mapping: Box<TextureMapping3D>,
        octaves: i32,
        omega: Float,
        scale: Float,
        variation: Float,
    ) -> Self {
        MarbleTexture {
            mapping,
            omega,
            octaves,
            scale,
            variation,
        }
    }
}

impl Texture<Spectrum> for MarbleTexture {
    fn evaluate(&self, si: &SurfaceInteraction) -> Spectrum {
        let mut dpdx: Vector3f = Vector3f::default();
        let mut dpdy: Vector3f = Vector3f::default();
        let mut p: Point3f = self.mapping.map(si, &mut dpdx, &mut dpdy);
        p *= self.scale;
        let marble: Float = p.y
            + self.variation
                * fbm(
                    &p,
                    &(dpdx * self.scale),
                    &(dpdy * self.scale),
                    self.omega,
                    self.octaves,
                );
        let mut t: Float = 0.5 as Float + 0.5 as Float * marble.sin();
        let c: [[Float; 3]; 9] = [
            [0.58 as Float, 0.58 as Float, 0.6 as Float],
            [0.58 as Float, 0.58 as Float, 0.6 as Float],
            [0.58 as Float, 0.58 as Float, 0.6 as Float],
            [0.5 as Float, 0.5 as Float, 0.5 as Float],
            [0.6 as Float, 0.59 as Float, 0.58 as Float],
            [0.58 as Float, 0.58 as Float, 0.6 as Float],
            [0.58 as Float, 0.58 as Float, 0.6 as Float],
            [0.2 as Float, 0.2 as Float, 0.33 as Float],
            [0.58 as Float, 0.58 as Float, 0.6 as Float],
        ];
        let nseg: usize = 6;
        let mut first: usize = (t * nseg as Float).floor() as usize;
        if first > 5 {
            // make sure we don't panic with index out of bounds
            first = 5;
        }
        t = t * nseg as Float - first as Float;
        let c0: Spectrum = Spectrum::from_rgb(&c[first]);
        let c1: Spectrum = Spectrum::from_rgb(&c[first + 1]);
        let c2: Spectrum = Spectrum::from_rgb(&c[first + 2]);
        let c3: Spectrum = Spectrum::from_rgb(&c[first + 3]);
        // Bezier spline evaluated with de Castilejau's algorithm
        let mut s0: Spectrum = c0 * (1.0 as Float - t) + c1 * t;
        let mut s1: Spectrum = c1 * (1.0 as Float - t) + c2 * t;
        let s2: Spectrum = c2 * (1.0 as Float - t) + c3 * t;
        s0 = s0 * (1.0 as Float - t) + s1 * t;
        s1 = s1 * (1.0 as Float - t) + s2 * t;
        // extra scale of 1.5 to increase variation among colors
        (s0 * (1.0 as Float - t) + s1 * t) * 1.5 as Float
    }
}