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 scene effects.rs
//! `Render.doRenderShadowAndFire`: blob shadows under entities and flames on burning ones.
use common::entity::mob::MobKind;
use common::math::floor_f64;
use common::world::Block;
use glam::{DVec3, Mat3, Vec3};
use super::Geometry;
use crate::entities::Kind;
use crate::world::ClientWorld;
const SHADOW: i32 = crate::assets::entity_texture("misc/shadow.png");
/// Scene texture flag: sample smoothly and clamped, like `%clamp%` textures.
const CLAMP: i32 = 1 << 16;
/// The width, height, `posY - boundingBox.minY` and shadow size of an entity kind.
pub fn dimensions(kind: Kind) -> (f32, f32, f32, f32) {
match kind {
Kind::Painting(_) | Kind::Arrow => (0.5, 0.5, 0.0, 0.0),
Kind::Player => (0.6, 1.8, 0.0, 0.5),
Kind::Mob(mob) => {
let [width, height] = mob.size();
let shadow = match mob {
MobKind::Pig | MobKind::Cow | MobKind::Sheep | MobKind::Squid => 0.7,
MobKind::Slime => 0.25,
MobKind::Giant => 3.0,
MobKind::Chicken => 0.3,
MobKind::Spider => 1.0,
_ => 0.5,
};
(width, height, 0.0, shadow)
}
Kind::Item(_) => (0.25, 0.25, 0.125, 0.15),
Kind::Falling(_) | Kind::Tnt => (0.98, 0.98, 0.49, 0.5),
Kind::Fireball => (1.0, 1.0, 0.0, 0.0),
Kind::Vehicle(kind) => {
let [width, height] = kind.size();
(width, height, kind.y_offset(), 0.5)
}
Kind::Hook(_) | Kind::Thrown(_) => (0.25, 0.25, 0.0, 0.0),
}
}
impl Geometry {
/// `renderShadow`: a blob on the tops of the solid blocks below the entity, fading with
/// height and distance.
pub(super) fn shadow(
&mut self,
world: &ClientWorld,
position: DVec3,
eye: DVec3,
(height, size, opaque): (f32, f32, f64),
sky_darkness: u32,
) {
let opacity = (1.0 - position.distance_squared(eye) / 256.0) * opaque;
if opacity <= 0.0 || size <= 0.0 {
return;
}
let size = f64::from(size);
let center = position + DVec3::Y * f64::from(height / 2.0);
for x in floor_f64(center.x - size)..=floor_f64(center.x + size) {
for y in floor_f64(center.y - size)..=floor_f64(center.y) {
for z in floor_f64(center.z - size)..=floor_f64(center.z + size) {
use common::world::shape::BlockView;
let below = world.block(x, y - 1, z);
let point = DVec3::new(f64::from(x), f64::from(y), f64::from(z)) + 0.5;
let light = world.light_level(point.x, point.y, point.z, sky_darkness);
if below.is_air() || light <= 3 || !below.properties().is_some_and(|p| p.normal)
{
continue;
}
let brightness = f64::from(world.brightness[usize::from(light)]);
let alpha = (opacity - (center.y - f64::from(y)) / 2.0) * 0.5 * brightness;
if alpha < 0.0 {
continue;
}
let (x0, x1) = (f64::from(x), f64::from(x + 1));
let (z0, z1) = (f64::from(z), f64::from(z + 1));
let top = f64::from(y) + 1.0 / 64.0;
let corners = [(x0, z0), (x0, z1), (x1, z1), (x1, z0)];
let points = corners.map(|(wx, wz)| (DVec3::new(wx, top, wz) - eye).as_vec3());
let uv = corners.map(|(wx, wz)| {
[center.x - wx, center.z - wz].map(|d| (d / 2.0 / size + 0.5) as f32)
});
let color = ((alpha.min(1.0) * 255.0) as u32) << 24 | 0xffffff;
self.quad_uv(points, uv, SHADOW | CLAMP, color);
}
}
}
}
/// `renderEntityOnFire`: layers of fire facing the camera, narrowing upwards.
pub(super) fn entity_fire(
&mut self,
relative: Vec3,
(width, height, offset): (f32, f32, f32),
view_yaw: f32,
) {
let tile = Block::FIRE.properties().map_or(0, |p| p.texture);
let (tx, ty) = (f32::from(tile & 15) * 16.0, f32::from(tile & 0xF0));
let scale = width * 1.4;
let mut remaining = height / scale;
let rotation = Mat3::from_rotation_y((-view_yaw).to_radians());
let shift = Vec3::new(0.0, 0.0, -0.3 + (remaining as i32) as f32 * 0.02);
let (mut half, mut bottom, mut depth) = (0.5, offset, 0.0);
let mut layer = 0;
while remaining > 0.0 {
let v0 = if layer % 2 == 0 { ty } else { ty + 16.0 };
let (v0, v1) = (v0 / 256.0, (v0 + 15.99) / 256.0);
let (mut u0, mut u1) = (tx / 256.0, (tx + 15.99) / 256.0);
if layer / 2 % 2 == 0 {
(u0, u1) = (u1, u0);
}
let place =
|x: f32, y: f32| relative + rotation * ((Vec3::new(x, y, depth) + shift) * scale);
let points = [
place(half, -bottom),
place(-half, -bottom),
place(-half, 1.4 - bottom),
place(half, 1.4 - bottom),
];
self.quad_uv(
points,
[[u1, v1], [u0, v1], [u0, v0], [u1, v0]],
0,
0xffffffff,
);
remaining -= 0.45;
bottom -= 0.45;
half *= 0.9;
depth += 0.03;
layer += 1;
}
}
}