nightshade-api 0.43.0

Procedural high level API for the nightshade game engine
Documentation
//! Projected textures: bullet holes, scorch marks, splatters, signage.

use nightshade::prelude::*;

/// Projects a texture onto whatever surface sits at `position` facing
/// `normal`, both usually straight from a [`raycast`](crate::prelude::raycast)
/// hit. `size` is the decal's width and height in world units.
///
/// ```ignore
/// if let Some(hit) = raycast(world, muzzle, direction, 100.0) {
///     spawn_decal(world, "scorch", hit.point, hit.normal, 0.5);
/// }
/// ```
pub fn spawn_decal(
    world: &mut World,
    texture: &str,
    position: Vec3,
    normal: Vec3,
    size: f32,
) -> Entity {
    let entity = spawn_entities(
        world,
        DECAL | LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM,
        1,
    )[0];
    assign_local_transform(
        world,
        entity,
        LocalTransform {
            translation: position + normal * 0.01,
            rotation: rotation_from_normal(normal),
            ..Default::default()
        },
    );
    world.core.set_decal(
        entity,
        Decal::new(texture).with_size(size, size).with_depth(size),
    );
    entity
}

fn rotation_from_normal(normal: Vec3) -> nalgebra_glm::Quat {
    let forward = Vec3::new(0.0, 0.0, -1.0);
    let normal = nalgebra_glm::normalize(&normal);

    if (normal - forward).norm() < 0.001 {
        return nalgebra_glm::Quat::identity();
    }
    if (normal + forward).norm() < 0.001 {
        return nalgebra_glm::quat_angle_axis(std::f32::consts::PI, &Vec3::new(0.0, 1.0, 0.0));
    }

    let axis = nalgebra_glm::normalize(&nalgebra_glm::cross(&forward, &normal));
    let angle = nalgebra_glm::dot(&forward, &normal).acos();
    nalgebra_glm::quat_angle_axis(angle, &axis)
}