alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
root crates client src render item.rs
use common::world::{Block, Shape, texture};
use glam::{BVec3, Vec3};
pub struct Face {
pub points: [Vec3; 4],
pub uv: [[f32; 2]; 4],
pub shade: f32,
}
pub fn in_3d(block: Block) -> bool {
block.properties().is_some_and(|p| {
matches!(
p.shape,
Shape::Cube | Shape::Stairs | Shape::Fence | Shape::Cactus | Shape::PistonBase
)
})
}
pub fn tint(block: Block, metadata: u8) -> u32 {
match (block, metadata & 3) {
(Block::LEAVES, 1 | 3) => 6396257,
(Block::LEAVES, 2) => 8431445,
(Block::LEAVES, _) => 4764952,
_ => 0xffffff,
}
}
pub fn color(tint: u32, brightness: f32) -> u32 {
let channel =
|shift: u32| (((tint >> shift) & 255) as f32 * brightness).clamp(0.0, 255.0) as u32;
0xff000000 | channel(16) | (channel(8) << 8) | (channel(0) << 16)
}
pub fn faces(block: Block, metadata: u8) -> Vec<Face> {
let mut faces = Vec::with_capacity(24);
let mut cuboid = |min: [f32; 3], max: [f32; 3]| {
let (min, max) = (Vec3::from_array(min), Vec3::from_array(max));
// Per side, the corners whose bits 4, 2 and 1 pick the maximum x, y and z
for (side, corners) in [
[1, 0, 4, 5],
[2, 3, 7, 6],
[6, 4, 0, 2],
[3, 1, 5, 7],
[2, 0, 1, 3],
[7, 5, 4, 6],
]
.into_iter()
.enumerate()
{
let mut points = corners.map(|bits: u8| {
Vec3::select(
BVec3::new(bits & 4 != 0, bits & 2 != 0, bits & 1 != 0),
max,
min,
)
});
let tile = texture::inventory_face(block, metadata, side);
let origin = [f32::from(tile & 15) / 16.0, f32::from(tile >> 4) / 16.0];
let uv = points.map(|p| {
let (u, v) = match side {
0 | 1 => (p.x, p.z),
2 => (1.0 - p.x, 1.0 - p.y),
3 => (p.x, 1.0 - p.y),
4 => (p.z, 1.0 - p.y),
_ => (1.0 - p.z, 1.0 - p.y),
};
[
origin[0] + u.clamp(0.0, 0.999375) / 16.0,
origin[1] + v.clamp(0.0, 0.999375) / 16.0,
]
});
if block == Block::CACTUS && side >= 2 {
let axis = if side < 4 { 2 } else { 0 };
for p in &mut points {
p[axis] += if side % 2 == 0 { 0.0625 } else { -0.0625 };
}
}
faces.push(Face {
points: points.map(|p| p - Vec3::splat(0.5)),
uv,
shade: [0.5, 1.0, 0.8, 0.8, 0.6, 0.6][side],
});
}
};
match block.properties().map(|p| p.shape) {
Some(Shape::Stairs) => {
cuboid([0.0, 0.0, 0.0], [1.0, 1.0, 0.5]);
cuboid([0.0, 0.0, 0.5], [1.0, 0.5, 1.0]);
}
Some(Shape::Fence) => {
cuboid([0.375, 0.0, 0.0], [0.625, 1.0, 0.25]);
cuboid([0.375, 0.0, 0.75], [0.625, 1.0, 1.0]);
cuboid([0.4375, 0.8125, -0.125], [0.5625, 0.9375, 1.125]);
cuboid([0.4375, 0.3125, -0.125], [0.5625, 0.4375, 1.125]);
}
_ if block == Block::SLAB => cuboid([0.0; 3], [1.0, 0.5, 1.0]),
_ if block == Block::FARMLAND => cuboid([0.0; 3], [1.0, 0.9375, 1.0]),
_ if block == Block::TRAPDOOR => cuboid([0.0, 0.40625, 0.0], [1.0, 0.59375, 1.0]),
_ if block == Block::SNOW_LAYER => cuboid([0.0; 3], [1.0, 0.125, 1.0]),
_ if block == Block::CAKE => cuboid([0.0625, 0.0, 0.0625], [0.9375, 0.5, 0.9375]),
_ if matches!(
block,
Block::STONE_PRESSURE_PLATE | Block::WOODEN_PRESSURE_PLATE
) =>
{
cuboid([0.0, 0.375, 0.0], [1.0, 0.625, 1.0])
}
_ if block == Block::BUTTON => cuboid([0.3125, 0.375, 0.375], [0.6875, 0.625, 0.625]),
_ => cuboid([0.0; 3], [1.0; 3]),
}
faces
}
/// `Item.getIconFromDamage`: the item's icon, which for dyes depends on the color.
pub fn icon(stack: common::item::ItemStack) -> u8 {
let icon = stack.item.properties().map_or(0, |p| p.icon);
if stack.item == common::item::Item::DYE {
icon.wrapping_add((stack.damage.rem_euclid(8) * 16 + stack.damage.div_euclid(8)) as u8)
} else {
icon
}
}