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
}
}