gltf_viewer_lib/render/
texture.rs1use std::os::raw::c_void;
2use std::path::Path;
3use std::{fs, io};
4
5use base64;
6use gl;
7use gltf;
8use gltf::json::texture::MinFilter;
9use gltf::image::Source;
10
11use image;
12use image::ImageFormat::{JPEG, PNG};
13use image::DynamicImage::*;
14use image::GenericImageView;
15use image::FilterType;
16
17use crate::importdata::ImportData;
18
19pub struct Texture {
20 pub index: usize, pub name: Option<String>,
22
23 pub id: u32, pub tex_coord: u32, }
26
27impl Texture {
28 pub fn from_gltf(g_texture: &gltf::Texture<'_>, tex_coord: u32, imp: &ImportData, base_path: &Path) -> Texture {
29 let buffers = &imp.buffers;
30 let mut texture_id = 0;
31 unsafe {
32 gl::GenTextures(1, &mut texture_id);
33 gl::BindTexture(gl::TEXTURE_2D, texture_id);
34 }
35 let (needs_power_of_two, generate_mip_maps) =
36 unsafe { Self::set_sampler_params(&g_texture.sampler()) };
37
38 let g_img = g_texture.source();
41 let img = match g_img.source() {
42 Source::View { view, mime_type } => {
43 let parent_buffer_data = &buffers[view.buffer().index()].0;
44 let begin = view.offset();
45 let end = begin + view.length();
46 let data = &parent_buffer_data[begin..end];
47 match mime_type {
48 "image/jpeg" => image::load_from_memory_with_format(data, JPEG),
49 "image/png" => image::load_from_memory_with_format(data, PNG),
50 _ => panic!(format!("unsupported image type (image: {}, mime_type: {})",
51 g_img.index(), mime_type)),
52 }
53 },
54 Source::Uri { uri, mime_type } => {
55 if uri.starts_with("data:") {
56 let encoded = uri.split(',').nth(1).unwrap();
57 let data = base64::decode(&encoded).unwrap();
58 let mime_type = if let Some(ty) = mime_type {
59 ty
60 } else {
61 uri.split(',')
62 .nth(0).unwrap()
63 .split(':')
64 .nth(1).unwrap()
65 .split(';')
66 .nth(0).unwrap()
67 };
68
69 match mime_type {
70 "image/jpeg" => image::load_from_memory_with_format(&data, JPEG),
71 "image/png" => image::load_from_memory_with_format(&data, PNG),
72 _ => panic!(format!("unsupported image type (image: {}, mime_type: {})",
73 g_img.index(), mime_type)),
74 }
75 }
76 else if let Some(mime_type) = mime_type {
77 let path = base_path.parent().unwrap_or_else(|| Path::new("./")).join(uri);
78 let file = fs::File::open(path).unwrap();
79 let reader = io::BufReader::new(file);
80 match mime_type {
81 "image/jpeg" => image::load(reader, JPEG),
82 "image/png" => image::load(reader, PNG),
83 _ => panic!(format!("unsupported image type (image: {}, mime_type: {})",
84 g_img.index(), mime_type)),
85 }
86 }
87 else {
88 let path = base_path.parent().unwrap_or_else(||Path::new("./")).join(uri);
89 image::open(path)
90 }
91 }
92 };
93
94 let dyn_img = img.expect("Image loading failed.");
96
97 let format = match dyn_img {
98 ImageLuma8(_) => gl::RED,
99 ImageLumaA8(_) => gl::RG,
100 ImageRgb8(_) => gl::RGB,
101 ImageRgba8(_) => gl::RGBA,
102 ImageBgr8(_) => gl::BGR,
103 ImageBgra8(_) => gl::BGRA,
104 };
105
106 let (width, height) = dyn_img.dimensions();
114 let (data, width, height) =
115 if needs_power_of_two && (!width.is_power_of_two() || !height.is_power_of_two()) {
116 let nwidth = width.next_power_of_two();
117 let nheight = height.next_power_of_two();
118 let resized = dyn_img.resize(nwidth, nheight, FilterType::Lanczos3);
119 (resized.raw_pixels(), resized.width(), resized.height())
120 }
121 else {
122 (dyn_img.raw_pixels(), dyn_img.width(), dyn_img.height())
123 };
124
125 unsafe {
126 gl::TexImage2D(gl::TEXTURE_2D, 0, format as i32, width as i32, height as i32,
127 0, format, gl::UNSIGNED_BYTE, &data[0] as *const u8 as *const c_void);
128
129 if generate_mip_maps {
130 gl::GenerateMipmap(gl::TEXTURE_2D);
131 }
132 }
133 Texture {
134 index: g_texture.index(),
135 name: g_texture.name().map(|s| s.into()),
136 id: texture_id,
137 tex_coord,
138 }
139 }
140
141 unsafe fn set_sampler_params(sampler: &gltf::texture::Sampler<'_>) -> (bool, bool) {
144 let mip_maps = match sampler.min_filter() {
149 Some(MinFilter::NearestMipmapNearest) |
150 Some(MinFilter::LinearMipmapNearest) |
151 Some(MinFilter::NearestMipmapLinear) |
152 Some(MinFilter::LinearMipmapLinear) |
153 None => true, _ => false
155 };
156
157 if let Some(min_filter) = sampler.min_filter() {
160 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, min_filter.as_gl_enum() as i32);
161 }
162 else {
163 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR as i32);
164 }
165 if let Some(mag_filter) = sampler.mag_filter() {
166 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, mag_filter.as_gl_enum() as i32);
167 }
168 else {
169 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
170 }
171
172 let wrap_s = sampler.wrap_s().as_gl_enum();
173 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, wrap_s as i32);
174 let wrap_t = sampler.wrap_t().as_gl_enum();
175 gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, wrap_t as i32);
176
177 let needs_power_of_two =
178 wrap_s != gl::CLAMP_TO_EDGE ||
179 wrap_t != gl::CLAMP_TO_EDGE ||
180 mip_maps;
181 (needs_power_of_two, mip_maps)
182 }
183}