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
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);
|
|
}
|
|
}
|
|
}
|