use blit::{Color, BlitBuffer, BlitExt};
use image;
use std::fmt;
use std::path::Path;
use std::error::Error;
use font::*;
#[derive(Debug, Clone)]
pub struct InvalidImageFormat;
impl fmt::Display for InvalidImageFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "file format doesn't match '.png' or '.blit'")
}
}
impl Error for InvalidImageFormat {
fn description(&self) -> &str {
"file format doesn't match '.png' or '.blit'"
}
fn cause(&self) -> Option<&Error> {
None
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct SpriteRef(usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct FontRef(usize);
#[derive(Debug)]
pub struct Resources {
sprites: Vec<BlitBuffer>,
fonts: Vec<Font>
}
impl Resources {
pub fn new() -> Self {
let mut fonts = Vec::new();
let default_font_buffer = BlitBuffer::from_memory(include_bytes!("../resources/ArtosSans.png.blit")).unwrap();
let default_font_settings = FontSettings {
start: '!',
char_size: (9, 9),
leading_offset: 2,
mask_color: Color::from_u32(0xFF00FF)
};
fonts.push(Font::new(default_font_buffer, default_font_settings));
Resources {
fonts,
sprites: Vec::new()
}
}
pub fn default_font(&self) -> FontRef {
FontRef(0)
}
pub fn load_sprite_from_file<P>(&mut self, path: P, mask_color: Color) -> Result<SpriteRef, Box<Error>> where P: AsRef<Path> {
let index = self.sprites.len();
let buffer = Resources::load_blitbuffer(path.as_ref(), mask_color)?;
self.sprites.push(buffer);
Ok(SpriteRef(index))
}
pub fn load_sprite_from_memory(&mut self, buffer: &[u8]) -> Result<SpriteRef, Box<Error>> {
let index = self.sprites.len();
let blitbuffer = BlitBuffer::from_memory(buffer)?;
self.sprites.push(blitbuffer);
Ok(SpriteRef(index))
}
pub fn get_sprite(&self, sprite_ref: SpriteRef) -> Option<&BlitBuffer> {
if sprite_ref.0 < self.sprites.len() {
Some(&self.sprites[sprite_ref.0])
} else {
None
}
}
pub fn load_font_sprite_from_file<P>(&mut self, path: P, settings: FontSettings) -> Result<FontRef, Box<Error>> where P: AsRef<Path> {
let index = self.fonts.len();
let buffer = Resources::load_blitbuffer(path.as_ref(), settings.mask_color)?;
self.fonts.push(Font::new(buffer, settings));
Ok(FontRef(index))
}
pub fn load_font_sprite_from_memory(&mut self, buffer: &[u8], settings: FontSettings) -> Result<FontRef, Box<Error>> {
let index = self.sprites.len();
let blitbuffer = BlitBuffer::from_memory(buffer)?;
self.fonts.push(Font::new(blitbuffer, settings));
Ok(FontRef(index))
}
pub fn get_font(&self, font_ref: FontRef) -> Option<&Font> {
if font_ref.0 < self.fonts.len() {
Some(&self.fonts[font_ref.0])
} else {
None
}
}
pub fn load_blitbuffer(path: &Path, mask_color: Color) -> Result<BlitBuffer, Box<Error>> {
let ext = path.extension().and_then(|s| s.to_str()).map_or("".to_string(), |s| s.to_ascii_lowercase());
let buffer = match &ext[..] {
"blit" => {
BlitBuffer::open(path)?
},
"png" => {
let img = image::open(path)?;
let rgb = img.as_rgb8().expect("Image is not of a valid type, consider removing the alpha channel");
rgb.to_blit_buffer(mask_color)
},
_ => return Err(Box::new(InvalidImageFormat))
};
Ok(buffer)
}
}