use bevy::prelude::*;
use crate::dice3d::types::DiceType;
pub fn get_label_offset(die_type: DiceType) -> f32 {
match die_type {
DiceType::D4 => 0.22, DiceType::D6 => 0.33, DiceType::D8 => 0.25, DiceType::D10 => 0.28, DiceType::D12 => 0.28, DiceType::D20 => 0.28, }
}
pub fn get_label_scale(die_type: DiceType) -> f32 {
match die_type {
DiceType::D4 => 0.08, DiceType::D6 => 0.24,
DiceType::D8 => 0.18,
DiceType::D10 => 0.15,
DiceType::D12 => 0.09,
DiceType::D20 => 0.11,
}
}
pub fn get_label_rotation(normal: Vec3) -> Quat {
if normal.y.abs() > 0.99 {
if normal.y > 0.0 {
Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)
} else {
Quat::from_rotation_x(std::f32::consts::FRAC_PI_2)
}
} else {
Quat::from_rotation_arc(Vec3::Z, normal)
* Quat::from_rotation_z(if normal.x < -0.5 {
std::f32::consts::PI
} else {
0.0
})
}
}
pub fn create_number_mesh(value: u32, meshes: &mut ResMut<Assets<Mesh>>) -> Handle<Mesh> {
meshes.add(create_digit_mesh(value))
}
pub fn create_digit_mesh(value: u32) -> Mesh {
use bevy::render::mesh::{Indices, PrimitiveTopology};
use bevy::render::render_asset::RenderAssetUsages;
let (positions, indices) = generate_number_geometry(value);
let mut normals = Vec::new();
let verts_per_box = 24;
let num_boxes = positions.len() / verts_per_box;
for _ in 0..num_boxes {
for _ in 0..4 {
normals.push([0.0, 0.0, 1.0]);
}
for _ in 0..4 {
normals.push([0.0, 0.0, -1.0]);
}
for _ in 0..4 {
normals.push([0.0, 1.0, 0.0]);
}
for _ in 0..4 {
normals.push([0.0, -1.0, 0.0]);
}
for _ in 0..4 {
normals.push([-1.0, 0.0, 0.0]);
}
for _ in 0..4 {
normals.push([1.0, 0.0, 0.0]);
}
}
while normals.len() < positions.len() {
normals.push([0.0, 0.0, 1.0]);
}
let uvs: Vec<[f32; 2]> = positions.iter().map(|_| [0.5, 0.5]).collect();
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
.with_inserted_indices(Indices::U32(indices))
}
pub fn generate_number_geometry(value: u32) -> (Vec<[f32; 3]>, Vec<u32>) {
let mut positions = Vec::new();
let mut indices = Vec::new();
let digits: Vec<u32> = if value == 0 {
vec![0]
} else {
let mut v = value;
let mut d = Vec::new();
while v > 0 {
d.push(v % 10);
v /= 10;
}
d.reverse();
d
};
let num_digits = digits.len();
let digit_width = 0.6;
let spacing = 0.1;
let total_width = num_digits as f32 * digit_width + (num_digits - 1) as f32 * spacing;
let start_x = -total_width / 2.0 + digit_width / 2.0;
for (i, &digit) in digits.iter().enumerate() {
let offset_x = start_x + i as f32 * (digit_width + spacing);
let base_idx = positions.len() as u32;
let (digit_pos, digit_idx) = get_digit_geometry(digit, offset_x);
for pos in digit_pos {
positions.push(pos);
}
for idx in digit_idx {
indices.push(base_idx + idx);
}
}
(positions, indices)
}
pub fn get_digit_geometry(digit: u32, offset_x: f32) -> (Vec<[f32; 3]>, Vec<u32>) {
let stroke_width = 0.12; let h = 0.5; let w = 0.35; let d = 0.02; let curve_segments = 6;
let mut positions = Vec::new();
let mut indices = Vec::new();
let add_segment = |positions: &mut Vec<[f32; 3]>,
indices: &mut Vec<u32>,
x1: f32,
y1: f32,
x2: f32,
y2: f32| {
let base_idx = positions.len() as u32;
let dx = x2 - x1;
let dy = y2 - y1;
let len = (dx * dx + dy * dy).sqrt();
if len < 0.001 {
return;
}
let px = -dy / len * stroke_width / 2.0;
let py = dx / len * stroke_width / 2.0;
positions.push([offset_x + x1 - px, y1 - py, d / 2.0]);
positions.push([offset_x + x1 + px, y1 + py, d / 2.0]);
positions.push([offset_x + x2 + px, y2 + py, d / 2.0]);
positions.push([offset_x + x2 - px, y2 - py, d / 2.0]);
indices.extend_from_slice(&[base_idx, base_idx + 1, base_idx + 2]);
indices.extend_from_slice(&[base_idx, base_idx + 2, base_idx + 3]);
let base_idx = positions.len() as u32;
positions.push([offset_x + x1 + px, y1 + py, -d / 2.0]);
positions.push([offset_x + x1 - px, y1 - py, -d / 2.0]);
positions.push([offset_x + x2 - px, y2 - py, -d / 2.0]);
positions.push([offset_x + x2 + px, y2 + py, -d / 2.0]);
indices.extend_from_slice(&[base_idx, base_idx + 1, base_idx + 2]);
indices.extend_from_slice(&[base_idx, base_idx + 2, base_idx + 3]);
};
let add_curve = |positions: &mut Vec<[f32; 3]>,
indices: &mut Vec<u32>,
cx: f32,
cy: f32,
radius: f32,
start_angle: f32,
end_angle: f32| {
for i in 0..curve_segments {
let t1 = i as f32 / curve_segments as f32;
let t2 = (i + 1) as f32 / curve_segments as f32;
let a1 = start_angle + (end_angle - start_angle) * t1;
let a2 = start_angle + (end_angle - start_angle) * t2;
let x1 = cx + radius * a1.cos();
let y1 = cy + radius * a1.sin();
let x2 = cx + radius * a2.cos();
let y2 = cy + radius * a2.sin();
add_segment(positions, indices, x1, y1, x2, y2);
}
};
let pi = std::f32::consts::PI;
let half_pi = std::f32::consts::FRAC_PI_2;
match digit {
0 => {
add_curve(
&mut positions,
&mut indices,
0.0,
h * 0.5,
w * 0.6,
half_pi,
pi + half_pi,
);
add_curve(
&mut positions,
&mut indices,
0.0,
-h * 0.5,
w * 0.6,
-half_pi,
half_pi,
);
add_segment(
&mut positions,
&mut indices,
-w * 0.6,
h * 0.5,
-w * 0.6,
-h * 0.5,
);
add_segment(
&mut positions,
&mut indices,
w * 0.6,
h * 0.5,
w * 0.6,
-h * 0.5,
);
}
1 => {
add_segment(&mut positions, &mut indices, 0.0, h, 0.0, -h);
add_segment(&mut positions, &mut indices, -w * 0.3, h * 0.6, 0.0, h);
}
2 => {
add_curve(&mut positions, &mut indices, 0.0, h * 0.5, w * 0.5, 0.0, pi);
add_segment(&mut positions, &mut indices, w * 0.5, h * 0.5, -w * 0.6, -h);
add_segment(&mut positions, &mut indices, -w * 0.6, -h, w * 0.6, -h);
}
3 => {
add_curve(
&mut positions,
&mut indices,
0.0,
h * 0.5,
w * 0.5,
-half_pi,
pi,
);
add_curve(
&mut positions,
&mut indices,
0.0,
-h * 0.5,
w * 0.5,
-pi,
half_pi,
);
}
4 => {
add_segment(&mut positions, &mut indices, -w * 0.6, h, -w * 0.6, 0.0);
add_segment(&mut positions, &mut indices, -w * 0.6, 0.0, w * 0.6, 0.0);
add_segment(&mut positions, &mut indices, w * 0.4, h, w * 0.4, -h);
}
5 => {
add_segment(&mut positions, &mut indices, w * 0.5, h, -w * 0.5, h);
add_segment(&mut positions, &mut indices, -w * 0.5, h, -w * 0.5, 0.0);
add_segment(&mut positions, &mut indices, -w * 0.5, 0.0, w * 0.3, 0.0);
add_curve(
&mut positions,
&mut indices,
w * 0.1,
-h * 0.5,
w * 0.5,
half_pi,
-pi,
);
}
6 => {
add_curve(&mut positions, &mut indices, 0.0, h * 0.3, w * 0.5, 0.0, pi);
add_segment(
&mut positions,
&mut indices,
-w * 0.5,
h * 0.3,
-w * 0.5,
-h * 0.3,
);
add_curve(
&mut positions,
&mut indices,
0.0,
-h * 0.4,
w * 0.5,
0.0,
2.0 * pi,
);
}
7 => {
add_segment(&mut positions, &mut indices, -w * 0.5, h, w * 0.5, h);
add_segment(&mut positions, &mut indices, w * 0.5, h, -w * 0.2, -h);
}
8 => {
add_curve(
&mut positions,
&mut indices,
0.0,
h * 0.5,
w * 0.4,
0.0,
2.0 * pi,
);
add_curve(
&mut positions,
&mut indices,
0.0,
-h * 0.45,
w * 0.5,
0.0,
2.0 * pi,
);
}
9 => {
add_curve(
&mut positions,
&mut indices,
0.0,
h * 0.4,
w * 0.5,
0.0,
2.0 * pi,
);
add_segment(
&mut positions,
&mut indices,
w * 0.5,
h * 0.2,
w * 0.5,
-h * 0.3,
);
add_curve(
&mut positions,
&mut indices,
0.0,
-h * 0.3,
w * 0.5,
0.0,
-pi,
);
}
_ => {
add_segment(&mut positions, &mut indices, -w * 0.5, h, w * 0.5, h);
add_segment(&mut positions, &mut indices, w * 0.5, h, w * 0.5, -h);
add_segment(&mut positions, &mut indices, w * 0.5, -h, -w * 0.5, -h);
add_segment(&mut positions, &mut indices, -w * 0.5, -h, -w * 0.5, h);
}
}
(positions, indices)
}