use crate::gl_utils::{compile_shader, link_shader_program, create_buffer_f32};
use crate::image::ImageRef;
use crate::renderers::{Renderer, IntRect};
type Error = Box<dyn std::error::Error>;
pub struct ImageTexture {
texture_id: u32,
size: (u32, u32),
}
impl ImageTexture {
pub fn new(image: ImageRef) -> Self {
let texture_id = image.create_texture().unwrap();
unsafe {
gl::BindTexture(gl::TEXTURE_2D, texture_id);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
}
Self {
texture_id,
size: image.size(),
}
}
pub fn size(&self) -> (u32, u32) {
self.size
}
}
impl Drop for ImageTexture {
fn drop(&mut self) {
unsafe {
gl::DeleteTextures(1, &self.texture_id);
}
}
}
pub struct ImageRenderer {
renderer: _ImageRenderer,
viewport_rect: IntRect,
texture: Option<ImageTexture>,
}
impl ImageRenderer {
pub fn new(viewport_rect: IntRect) -> Result<Self, Error> {
let renderer = _ImageRenderer::new()?;
Ok(Self {
renderer,
viewport_rect,
texture: None,
})
}
pub fn set_render_quad(&mut self, vertices: &[f32]) {
self.renderer.set_render_quad(vertices);
}
pub fn reset_render_quad(&mut self) {
self.renderer.reset_render_quad();
}
pub fn replace_texture(&mut self, texture: ImageTexture) -> Option<ImageTexture> {
let old_texture = self.texture.take();
self.texture = Some(texture);
old_texture
}
}
impl Renderer for ImageRenderer {
fn set_viewport(&mut self, viewport_rect: IntRect) {
self.viewport_rect = viewport_rect;
}
fn render(&self) {
if let Some(ref texture) = self.texture {
self.viewport_rect.gl_viewport();
self.renderer.render(texture);
}
}
}
struct _ImageRenderer {
program: u32,
vao: u32,
vbo: u32,
}
impl _ImageRenderer {
pub fn new() -> Result<Self, Error> {
let vcode = include_str!("shaders/vertex_shader.glsl");
let fcode = include_str!("shaders/fragment_shader.glsl");
let vshader = compile_shader(vcode, gl::VERTEX_SHADER)?;
let fshader = compile_shader(fcode, gl::FRAGMENT_SHADER)?;
let shaders = &[vshader, fshader];
let program = link_shader_program(shaders)?;
let vertices: &[f32] = &[
-1.0, 1.0,
1.0, 1.0,
1.0, -1.0,
-1.0, -1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
];
let vbo = create_buffer_f32(vertices, gl::DYNAMIC_DRAW)?;
let mut vao = 0;
unsafe {
gl::GenVertexArrays(1, &mut vao);
gl::BindVertexArray(vao);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
let stride = 0;
let offset = 0 as *const _;
gl::VertexAttribPointer(0, 2, gl::FLOAT, gl::FALSE, stride, offset);
gl::EnableVertexAttribArray(0);
let offset = (8 * std::mem::size_of::<f32>()) as *const _;
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE, stride, offset);
gl::EnableVertexAttribArray(1);
}
Ok(Self {
program,
vao,
vbo,
})
}
pub unsafe fn render_raw_texture(&self, texture_id: u32) {
unsafe {
gl::UseProgram(self.program);
gl::BindTexture(gl::TEXTURE_2D, texture_id);
gl::BindVertexArray(self.vao);
gl::DrawArrays(gl::TRIANGLE_FAN, 0, 4);
}
}
pub fn render(&self, texture: &ImageTexture) {
unsafe {
self.render_raw_texture(texture.texture_id);
}
}
pub fn set_render_quad(&mut self, vertices: &[f32]) {
if vertices.len() != 8 {
panic!("Invalid number of vertices");
}
unsafe {
gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
gl::BufferSubData(gl::ARRAY_BUFFER, 0, (vertices.len() * std::mem::size_of::<f32>()) as isize, vertices.as_ptr() as _);
}
}
pub fn reset_render_quad(&mut self) {
let vertices: &[f32] = &[
-1.0, 1.0,
1.0, 1.0,
1.0, -1.0,
-1.0, -1.0,
];
self.set_render_quad(vertices);
}
}
impl Drop for _ImageRenderer {
fn drop(&mut self) {
unsafe {
gl::DeleteProgram(self.program);
gl::DeleteVertexArrays(1, &self.vao);
gl::DeleteBuffers(1, &self.vbo);
}
}
}