use std::iter::zip; use bevy::{prelude::*, render::{mesh::{Indices, PrimitiveTopology}, render_asset::RenderAssetUsages}}; use vector_grid::prelude::*; use cube_mesher::*; pub const SIDE_ROTATION_ORDER: [[usize; 4]; 4] = [ [0, 1, 2, 3], [1, 3, 0, 2], [3, 2, 1, 0], [2, 0, 3, 1], ]; #[derive(Default, Clone, Copy)] pub enum BlockType { #[default] Air, Dirt, Grass, Stone, Log, Leaves, Water, } impl BlockType { fn sides(&self) -> [BlockSide; 6] { match self { BlockType::Air => panic!(), BlockType::Dirt => [ BlockSide { rotation: 0, texture_index: 0 }; 6 ], BlockType::Grass => [ BlockSide { rotation: 0, texture_index: 1 }, BlockSide { rotation: 1, texture_index: 1 }, BlockSide { rotation: 0, texture_index: 0 }, BlockSide { rotation: 0, texture_index: 2 }, BlockSide { rotation: 1, texture_index: 1 }, BlockSide { rotation: 0, texture_index: 1 }, ], BlockType::Stone => [ BlockSide { rotation: 0, texture_index: 3 }; 6 ], BlockType::Log => [ BlockSide { rotation: 0, texture_index: 4 }, BlockSide { rotation: 1, texture_index: 4 }, BlockSide { rotation: 0, texture_index: 5 }, BlockSide { rotation: 0, texture_index: 5 }, BlockSide { rotation: 1, texture_index: 4 }, BlockSide { rotation: 0, texture_index: 4 }, ], BlockType::Leaves => [ BlockSide { rotation: 0, texture_index: 6 }; 6 ], BlockType::Water => [ BlockSide { rotation: 0, texture_index: 7 }; 6 ], } } } #[derive(Clone, Copy)] struct BlockSide { rotation: u8, texture_index: u8, } #[derive(Clone, Copy)] pub struct Block { pub block_type: BlockType, } impl Default for Block { fn default() -> Self { Self { block_type: default() } } } impl vector_grid::Air for Block { fn is_air(&self) -> bool { match self.block_type { BlockType::Air => true, _ => false, } } } impl vector_grid::Transparent for Block { fn is_transparent(&self) -> bool { match self.block_type { BlockType::Air => true, BlockType::Leaves => true, BlockType::Water => true, _ => false } } } impl VoxelMesher for Block { fn generate(&self, visible_sides: [bool; 6]) -> Mesh { let mut result = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default()) .with_inserted_indices(Indices::U32(vec![])) .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vec![Vec3::ZERO; 0]) .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vec![Vec3::ZERO; 0]) .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![Vec2::ZERO; 0]); for (side_n, (is_visible, side)) in zip(visible_sides, self.block_type.sides()).enumerate() { if is_visible { let mut uv = Vec::new(); let coordinate = Vec2::new( (side.texture_index % 4) as f32 / 4.0, (side.texture_index / 4) as f32 / 4.0, ); for corner in 0..4 { uv.push(SIDE_UV[SIDE_ROTATION_ORDER[side.rotation as usize][corner]] / 4.0 + coordinate); } let side_mesh = generate_side_mesh(side_n) .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uv); result.merge(side_mesh); } } result } }