dedup textures

This commit is contained in:
Robin Appelman 2023-12-16 23:55:50 +01:00
commit 44be60641b
2 changed files with 53 additions and 21 deletions

View file

@ -1,4 +1,4 @@
use crate::material::MaterialData; use crate::material::{MaterialData, TextureData};
use bytemuck::{offset_of, Pod, Zeroable}; use bytemuck::{offset_of, Pod, Zeroable};
use gltf_json::accessor::{ComponentType, GenericComponentType, Type}; use gltf_json::accessor::{ComponentType, GenericComponentType, Type};
use gltf_json::buffer::{Target, View}; use gltf_json::buffer::{Target, View};
@ -9,7 +9,7 @@ use gltf_json::texture::Info;
use gltf_json::validation::Checked::Valid; use gltf_json::validation::Checked::Valid;
use gltf_json::{Accessor, Extras, Image, Index, Material, Mesh, Texture, Value}; use gltf_json::{Accessor, Extras, Image, Index, Material, Mesh, Texture, Value};
use image::png::PngEncoder; use image::png::PngEncoder;
use image::{DynamicImage, GenericImageView}; use image::GenericImageView;
use std::mem::size_of; use std::mem::size_of;
use vmdl::{Model, SkinTable}; use vmdl::{Model, SkinTable};
@ -219,15 +219,9 @@ pub fn push_material(
images: &mut Vec<Image>, images: &mut Vec<Image>,
material: MaterialData, material: MaterialData,
) -> Material { ) -> Material {
let textures_start = textures.len() as u32; let texture_index = material
let texture = material
.texture .texture
.map(|tex| push_texture(buffer, views, images, tex)); .map(|tex| push_or_get_texture(buffer, views, textures, images, tex));
let texture_index = texture.map(|texture| {
textures.push(texture);
textures_start
});
let alpha_mode = match (material.translucent, material.alpha_test.is_some()) { let alpha_mode = match (material.translucent, material.alpha_test.is_some()) {
(true, _) => AlphaMode::Blend, (true, _) => AlphaMode::Blend,
@ -248,7 +242,7 @@ pub fn push_material(
material.color.map(|channel| channel as f32 / 255.0), material.color.map(|channel| channel as f32 / 255.0),
), ),
base_color_texture: texture_index.map(|index| Info { base_color_texture: texture_index.map(|index| Info {
index: Index::new(index), index,
tex_coord: 0, tex_coord: 0,
extensions: None, extensions: None,
extras: Extras::default(), extras: Extras::default(),
@ -259,12 +253,38 @@ pub fn push_material(
} }
} }
fn push_or_get_texture(
buffer: &mut Vec<u8>,
views: &mut Vec<View>,
textures: &mut Vec<Texture>,
images: &mut Vec<Image>,
texture: TextureData,
) -> Index<Texture> {
match get_texture_index(textures, &texture.name) {
Some(index) => index,
None => {
let index = textures.len() as u32;
textures.push(push_texture(buffer, views, images, texture));
Index::new(index)
}
}
}
fn get_texture_index(textures: &[Texture], name: &str) -> Option<Index<Texture>> {
textures
.iter()
.enumerate()
.find_map(|(i, tex)| (tex.name.as_deref() == Some(name)).then_some(i))
.map(|i| Index::new(i as u32))
}
fn push_texture( fn push_texture(
buffer: &mut Vec<u8>, buffer: &mut Vec<u8>,
views: &mut Vec<View>, views: &mut Vec<View>,
images: &mut Vec<Image>, images: &mut Vec<Image>,
image: DynamicImage, texture: TextureData,
) -> Texture { ) -> Texture {
let image = texture.image;
let buffer_start = buffer.len() as u32; let buffer_start = buffer.len() as u32;
let view_start = views.len() as u32; let view_start = views.len() as u32;
let image_start = images.len() as u32; let image_start = images.len() as u32;
@ -291,7 +311,7 @@ fn push_texture(
byte_stride: None, byte_stride: None,
extensions: Default::default(), extensions: Default::default(),
extras: Default::default(), extras: Default::default(),
name: None, name: Some(texture.name.clone()),
target: None, target: None,
}; };
@ -300,7 +320,7 @@ fn push_texture(
let image = Image { let image = Image {
buffer_view: Some(Index::new(view_start)), buffer_view: Some(Index::new(view_start)),
mime_type: Some(MimeType("image/png".into())), mime_type: Some(MimeType("image/png".into())),
name: None, name: Some(texture.name.clone()),
uri: None, uri: None,
extensions: None, extensions: None,
extras: Default::default(), extras: Default::default(),
@ -308,7 +328,7 @@ fn push_texture(
images.push(image); images.push(image);
Texture { Texture {
name: None, name: Some(texture.name),
sampler: None, sampler: None,
source: Index::new(image_start), source: Index::new(image_start),
extensions: None, extensions: None,

View file

@ -28,12 +28,18 @@ pub fn load_material_fallback(name: &str, search_dirs: &[String], loader: &Loade
pub struct MaterialData { pub struct MaterialData {
pub name: String, pub name: String,
pub color: [u8; 4], pub color: [u8; 4],
pub texture: Option<DynamicImage>, pub texture: Option<TextureData>,
pub alpha_test: Option<f32>, pub alpha_test: Option<f32>,
pub bump_map: Option<DynamicImage>, pub bump_map: Option<TextureData>,
pub translucent: bool, pub translucent: bool,
} }
#[derive(Debug)]
pub struct TextureData {
pub name: String,
pub image: DynamicImage,
}
pub fn load_material( pub fn load_material(
name: &str, name: &str,
search_dirs: &[String], search_dirs: &[String],
@ -85,14 +91,20 @@ pub fn load_material(
.and_then(|val| f32::from_str(val).ok()) .and_then(|val| f32::from_str(val).ok())
.unwrap_or(1.0); .unwrap_or(1.0);
let bump_map = get_path(&table, "$bumpmap") let bump_map = get_path(&table, "$bumpmap").and_then(|path| {
.map(|path| load_texture(&path, loader, true).ok()) Some(TextureData {
.flatten(); image: load_texture(&path, loader, true).ok()?,
name: path,
})
});
Ok(MaterialData { Ok(MaterialData {
color: [255; 4], color: [255; 4],
name: name.into(), name: name.into(),
texture: Some(texture), texture: Some(TextureData {
name: base_texture,
image: texture,
}),
bump_map, bump_map,
alpha_test: alpha_test.then_some(alpha_cutout), alpha_test: alpha_test.then_some(alpha_cutout),
translucent: translucent | glass | alpha_test, translucent: translucent | glass | alpha_test,