use rin_graphics::{self as graphics, Vertex2DTex3D};
pub use glin::cubemap::*;
use glin::RenderSurface;
use super::{Renderer, Renderer2d, Render2d};
use glin::{gl, gl::types::*};
use glin::uniforms;
use rin_math::{vec2, vec3, Pnt2, Vec2, Vec3, ToVec, zero};
impl<'a> Render2d for &'a glin::CubeMap{
type Material = Material<'a>;
fn default_material(&self) -> Material<'a>{
Material::new(self)
}
fn render_with_material<R: RenderSurface, M: super::Material>(&self, gl: &Renderer<R>, pos: &Pnt2, material: &M){
self.render_size_with_material(gl, pos, &vec2(self.width() as f32, self.height() as f32), material);
}
fn render_size_with_material<R: RenderSurface, M: super::Material>(&self, gl: &Renderer<R>, pos: &Pnt2, size: &Vec2, material: &M){
let mesh = unwraped_mesh(pos, size, gl.origin());
gl.draw_mesh_with_material(&mesh, material);
}
}
#[derive(Copy,Clone)]
pub struct Level<'a>{
pub cubemap: &'a glin::CubeMap,
pub level: f32,
}
impl<'a> Render2d for Level<'a>{
type Material = Material<'a>;
fn default_material(&self) -> Material<'a>{
Material::from_level(*self)
}
fn render_with_material<R: RenderSurface, M: super::Material>(&self, gl: &Renderer<R>, pos: &Pnt2, material: &M){
self.cubemap.render_with_material(gl, pos, material);
}
fn render_size_with_material<R: RenderSurface, M: super::Material>(&self, gl: &Renderer<R>, pos: &Pnt2, size: &Vec2, material: &M){
self.cubemap.render_size_with_material(gl, pos, size, material);
}
}
#[derive(Copy,Clone)]
pub struct Face<'a>{
pub cubemap: &'a glin::CubeMap,
pub level: f32,
pub face: GLenum,
}
impl<'a> Render2d for Face<'a>{
type Material = Material<'a>;
fn default_material(&self) -> Material<'a>{
Material::from_level(Level{
cubemap: self.cubemap,
level: self.level
})
}
fn render_with_material<R: RenderSurface, M: super::Material>(&self, gl: &Renderer<R>, pos: &Pnt2, material: &M){
self.render_size_with_material(gl, pos, &vec2(self.cubemap.width() as f32, self.cubemap.height() as f32), material);
}
fn render_size_with_material<R: RenderSurface, M: super::Material>(&self, gl: &Renderer<R>, pos: &Pnt2, size: &Vec2, material: &M){
let mesh = face_mesh(self.face, pos, size, gl.origin());
gl.draw_mesh_with_material(&mesh, material);
}
}
pub struct Material<'a>{
_cubemap: &'a glin::CubeMap,
uniforms: Vec<glin::program::Uniform>,
}
impl<'a> Material<'a>{
pub fn new(cubemap: &glin::CubeMap) -> Material{
let uniforms = uniforms!{
cubemap: cubemap,
level: -1.0,
};
Material{
_cubemap: cubemap,
uniforms,
}
}
pub fn from_level(level: Level) -> Material{
let uniforms = uniforms!{
cubemap: level.cubemap,
level: level.level,
};
Material{
_cubemap: level.cubemap,
uniforms,
}
}
}
impl<'a> super::Material for Material<'a>{
fn program<R: RenderSurface>(&self, renderer: &Renderer<R>) -> &glin::Program{
get_program(renderer)
}
fn uniforms<R: RenderSurface>(&self, _renderer: &Renderer<R>) -> &[glin::program::Uniform]{
&self.uniforms
}
fn properties(&self) -> &[glin::Property]{
&[]
}
}
program_cache!(glin::program::Settings{
version: crate::default_glsl_version(),
precision: glin::program::ShaderPrecision::High,
shaders: vec![
(gl::VERTEX_SHADER, include_str!("shaders/vertex_cubemap.glsl")),
(gl::FRAGMENT_SHADER, include_str!("shaders/fragment_cubemap.glsl")),
],
bindings: crate::default_attribute_bindings().clone(),
.. Default::default()
}, get_program, CUBEMAP_SHADER);
geometry_cache!(Vertex2DTex3D, unwraped_mesh(&Pnt2::origin(), &zero(), rin_graphics::CoordinateOrigin::BottomLeft));
fn tex_coords(face: GLenum) -> Vec<Vec3>{
let l = 1.0 / 3.0f32.sqrt();
match face{
gl::TEXTURE_CUBE_MAP_NEGATIVE_X => vec![
vec3(-l,-l,-l),
vec3(-l,-l,l),
vec3(-l,l,l),
vec3(-l,l,l),
vec3(-l,l,-l),
vec3(-l,-l,-l),
],
gl::TEXTURE_CUBE_MAP_POSITIVE_Z => vec![
vec3(-l,-l,l),
vec3(l,-l,l),
vec3(l,l,l),
vec3(l,l,l),
vec3(-l,l,l),
vec3(-l,-l,l),
],
gl::TEXTURE_CUBE_MAP_POSITIVE_X => vec![
vec3(l,-l,l),
vec3(l,-l,-l),
vec3(l,l,-l),
vec3(l,l,-l),
vec3(l,l,l),
vec3(l,-l,l),
],
gl::TEXTURE_CUBE_MAP_NEGATIVE_Z => vec![
vec3(l,-l,-l),
vec3(-l,-l,-l),
vec3(-l,l,-l),
vec3(-l,l,-l),
vec3(l,l,-l),
vec3(l,-l,-l),
],
gl::TEXTURE_CUBE_MAP_POSITIVE_Y => vec![
vec3(-l,l,l),
vec3(l,l,l),
vec3(l,l,-l),
vec3(l,l,-l),
vec3(-l,l,-l),
vec3(-l,l,l),
],
gl::TEXTURE_CUBE_MAP_NEGATIVE_Y => vec![
vec3(-l,-l,-l),
vec3(l,-l,-l),
vec3(l,-l,l),
vec3(l,-l,l),
vec3(-l,-l,l),
vec3(-l,-l,-l),
],
_ => panic!("Wrong face!!")
}
}
pub fn face_mesh(face: GLenum, pos: &Pnt2, size: &Vec2, coordinate_origin: graphics::CoordinateOrigin) -> graphics::Mesh<graphics::Vertex2DTex3D>{
let pos = pos.to_vec();
let tex_coords = tex_coords(face);
let vertices = match coordinate_origin{
graphics::CoordinateOrigin::BottomLeft | graphics::CoordinateOrigin::CenterUp=> vec![
graphics::vertex2dtex3d(vec2(pos.x, pos.y), tex_coords[0]),
graphics::vertex2dtex3d(vec2(pos.x + size.x, pos.y), tex_coords[1]),
graphics::vertex2dtex3d(vec2(pos.x + size.x, pos.y + size.y), tex_coords[2]),
graphics::vertex2dtex3d(vec2(pos.x + size.x, pos.y + size.y), tex_coords[3]),
graphics::vertex2dtex3d(vec2(pos.x, pos.y + size.y), tex_coords[4]),
graphics::vertex2dtex3d(vec2(pos.x, pos.y), tex_coords[5]),
],
graphics::CoordinateOrigin::TopLeft | graphics::CoordinateOrigin::CenterDown => vec![
graphics::vertex2dtex3d(vec2(pos.x, pos.y + size.y), tex_coords[0]),
graphics::vertex2dtex3d(vec2(pos.x + size.x, pos.y + size.y), tex_coords[1]),
graphics::vertex2dtex3d(vec2(pos.x + size.x, pos.y), tex_coords[2]),
graphics::vertex2dtex3d(vec2(pos.x + size.x, pos.y), tex_coords[3]),
graphics::vertex2dtex3d(vec2(pos.x, pos.y), tex_coords[4]),
graphics::vertex2dtex3d(vec2(pos.x, pos.y + size.y), tex_coords[5]),
],
};
graphics::mesh(vertices, graphics::PrimitiveType::Triangles)
}
pub fn unwraped_mesh(pos: &Pnt2, size: &Vec2, orig: graphics::CoordinateOrigin) -> graphics::Mesh<graphics::Vertex2DTex3D>{
let faces = match orig{
graphics::CoordinateOrigin::BottomLeft | graphics::CoordinateOrigin::CenterUp => [
(gl::TEXTURE_CUBE_MAP_NEGATIVE_X, vec2(0., size.y)),
(gl::TEXTURE_CUBE_MAP_POSITIVE_Z, vec2(size.x, size.y)),
(gl::TEXTURE_CUBE_MAP_POSITIVE_X, vec2(size.x * 2., size.y)),
(gl::TEXTURE_CUBE_MAP_NEGATIVE_Z, vec2(size.x * 3., size.y)),
(gl::TEXTURE_CUBE_MAP_POSITIVE_Y, vec2(size.x, size.y * 2.)),
(gl::TEXTURE_CUBE_MAP_NEGATIVE_Y, vec2(size.x, 0.)),
],
graphics::CoordinateOrigin::TopLeft | graphics::CoordinateOrigin::CenterDown => [
(gl::TEXTURE_CUBE_MAP_NEGATIVE_X, vec2(0., size.y)),
(gl::TEXTURE_CUBE_MAP_POSITIVE_Z, vec2(size.x, size.y)),
(gl::TEXTURE_CUBE_MAP_POSITIVE_X, vec2(size.x * 2., size.y)),
(gl::TEXTURE_CUBE_MAP_NEGATIVE_Z, vec2(size.x * 3., size.y)),
(gl::TEXTURE_CUBE_MAP_POSITIVE_Y, vec2(size.x, 0.)),
(gl::TEXTURE_CUBE_MAP_NEGATIVE_Y, vec2(size.x, size.y * 2.)),
],
};
let faces = faces.iter().flat_map(|&(face, offset)|{
let (vertices, _) = face_mesh(face, pos, size, orig).into();
vertices.into_iter()
.map(move |vertex| graphics::vertex2dtex3d(vertex.position + offset, vertex.texcoord))
}).collect();
graphics::mesh(faces, graphics::PrimitiveType::Triangles)
}