154 lines
4.5 KiB
Rust
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),
|
|
}
|
|
}
|
|
}
|