view examples/common.rs @ 752:5e5e7136ac92

examples: Return a Result for load_file_into_vec()
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 29 Jan 2020 17:45:25 +0100
parents ee45bfde91bb
children a662dddd4a2b
line wrap: on
line source

use image::{GenericImageView, DynamicImage, GrayImage, ImageError};
use luminance::pixel::{NormRGB8UI, NormRGBA8UI};
use luminance::texture::{Dim2, Flat, Sampler, Texture, GenMipmaps};
use luminance_glfw::GlfwSurface;
use touhou::th06::anm0::Anm0;
use std::fs::File;
use std::io::{self, BufReader, Read};
use std::path::Path;

pub fn load_file_into_vec<P: AsRef<Path>>(filename: P) -> io::Result<Vec<u8>> {
    let file = File::open(filename)?;
    let mut file = BufReader::new(file);
    let mut buf = vec![];
    file.read_to_end(&mut buf)?;
    Ok(buf)
}

pub enum LoadedTexture {
    Rgba(Texture<Flat, Dim2, NormRGBA8UI>),
    Rgb(Texture<Flat, Dim2, NormRGB8UI>),
}

#[derive(Debug)]
pub enum TextureLoadError {
    CannotOpenRgb(String, ImageError),
    CannotOpenAlpha(String, ImageError),
    AlphaToGrayscale(String),
}

fn open_rgb_png(path: &Path) -> Result<DynamicImage, TextureLoadError> {
    // load the texture into memory as a whole bloc (i.e. no streaming)
    image::open(&path).map_err(|e| TextureLoadError::CannotOpenRgb(path.to_str().unwrap().to_owned(), e))
}

fn open_alpha_png(path: &Path) -> Result<DynamicImage, TextureLoadError> {
    // load the texture into memory as a whole bloc (i.e. no streaming)
    image::open(&path).map_err(|e| TextureLoadError::CannotOpenAlpha(path.to_str().unwrap().to_owned(), e))
}

fn merge_rgb_alpha(rgb: &DynamicImage, alpha: &GrayImage) -> Vec<(u8, u8, u8, u8)> {
    rgb
        .pixels()
        .zip(alpha.pixels())
        .map(|((_x, _y, rgb), luma)| (rgb[0], rgb[1], rgb[2], luma[0]))
        .collect::<Vec<_>>()
}

pub fn load_from_data(data: &[u8]) -> Result<DynamicImage, ImageError> {
    image::load_from_memory(data)
}

pub fn reupload_texture_from_rgb_image(tex: &mut Texture<Flat, Dim2, NormRGB8UI>, img: DynamicImage) -> Result<(), TextureLoadError> {
    let texels = img
        .pixels()
        .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2]))
        .collect::<Vec<_>>();

    // the first argument disables mipmap generation (we don’t care so far)
    tex.upload(GenMipmaps::No, &texels).unwrap();

    Ok(())
}

pub fn upload_texture_from_rgb_image(surface: &mut GlfwSurface, img: DynamicImage) -> Result<LoadedTexture, TextureLoadError> {
    let (width, height) = img.dimensions();

    // create the luminance texture; the third argument is the number of mipmaps we want (leave it
    // to 0 for now) and the latest is a the sampler to use when sampling the texels in the
    // shader (we’ll just use the default one)
    let mut tex =
        Texture::new(surface, [width, height], 0, Sampler::default()).expect("luminance texture creation");

    reupload_texture_from_rgb_image(&mut tex, img)?;

    Ok(LoadedTexture::Rgb(tex))
}

pub fn load_rgb_texture(surface: &mut GlfwSurface, path: &Path) -> Result<LoadedTexture, TextureLoadError> {
    let img = open_rgb_png(&path)?;
    upload_texture_from_rgb_image(surface, img)
}

fn load_rgb_a_pngs(surface: &mut GlfwSurface, rgb: &Path, alpha: &Path) -> Result<LoadedTexture, TextureLoadError> {
    let img = open_alpha_png(&alpha)?;
    let alpha = match img.grayscale() {
        DynamicImage::ImageLuma8(img) => img,
        _ => {
            return Err(TextureLoadError::AlphaToGrayscale(alpha.to_str().unwrap().to_owned()))
        }
    };
    let (width, height) = img.dimensions();
    let img = open_rgb_png(&rgb)?;
    assert_eq!((width, height), img.dimensions());
    let texels = merge_rgb_alpha(&img, &alpha);

    // create the luminance texture; the third argument is the number of mipmaps we want (leave it
    // to 0 for now) and the latest is a the sampler to use when sampling the texels in the
    // shader (we’ll just use the default one)
    let tex =
        Texture::new(surface, [width, height], 0, Sampler::default()).expect("luminance texture creation");

    // the first argument disables mipmap generation (we don’t care so far)
    tex.upload(GenMipmaps::No, &texels).unwrap();

    Ok(LoadedTexture::Rgba(tex))
}

pub fn load_anm_image<P: AsRef<Path>>(mut surface: &mut GlfwSurface, anm0: &Anm0, anm_filename: P) -> Result<LoadedTexture, TextureLoadError> {
    let anm_filename = anm_filename.as_ref();
    let png_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap());
    match anm0.alpha_filename {
        Some(ref filename) => {
            let alpha_filename = anm_filename.with_file_name(Path::new(filename).file_name().unwrap());
            load_rgb_a_pngs(&mut surface, &png_filename, &alpha_filename)
        },
        None => {
            load_rgb_texture(&mut surface, &png_filename)
        }
    }
}