You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.1 KiB
Rust

use crate::err::Error;
pub use image::{ColorType, ImageFormat};
use image::{DynamicImage, GenericImageView};
use nalgebra_glm::Vec4;
use std::io::{BufRead, Seek};
use std::os::raw::c_void;
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum WrapStyle {
Repeat = gl::REPEAT,
MirroredRepeat = gl::MIRRORED_REPEAT,
ClampToEdge = gl::CLAMP_TO_EDGE,
ClampToBorder = gl::CLAMP_TO_BORDER,
}
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum FilterStyle {
Nearest = gl::NEAREST,
Linear = gl::LINEAR,
}
impl FilterStyle {
fn get_gl_enum(filter: FilterStyle, mipmap: Option<FilterStyle>) -> i32 {
let gl_enum = match (filter, mipmap) {
(FilterStyle::Nearest, None) => gl::NEAREST,
(FilterStyle::Linear, None) => gl::LINEAR,
(FilterStyle::Linear, Some(FilterStyle::Linear)) => gl::LINEAR_MIPMAP_LINEAR,
(FilterStyle::Linear, Some(FilterStyle::Nearest)) => gl::LINEAR_MIPMAP_NEAREST,
(FilterStyle::Nearest, Some(FilterStyle::Linear)) => gl::NEAREST_MIPMAP_LINEAR,
(FilterStyle::Nearest, Some(FilterStyle::Nearest)) => gl::NEAREST_MIPMAP_NEAREST,
};
gl_enum as i32
}
}
#[derive(Clone, Debug)]
pub struct Texture {
image_id: u32,
options: TextureOptions,
}
pub struct Image {
pub image: DynamicImage,
}
impl Image {
pub fn load<R: BufRead + Seek>(r: R, format: ImageFormat) -> Result<Image, Error> {
Ok(Image {
image: image::load(r, format)?,
})
}
pub fn into_texture(mut self, options: TextureOptions) -> Result<Texture, Error> {
let mut image_id = 0;
unsafe {
gl::GenTextures(1, &mut image_id);
gl::BindTexture(gl::TEXTURE_2D, image_id);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, options.wrap_s as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, options.wrap_t as i32);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_MAG_FILTER,
FilterStyle::get_gl_enum(options.mag_filter, options.mag_mipmap_filter),
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_MAG_FILTER,
FilterStyle::get_gl_enum(options.min_filter, options.min_mipmap_filter),
);
if let Some((_, ref border)) = options.border {
gl::TexParameterfv(gl::TEXTURE_2D, gl::TEXTURE_BORDER_COLOR, border.as_ptr())
}
if options.flip_vertically {
self.image = self.image.flipv()
}
let pixels = self
.image
.pixels()
.into_iter()
.flat_map(|x| vec![x.2[0], x.2[1], x.2[2], x.2[3]])
.collect::<Vec<u8>>();
let width = self.image.width();
let height = self.image.height();
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGBA as i32,
width as i32,
height as i32,
0,
gl::RGBA,
gl::UNSIGNED_BYTE,
pixels.as_ptr() as *const c_void,
);
gl::GenerateMipmap(gl::TEXTURE_2D);
}
Ok(Texture { image_id, options })
}
}
#[derive(Clone, Debug)]
pub struct TextureOptions {
wrap_s: WrapStyle,
wrap_t: WrapStyle,
border: Option<(i32, Vec4)>,
mag_filter: FilterStyle,
min_filter: FilterStyle,
min_mipmap_filter: Option<FilterStyle>,
mag_mipmap_filter: Option<FilterStyle>,
flip_vertically: bool,
}
impl Default for TextureOptions {
fn default() -> Self {
TextureOptions {
wrap_s: WrapStyle::Repeat,
wrap_t: WrapStyle::Repeat,
border: None,
mag_filter: FilterStyle::Linear,
min_filter: FilterStyle::Linear,
min_mipmap_filter: None,
mag_mipmap_filter: None,
flip_vertically: true,
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum TextureSlot {
Slot0 = gl::TEXTURE0,
Slot1 = gl::TEXTURE1,
Slot2 = gl::TEXTURE2,
Slot3 = gl::TEXTURE3,
Slot4 = gl::TEXTURE4,
Slot5 = gl::TEXTURE5,
Slot6 = gl::TEXTURE6,
Slot7 = gl::TEXTURE7,
Slot8 = gl::TEXTURE8,
Slot9 = gl::TEXTURE9,
Slot10 = gl::TEXTURE10,
Slot11 = gl::TEXTURE11,
Slot12 = gl::TEXTURE12,
Slot13 = gl::TEXTURE13,
Slot14 = gl::TEXTURE14,
Slot15 = gl::TEXTURE15,
Slot16 = gl::TEXTURE16,
Slot17 = gl::TEXTURE17,
Slot18 = gl::TEXTURE18,
Slot19 = gl::TEXTURE19,
Slot20 = gl::TEXTURE20,
Slot21 = gl::TEXTURE21,
Slot22 = gl::TEXTURE22,
Slot23 = gl::TEXTURE23,
Slot24 = gl::TEXTURE24,
Slot25 = gl::TEXTURE25,
Slot26 = gl::TEXTURE26,
Slot27 = gl::TEXTURE27,
Slot28 = gl::TEXTURE28,
Slot29 = gl::TEXTURE29,
Slot30 = gl::TEXTURE30,
Slot31 = gl::TEXTURE31,
}
impl Texture {
pub fn enable(&self, slot: TextureSlot) {
unsafe {
gl::ActiveTexture(slot as u32);
gl::BindTexture(gl::TEXTURE_2D, self.image_id);
}
}
}