use super::{ super::{Pipeline, TgtColorFmt, TgtDepthStencilFmt}, shadow, terrain, Globals, Light, Shadow, }; use core::fmt; use gfx::{ self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner, gfx_vertex_struct_meta, state::ColorMask, }; use vek::*; gfx_defines! { vertex Vertex { pos: [f32; 3] = "v_pos", // Because we try to restrict terrain sprite data to a 128×128 block // we need an offset into the texture atlas. atlas_pos: u32 = "v_atlas_pos", // ____BBBBBBBBGGGGGGGGRRRRRRRR // col: u32 = "v_col", // ...AANNN // A = AO // N = Normal norm_ao: u32 = "v_norm_ao", } constant Locals { // Each matrix performs rotatation, translation, and scaling, relative to the sprite // origin, for all sprite instances. The matrix will be in an array indexed by the // sprite instance's orientation (0 through 7). mat: [[f32; 4]; 4] = "mat", wind_sway: [f32; 4] = "wind_sway", offs: [f32; 4] = "offs", scale: f32 = "scale", } vertex/*constant*/ Instance { // Terrain block position and orientation pos_ori: u32 = "inst_pos_ori", inst_mat0: [f32; 4] = "inst_mat0", inst_mat1: [f32; 4] = "inst_mat1", inst_mat2: [f32; 4] = "inst_mat2", inst_mat3: [f32; 4] = "inst_mat3", inst_light: [f32; 4] = "inst_light", inst_wind_sway: f32 = "inst_wind_sway", scale: f32 = "inst_scale", } pipeline pipe { vbuf: gfx::VertexBuffer = (), ibuf: gfx::InstanceBuffer = (), col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light", locals: gfx::ConstantBuffer = "u_locals", // A sprite instance is a cross between a sprite and a terrain chunk. terrain_locals: gfx::ConstantBuffer = "u_terrain_locals", globals: gfx::ConstantBuffer = "u_globals", lights: gfx::ConstantBuffer = "u_lights", shadows: gfx::ConstantBuffer = "u_shadows", point_shadow_maps: gfx::TextureSampler = "t_point_shadow_maps", directed_shadow_maps: gfx::TextureSampler = "t_directed_shadow_maps", alt: gfx::TextureSampler<[f32; 2]> = "t_alt", horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", noise: gfx::TextureSampler = "t_noise", // Shadow stuff light_shadows: gfx::ConstantBuffer = "u_light_shadows", tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, // tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))), } } impl fmt::Display for Vertex { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Vertex") .field("pos", &Vec3::::from(self.pos)) .field( "atlas_pos", &Vec2::new(self.atlas_pos & 0xFFFF, (self.atlas_pos >> 16) & 0xFFFF), ) .field("norm_ao", &self.norm_ao) .finish() } } impl Vertex { // NOTE: Limit to 16 (x) × 16 (y) × 32 (z). #[allow(clippy::collapsible_else_if)] pub fn new( atlas_pos: Vec2, pos: Vec3, norm: Vec3, /* , col: Rgb, ao: f32 */ ) -> Self { let norm_bits = if norm.x != 0.0 { if norm.x < 0.0 { 0 } else { 1 } } else if norm.y != 0.0 { if norm.y < 0.0 { 2 } else { 3 } } else { if norm.z < 0.0 { 4 } else { 5 } }; Self { // pos_norm: ((pos.x as u32) & 0x003F) // | ((pos.y as u32) & 0x003F) << 6 // | (((pos + EXTRA_NEG_Z).z.max(0.0).min((1 << 16) as f32) as u32) & 0xFFFF) << 12 // | if meta { 1 } else { 0 } << 28 // | (norm_bits & 0x7) << 29, pos: pos.into_array(), atlas_pos: ((atlas_pos.x as u32) & 0xFFFF) | ((atlas_pos.y as u32) & 0xFFFF) << 16, norm_ao: norm_bits, } } } impl Instance { pub fn new( mat: Mat4, wind_sway: f32, pos: Vec3, ori_bits: u8, light: f32, glow: f32, scale: f32, ) -> Self { const EXTRA_NEG_Z: i32 = 32768; let mat_arr = mat.into_col_arrays(); Self { pos_ori: ((pos.x as u32) & 0x003F) | ((pos.y as u32) & 0x003F) << 6 | (((pos + EXTRA_NEG_Z).z.max(0).min(1 << 16) as u32) & 0xFFFF) << 12 | (u32::from(ori_bits) & 0x7) << 29, inst_mat0: mat_arr[0], inst_mat1: mat_arr[1], inst_mat2: mat_arr[2], inst_mat3: mat_arr[3], inst_light: [light, glow, 1.0, 1.0], inst_wind_sway: wind_sway, scale, } } } impl Default for Instance { fn default() -> Self { Self::new(Mat4::identity(), 0.0, Vec3::zero(), 0, 1.0, 0.0, 0.0) } } impl Default for Locals { fn default() -> Self { Self::new(Mat4::identity(), Vec3::one(), Vec3::zero(), 0.0, 1.0) } } impl Locals { pub fn new( mat: Mat4, scale: Vec3, offs: Vec3, wind_sway: f32, integer_scale: f32, ) -> Self { Self { mat: mat.into_col_arrays(), wind_sway: [scale.x, scale.y, scale.z, wind_sway], offs: [offs.x, offs.y, offs.z, 0.0], scale: integer_scale, } } } pub struct SpritePipeline; impl Pipeline for SpritePipeline { type Vertex = Vertex; }