digging/src/assets.rs

154 lines
4.5 KiB
Rust

use std::collections::HashMap;
use glium::{
texture::{RawImage2d, SrgbTexture2d},
Display, Program,
};
use glob::glob;
pub type Textures = HashMap<String, SrgbTexture2d>;
#[derive(Debug)]
pub struct TextureAtlas {
pub texture: SrgbTexture2d,
rects: HashMap<String, glium::Rect>,
width: u32,
height: u32,
}
pub struct AtlasUVs {
pub bottom_left: [f32; 2],
pub bottom_right: [f32; 2],
pub top_left: [f32; 2],
pub top_right: [f32; 2],
}
impl TextureAtlas {
fn new(display: &Display) -> TextureAtlas {
log::info!("Loading textures");
let paths = glob("assets/textures/**/*.png").unwrap();
let items = paths.map(|entry| {
let path = entry.unwrap();
let image = image::open(&path).unwrap().to_rgba8();
let image_dimensions = image.dimensions();
let image = image.into_raw();
let name_path = path
.with_extension("")
.strip_prefix("assets/textures/")
.unwrap()
.to_owned();
let mut name = String::new();
for part in name_path.iter() {
name.push_str(part.to_str().unwrap());
name.push(':');
}
name.pop();
crunch::Item::new(
(name, image),
image_dimensions.0 as usize,
image_dimensions.1 as usize,
crunch::Rotation::None,
)
});
log::info!("Packing textures into atlas");
let (width, height, items) = crunch::pack_into_po2(4096, items).unwrap();
let items = items.into_iter().map(|entry| {
let rect = glium::Rect {
left: entry.0.x as u32,
bottom: entry.0.y as u32,
width: entry.0.w as u32,
height: entry.0.h as u32,
};
let name = entry.1 .0;
let image = entry.1 .1;
(name, image, rect)
});
let mut atlas = TextureAtlas {
texture: SrgbTexture2d::empty(display, width as u32, height as u32).unwrap(),
rects: HashMap::new(),
width: width as u32,
height: height as u32,
};
for (name, image, rect) in items {
atlas.texture.write(
rect,
RawImage2d::from_raw_rgba_reversed(&image, (rect.width, rect.height)),
);
atlas.rects.insert(name, rect);
}
atlas
}
pub fn get_uv(&self, name: String) -> AtlasUVs {
let rect = self.rects.get(&name).unwrap();
AtlasUVs {
bottom_left: Self::coord_to_uv(
rect.left,
rect.bottom + rect.height,
self.width,
self.height,
),
bottom_right: Self::coord_to_uv(
rect.left + rect.width,
rect.bottom + rect.height,
self.width,
self.height,
),
top_left: Self::coord_to_uv(rect.left, rect.bottom, self.width, self.height),
top_right: Self::coord_to_uv(
rect.left + rect.width,
rect.bottom,
self.width,
self.height,
),
}
}
fn coord_to_uv(x: u32, y: u32, width: u32, height: u32) -> [f32; 2] {
[x as f32 / width as f32, (y as f32 / height as f32)]
}
}
pub type Shaders = HashMap<String, Program>;
fn load_shaders(display: &Display) -> Shaders {
log::info!("Loading shaders.");
let mut shaders: Shaders = Shaders::new();
for entry in glob("assets/shaders/*").unwrap() {
if let Ok(path) = entry {
// Operate only on directories
if path.is_file() {
continue;
}
let vert_source = std::fs::read_to_string(path.join("vert.glsl")).unwrap();
let frag_source = std::fs::read_to_string(path.join("frag.glsl")).unwrap();
let program = Program::from_source(display, &vert_source, &frag_source, None).unwrap();
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
shaders.insert(name.to_string(), program);
log::info!("Loaded shader {:?} from {:?}.", name, path);
}
}
shaders
}
pub struct Assets {
pub texture_atlas: TextureAtlas,
pub shaders: Shaders,
}
impl Assets {
pub fn new(display: &Display) -> Assets {
Assets {
texture_atlas: TextureAtlas::new(display),
shaders: load_shaders(display),
}
}
}