extern crate gltf;

use nalgebra_glm as glm;

use glium::{ VertexBuffer, IndexBuffer };
use glium::texture::SrgbTexture2d;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 3],
    normal: [f32; 3],
    uv: [f32; 2],
}

implement_vertex!(Vertex, position, normal, uv);

pub struct Model {
    vb: VertexBuffer<Vertex>,
    ib: IndexBuffer<u32>,
    texture: SrgbTexture2d,
}

impl Model {
    pub fn new(display: &glium::Display, file: &str, image_file: &str) -> Self {
	let (document, buffers, _images) = gltf::import(file).expect("Could not load gltf file");
	let mesh = document.meshes().next().unwrap();
	let primitive = mesh.primitives().next().unwrap();
	let reader = primitive.reader(|buffer| Some(&buffers[buffer.index()]));

	let mut vertices: Vec<Vertex> = Vec::new();
	let positions = reader.read_positions().unwrap();
	let normals = reader.read_normals().unwrap();
	let uvs = reader.read_tex_coords(0).unwrap().into_f32();
	    
	for ((position, normal), uv) in positions.zip(normals).zip(uvs) {
	    vertices.push(Vertex { position, normal, uv});
	}   
	let vb = VertexBuffer::new(display, &vertices).unwrap();
	
	let indices: Vec<u32> = reader.read_indices().unwrap().into_u32().collect();
	let ib = IndexBuffer::new(display, glium::index::PrimitiveType::TrianglesList, &indices).unwrap();

	let image = image::io::Reader::open(image_file).unwrap().decode().unwrap().to_rgba8();
	let image_dimensions = image.dimensions();
	let image = glium::texture::RawImage2d::from_raw_rgba_reversed(&image.into_raw(), image_dimensions);
	let texture = glium::texture::SrgbTexture2d::new(display, image).unwrap();

	Model { vb, ib, texture }
    }

    pub fn draw(&self,
		target: &mut impl glium::Surface,
		program: &glium::Program,
		mvp: &glm::Mat4,
		params: &glium::DrawParameters
    ) {
	let uniforms = uniform! {
	    MVP: *mvp.as_ref(),
	    tex: glium::uniforms::Sampler::new(&self.texture),
	};

	target.draw(&self.vb, &self.ib, program, &uniforms, params).unwrap()
    }
}
