nd_vector 0.1.0

[WIP] Lengthen! Shrink! Iterate! Scale! Twist and turn to your imagination along any dimension on a vector!
Documentation
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
    }
}