bevy_copperfield 0.2.1

Procedural mesh editor, based on Half-Edge-Mesh datastructure
Documentation
use core::f32;

use bevy::prelude::{Transform, TransformPoint, Vec2, Vec3};
use slotmap::SecondaryMap;

use crate::mesh::{attributes::{SelectionQueries, TraversalQueries}, HalfEdgeId, HalfEdgeMesh};


pub(crate) fn sphere(mesh:&mut HalfEdgeMesh, sphere_center:Vec3, sphere_radius:Vec3) {
    let mut uvmap = SecondaryMap::<HalfEdgeId, Vec2>::new();
    for edge in mesh.edge_keys() {
        let d = (mesh.goto(edge).position() - sphere_center)/sphere_radius;
        let uv = Vec2{
            x: 1.0 - (0.5 + f32::atan2(d.z, d.x) / (2.0*f32::consts::PI)),
            y: 1.0 - (0.5 + f32::asin(d.y) / f32::consts::PI)
        };
        uvmap.insert(edge, uv);
    }
    mesh.add_attribute(crate::mesh::attributes::AttributeKind::UVs, uvmap);
}

pub(crate) fn cube(mesh:&mut HalfEdgeMesh, transform:Transform) {
    const CUBE_NORMALS:[Vec3;6] = [
        Vec3{x:0.0, y:1.0, z:0.0},
        Vec3{x:-1.0, y:0.0, z:0.0},
        Vec3{x:0.0, y:-1.0, z:0.0},
        Vec3{x:1.0, y:0.0, z:0.0},
        Vec3{x:0.0, y:0.0, z:1.0},
        Vec3{x:0.0, y:0.0, z:-1.0}
    ];
    const CUBE_UV_BASIS:[(Vec3, Vec3); 6] = [
        (Vec3{x:0.0, y:0.0, z:1.0}, Vec3{x:-1.0, y:0.0, z:0.0}),
        (Vec3{x:0.0, y:0.0, z:1.0}, Vec3{x:0.0, y:-1.0, z:0.0}),
        (Vec3{x:0.0, y:0.0, z:1.0}, Vec3{x:1.0, y:0.0, z:0.0}),
        (Vec3{x:0.0, y:0.0, z:-1.0}, Vec3{x:0.0, y:1.0, z:0.0}),
        (Vec3{x:1.0, y:0.0, z:0.0}, Vec3{x:0.0, y:1.0, z:0.0}),
        (Vec3{x:1.0, y:0.0, z:0.0}, Vec3{x:0.0, y:1.0, z:0.0}),
    ];
    const UV_TRANSLATE:[Vec2;6] = [
        Vec2{x:0.25, y:0.00},
        Vec2{x:0.25, y:0.25},
        Vec2{x:0.25, y:0.50},
        Vec2{x:0.25, y:0.75},
        Vec2{x:0.00, y:0.75},
        Vec2{x:0.50, y:0.75},
    ];
    let transform = transform.compute_affine().inverse();
    let mut uvmap = SecondaryMap::<HalfEdgeId, Vec2>::new();
    for face in mesh.face_keys() {
        let face = mesh.goto(face);
        let normal = face.calculate_normal().unwrap();
        let (idx, _) = CUBE_NORMALS.iter().enumerate().max_by_key(|(_, n)| { let n = n.dot(normal); if n < 0.0 { 0 } else {(1000.0*n) as i32}}).unwrap();
        let (basis_u, basis_v) = CUBE_UV_BASIS[idx];
        let translate = UV_TRANSLATE[idx];
        for edge in face.iter_loop() {
            let p = transform.transform_point(edge.position());
            let uv = if true {
                0.25*Vec2{x:p.dot(basis_u), y:p.dot(basis_v)} + translate + Vec2{x:0.125, y:0.125}
            } else {
                Vec2::ZERO
            };

            uvmap.insert(*edge, uv);
        }
    }
    mesh.add_attribute(crate::mesh::attributes::AttributeKind::UVs, uvmap);
}