use core::ffi::c_void;
use image::EncodableLayout as _;
pub struct Texture {
gl_id: u32,
}
impl Texture {
#[expect(
clippy::missing_inline_in_public_items,
reason = "Long function, probably shouldn't be inlined for compile times and binary size reasons."
)]
pub fn load_bytes(width: u32, bytes: &[u8]) -> Result<Texture, String> {
let mut gl_id = 0;
unsafe {
gl::GenTextures(1, &raw mut gl_id);
}
unsafe {
gl::BindTexture(gl::TEXTURE_2D, gl_id);
}
#[expect(
clippy::as_conversions,
clippy::cast_possible_wrap,
reason = "We are casting constants, impossible to cause issues."
)]
unsafe {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32);
};
#[expect(
clippy::as_conversions,
clippy::cast_possible_wrap,
reason = "We are casting constants, impossible to cause issues."
)]
unsafe {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
};
#[expect(
clippy::as_conversions,
clippy::cast_possible_wrap,
reason = "We are casting constants, impossible to cause issues."
)]
unsafe {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
};
#[expect(
clippy::as_conversions,
clippy::cast_possible_wrap,
reason = "We are casting constants, impossible to cause issues."
)]
unsafe {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
};
unsafe {
#[expect(
clippy::borrow_as_ptr,
clippy::indexing_slicing,
clippy::as_conversions,
reason = "can't find other way to specify pixels field"
)]
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGB
.try_into()
.map_err(|_e| "gl::RGB returned garbage data which overflowed")?,
width
.try_into()
.map_err(|_e| "image width too large, led to overflow")?,
width
.try_into()
.map_err(|_e| "image width too large, led to overflow")?,
0,
gl::RGBA,
gl::UNSIGNED_BYTE,
(&bytes[0] as *const u8).cast::<c_void>(),
);
};
unsafe {
gl::GenerateMipmap(gl::TEXTURE_2D);
};
Ok(Texture { gl_id })
}
#[inline]
pub fn load_file(path: &str) -> Result<Texture, String> {
use std::path::Path;
let img = image::open(Path::new(path))
.map_err(|err| format!("Realms: could not open image file {path}: {err}"))?;
let img = img.flipv();
let rgba_data = img.to_rgba8();
let data = rgba_data.as_bytes();
Texture::load_bytes(img.width(), data)
}
#[inline]
pub fn bind(&self) {
unsafe {
gl::BindTexture(gl::TEXTURE_2D, self.gl_id);
}
}
}