use crate::{Allocation, AtlasSet, GpuRenderer, GraphicsError, TileSheet};
use image::{DynamicImage, GenericImageView, ImageFormat};
use std::{hash::Hash, path::Path};
#[derive(Clone, Debug, Default)]
pub struct Texture {
pub bytes: Vec<u8>,
size: (u32, u32),
}
impl Texture {
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, GraphicsError> {
Ok(Self::from_image(image::open(path)?))
}
pub fn upload_from<U: Hash + Eq>(
key: U,
path: impl AsRef<Path>,
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
) -> Option<usize> {
if let Some(id) = atlas.lookup(&key) {
Some(id)
} else {
let texture = Texture::from_file(path).ok()?;
let (width, height) = texture.size();
atlas.upload(key, texture.bytes(), width, height, 0, renderer)
}
}
pub fn upload_from_memory<U: Hash + Eq>(
key: U,
data: &[u8],
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
) -> Option<usize> {
if let Some(id) = atlas.lookup(&key) {
Some(id)
} else {
let texture = Texture::from_memory(data).ok()?;
let (width, height) = texture.size();
atlas.upload(key, texture.bytes(), width, height, 0, renderer)
}
}
pub fn upload_from_with_alloc<U: Hash + Eq>(
key: U,
path: impl AsRef<Path>,
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
) -> Option<(usize, Allocation)> {
if let Some(id) = atlas.lookup(&key) {
atlas.peek(id).map(|(allocation, _)| (id, *allocation))
} else {
let texture = Texture::from_file(path).ok()?;
let (width, height) = texture.size();
atlas.upload_with_alloc(
key,
texture.bytes(),
width,
height,
0,
renderer,
)
}
}
pub fn from_image(image: DynamicImage) -> Self {
let size = image.dimensions();
let bytes = image.into_rgba8().into_raw();
Self { bytes, size }
}
pub fn from_memory(data: &[u8]) -> Result<Self, GraphicsError> {
Ok(Self::from_image(image::load_from_memory(data)?))
}
pub fn from_memory_with_format(
data: &[u8],
format: ImageFormat,
) -> Result<Self, GraphicsError> {
Ok(Self::from_image(image::load_from_memory_with_format(
data, format,
)?))
}
pub fn upload<U: Hash + Eq>(
&self,
key: U,
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
) -> Option<usize> {
let (width, height) = self.size;
atlas.upload(key, &self.bytes, width, height, 0, renderer)
}
pub fn upload_with_alloc<U: Hash + Eq>(
&self,
key: U,
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
) -> Option<(usize, Allocation)> {
let (width, height) = self.size;
atlas.upload_with_alloc(key, &self.bytes, width, height, 0, renderer)
}
pub fn new_tilesheet(
self,
tileset_name: &str,
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
tilesize: u32,
) -> Option<TileSheet> {
TileSheet::new(tileset_name, self, renderer, atlas, tilesize)
}
pub fn tilesheet_upload(
self,
tileset_name: &str,
tilesheet: &mut TileSheet,
atlas: &mut AtlasSet<i32>,
renderer: &GpuRenderer,
tilesize: u32,
) -> Option<()> {
tilesheet.upload(tileset_name, self, renderer, atlas, tilesize)
}
pub fn size(&self) -> (u32, u32) {
self.size
}
}