Theme

alex/beta-minecraft-rust

Minecraft Beta 1.7.3 Rewrite

BRANCH main
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
Download file

root / crates / client / src / render / scene / vehicles.rs

use std::f32::consts::{FRAC_PI_2, PI};

use common::entity::vehicle::{self, VehicleKind};
use common::math::sin;
use glam::{Mat3, Mat4, Vec3};

use super::{
    Geometry,
    models::{Model, Part},
};
use crate::entities::RemoteEntity;

impl Geometry {
    pub(super) fn vehicle(
        &mut self,
        world: &crate::world::ClientWorld,
        kind: VehicleKind,
        entity: &RemoteEntity,
        mut position: Vec3,
        partial: f32,
        brightness: f32,
    ) {
        let boat = kind == VehicleKind::Boat;
        let previous = entity.previous_animation.rotation[0];
        let mut yaw = super::models::angle(previous, entity.animation.rotation[0], partial);
        let mut pitch = 0.0;
        let interpolated = entity.previous.lerp(entity.position, f64::from(partial));
        if !boat && let Some(snap) = vehicle::rail_position(world, interpolated) {
            let [ahead, behind] = [0.3_f32, -0.3].map(|offset| {
                vehicle::rail_offset(world, interpolated, f64::from(offset)).unwrap_or(snap)
            });
            position += (snap.with_y((ahead.y + behind.y) / 2.0) - interpolated).as_vec3();
            let direction = behind - ahead;
            if direction.length_squared() > 0.0 {
                let direction = direction.normalize();
                yaw = direction.z.atan2(direction.x).to_degrees() as f32;
                pitch = (direction.y.atan() * 73.0) as f32;
            }
        }
        let pose = entity.animation.vehicle;
        let hit = pose.hit as f32 - partial;
        let damage = (pose.damage as f32 - partial).max(0.0);
        let rock = if hit > 0.0 {
            (sin(hit) * hit * damage / 10.0 * pose.direction as f32).to_radians()
        } else {
            0.0
        };
        let rotation = Mat3::from_rotation_y((180.0 - yaw).to_radians())
            * Mat3::from_rotation_z(-pitch.to_radians())
            * Mat3::from_rotation_x(rock);
        if matches!(kind, VehicleKind::StorageCart | VehicleKind::PoweredCart) {
            let block = if kind == VehicleKind::StorageCart {
                common::world::Block::CHEST
            } else {
                common::world::Block::FURNACE
            };
            let content = rotation * Mat3::from_rotation_y(FRAC_PI_2);
            self.cuboid(
                Vec3::splat(-0.5),
                Vec3::splat(0.5),
                |point| {
                    position + rotation * Vec3::Y * (0.75 * 5.0 / 16.0) + content * point * 0.75
                },
                std::array::from_fn(|side| common::world::texture::inventory_face(block, 0, side)),
                [brightness; 6],
            );
        }
        let texture = crate::assets::entity_texture(if boat {
            "item/boat.png"
        } else {
            "item/cart.png"
        });
        let mut model = Model {
            position,
            transform: rotation * Mat3::from_diagonal(Vec3::new(-1.0, -1.0, 1.0) / 16.0),
            ..Model::new(self, Mat4::IDENTITY, texture, brightness)
        };
        let (min, size, [x, z]) = if boat {
            model.part(
                Part::new(
                    [-12.0, -8.0, -3.0],
                    [24.0, 16.0, 4.0],
                    [0.0, 4.0, 0.0],
                    [0.0, 8.0],
                )
                .rotate([FRAC_PI_2, 0.0, 0.0]),
            );
            ([-10.0, -7.0, -1.0], [20.0, 6.0, 2.0], [11.0, 9.0])
        } else {
            model.part(
                Part::new(
                    [-10.0, -8.0, -1.0],
                    [20.0, 16.0, 2.0],
                    [0.0, 4.0, 0.0],
                    [0.0, 10.0],
                )
                .rotate([FRAC_PI_2, 0.0, 0.0]),
            );
            model.part(
                Part::new(
                    [-9.0, -7.0, -1.0],
                    [18.0, 14.0, 1.0],
                    [0.0, 4.1, 0.0],
                    [44.0, 10.0],
                )
                .rotate([-FRAC_PI_2, 0.0, 0.0]),
            );
            ([-8.0, -9.0, -1.0], [16.0, 8.0, 2.0], [9.0, 7.0])
        };
        for (pivot, yaw) in [
            ([-x, 4.0, 0.0], PI * 1.5),
            ([x, 4.0, 0.0], FRAC_PI_2),
            ([0.0, 4.0, -z], PI),
            ([0.0, 4.0, z], 0.0),
        ] {
            model.part(Part::new(min, size, pivot, [0.0; 2]).rotate([0.0, yaw, 0.0]));
        }
    }
}