view examples/common.rs @ 746:0ebf6467e4ff

examples: Add a menu example.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 18 Jan 2020 19:19:51 +0100
parents 90e907859bae
children ee45bfde91bb
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::{BufReader, Read};
use std::path::Path;

pub fn load_file_into_vec<P: AsRef<Path>>(filename: P) -> Vec<u8> {
    let file = File::open(filename).unwrap();
    let mut file = BufReader::new(file);
    let mut buf = vec![];
    file.read_to_end(&mut buf).unwrap();
    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 upload_texture_from_rgb_image(surface: &mut GlfwSurface, img: DynamicImage) -> Result<LoadedTexture, TextureLoadError> {
    let (width, height) = img.dimensions();
    let texels = img
        .pixels()
        .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2]))
        .collect::<Vec<_>>();

    // 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::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)
        }
    }
}