• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ekarpp / lumo / 14235426927

03 Apr 2025 03:53AM UTC coverage: 72.653%. First build
14235426927

push

github

ekarpp
0.6.1

* Generalize thread pool
* Paralellize material parsing for scenes
* Implement variable wavelength index of refraction (and dispersion)
* Implement efficiency optimized russian roulette
* Add batching to samplers
* Restricts mediums to scene boundaries
* Fix cylinder bounding box
* Fix instance sample on normals
* Update github actions

290 of 821 new or added lines in 36 files covered. (35.32%)

6740 of 9277 relevant lines covered (72.65%)

39613243.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/parser/mtl.rs
1
use super::*;
2
use crate::pool::{Executor, ThreadPool};
3
use crate::tracer::{RGB, Spectrum};
4

5
use task::{MtlTask, MtlTaskExecutor};
6

7
mod task;
8

9
/// Holds the properties of a microfacet material
10
pub struct MtlConfig {
11
    /// Diffuse color of the material
12
    pub Kd: Spectrum,
13
    /// Texture map
14
    pub map_Kd: Option<Image<Spectrum>>,
15
    /// Specular color of the material
16
    pub Ks: Spectrum,
17
    /// Specular texture map
18
    pub map_Ks: Option<Image<Spectrum>>,
19
    /// Emittance of the material. If not zero vector, then createas a light
20
    pub Ke: Spectrum,
21
    /// Emission map
22
    pub map_Ke: Option<Image<Spectrum>>,
23
    /// Bump map for the material
24
    pub map_Bump: Option<Image<Normal>>,
25
    /// How much each light channel passes on transmission
26
    pub Tf: Spectrum,
27
    /// Refraction index of the material
28
    pub eta: Float,
29
    /// Roughness of the material
30
    pub roughness: Float,
31
    /// Absorption coefficient
32
    pub k: Float,
33
    /// Is fresnel enabled for the material a.k.a. is it a conductor/dielectric
34
    pub fresnel_enabled: bool,
35
    /// Is the material dielectric?
36
    pub is_transparent: bool,
37
}
38

39
impl Default for MtlConfig {
40
    fn default() -> Self {
×
41
        Self {
×
42
            Kd: Spectrum::BLACK,
×
43
            Ks: Spectrum::BLACK,
×
44
            Ke: Spectrum::BLACK,
×
45
            Tf: Spectrum::BLACK,
×
46
            eta: 1.5,
×
47
            k: 0.0,
×
48
            roughness: 1.0,
×
49
            fresnel_enabled: false,
×
50
            is_transparent: false,
×
51
            map_Kd: None,
×
52
            map_Ks: None,
×
53
            map_Ke: None,
×
54
            map_Bump: None,
×
55
        }
×
56
    }
×
57
}
58

59
impl MtlConfig {
60
    pub fn build_material(self) -> Material {
×
61
        if !self.Ke.is_black() || self.map_Ke.is_some() {
×
62
            if let Some(img) = self.map_Ke {
×
63
                Material::light(Texture::Image(img))
×
64
            } else {
65
                Material::light(Texture::from(self.Ke))
×
66
            }
67
        } else {
68
            let kd = if let Some(img) = self.map_Kd {
×
69
                Texture::Image(img)
×
70
            } else {
71
                Texture::from(self.Kd)
×
72
            };
73
            let ks = if let Some(img) = self.map_Ks {
×
74
                Texture::Image(img)
×
75
            } else {
76
                Texture::from(self.Ks)
×
77
            };
78
            let tf = Texture::from(self.Tf);
×
79

×
80
            Material::microfacet(
×
81
                self.roughness,
×
82
                self.eta,
×
83
                self.k,
×
84
                self.is_transparent,
×
85
                self.fresnel_enabled,
×
86
                kd, ks, tf,
×
87
                self.map_Bump,
×
88
            )
×
89
        }
90
    }
×
91
}
92

93
pub fn load_file<T: Read + Sized>(
×
94
    bytes: T,
×
95
    map_ks: bool,
×
NEW
96
    zip_file: Arc<Vec<u8>>,
×
97
    materials: &mut Vec<Material>,
×
98
    material_indices: &mut FxHashMap<String, usize>,
×
99
) -> Result<()> {
×
100
    let reader = BufReader::new(bytes);
×
NEW
101
    let mut block = Vec::new();
×
102

×
NEW
103
    let executor = MtlTaskExecutor::new(zip_file, map_ks);
×
NEW
104
    let threads = 4;
×
NEW
105
    let pool = ThreadPool::new(
×
NEW
106
        threads,
×
NEW
107
        executor,
×
NEW
108
    );
×
109

110
    for line in reader.lines() {
×
111
        let line = line?.trim().to_string();
×
112
        if line.starts_with('#') || line.is_empty() {
×
113
            continue;
×
114
        }
×
NEW
115
        let cmd = line.split_ascii_whitespace().nth(0).unwrap();
×
116

×
NEW
117
        if cmd == "newmtl" && !block.is_empty() {
×
NEW
118
            pool.publish(MtlTask::new(block));
×
NEW
119
            block = Vec::new();
×
120
        }
×
121

NEW
122
        block.push(line);
×
123
    }
124

NEW
125
    if !block.is_empty() {
×
NEW
126
        pool.publish(MtlTask::new(block));
×
127
    }
×
128

NEW
129
    pool.all_published();
×
NEW
130

×
NEW
131
    let mut finished = 0;
×
NEW
132
    while finished < threads {
×
NEW
133
        let result = pool.pop_result();
×
NEW
134
        if let Some(result) = result {
×
NEW
135
            if !material_indices.contains_key(&result.mtl_name) {
×
NEW
136
                println!("{}", result.mtl_name);
×
NEW
137
                materials.push(result.mtl_cfg.build_material());
×
NEW
138
                material_indices.insert(result.mtl_name, materials.len() - 1);
×
NEW
139
            }
×
NEW
140
        } else {
×
NEW
141
            finished += 1;
×
NEW
142
        }
×
143
    }
144

145
    Ok(())
×
146
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc