commit 1f3b92057041c11be58f5c192a7628476e7bc507 Author: yukirij <yukirij@yukiri.net> Date: Sun Jun 9 17:16:50 2024 -0700 Initialize repository. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b3d2a11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +*.obj diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0113d66 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "terrain" +version = "0.1.0" +edition = "2021" + +[dependencies] +glam = "0.27.0" +noise = "0.9.0" + +pool = { git = "https://git.tsukiyo.org/Utility/pool" } +sparse = { git = "https://git.tsukiyo.org/Utility/sparse" } diff --git a/src/bin/icosphere.rs b/src/bin/icosphere.rs new file mode 100644 index 0000000..75451c0 --- /dev/null +++ b/src/bin/icosphere.rs @@ -0,0 +1,77 @@ +#![allow(dead_code)] + +use glam::{DVec3, IVec3}; + +struct Icosphere { + vertices:Vec<DVec3>, + faces:Vec<IVec3>, +} +impl Icosphere { + pub fn new(depth:usize) -> Self + { + Self { + vertices:Vec::<DVec3>::with_capacity(12), + faces:Vec::<IVec3>::with_capacity(20), + }.init(depth) + } + + fn init(mut self, depth:usize) -> Self + { + let phi = (1. + f64::sqrt(5.)) / 2.; + + // Generate initial structure + self.vertices.append(&mut [ + DVec3::new( -1., phi, 0.), + DVec3::new( 1., phi, 0.), + DVec3::new( -1., -phi, 0.), + DVec3::new( 1., -phi, 0.), + DVec3::new( 0., -1., phi), + DVec3::new( 0., 1., phi), + DVec3::new( 0., -1., -phi), + DVec3::new( 0., 1., -phi), + DVec3::new( phi, 0., -1.), + DVec3::new( phi, 0., 1.), + DVec3::new(-phi, 0., -1.), + DVec3::new(-phi, 0., 1.), + ].to_vec()); + + self.faces.append(&mut [ + IVec3::new(0, 11, 5), + IVec3::new(0, 5, 1), + IVec3::new(0, 1, 7), + IVec3::new(0, 7, 10), + IVec3::new(0, 10, 11), + IVec3::new(1, 5, 9), + IVec3::new(5, 11, 4), + IVec3::new(11, 10, 2), + IVec3::new(10, 7, 6), + IVec3::new(7, 1, 8), + IVec3::new(3, 9, 4), + IVec3::new(3, 4, 2), + IVec3::new(3, 2, 6), + IVec3::new(3, 6, 8), + IVec3::new(3, 8, 9), + IVec3::new(4, 9, 5), + IVec3::new(2, 4, 11), + IVec3::new(6, 2, 10), + IVec3::new(8, 6, 7), + IVec3::new(9, 8, 1), + ].to_vec()); + + // Subdivide until depth + for _ in 0..depth { + self.subdivide(); + } + self + } + + fn subdivide(&mut self) + { + + } +} + +fn main() +{ + +} diff --git a/src/bin/mesh.rs b/src/bin/mesh.rs new file mode 100644 index 0000000..455ba90 --- /dev/null +++ b/src/bin/mesh.rs @@ -0,0 +1,756 @@ +#![allow(dead_code)] + +use std::{f32::consts::PI, io::Write}; +use glam::{IVec3, Vec3}; +use noise::NoiseFn; +use pool::Pool; +use sparse::Sparse; + +const DEBUG_PRINTS :bool = false; + +const DEGREES :f32 = PI / 180.; + +const SEED :u32 = 69; +const DELTA_THRESHOLD :f32 = 1. * DEGREES; +const MAX_DEPTH :u8 = 16; +const GRID_SIZE :usize = 23; +const GRID_SCALE :f32 = 20.; +const MESH_SCALE :f32 = 0.25; + +const SQRT_3 :f32 = 1.7320508075; +const TR_EDGE :f32 = 0.5; +const TR_VERT :f32 = 2. * TR_EDGE; +const TR_SIDH :f32 = SQRT_3 * TR_EDGE; +const TR_SIDE :f32 = 2. * TR_SIDH; +const TR_CROS :f32 = TR_EDGE + TR_VERT; + +#[derive(Clone, Copy)] +enum Action { + Check(/*Id*/usize, /*Caller*/usize), + Subdivide(/*Id*/usize, /*Caller*/usize), + Split(/*Id*/usize, /*Caller*/usize), +} + +#[derive(Clone, Copy)] +struct Cell { + pub depth:u8, + pub direction:u8, + pub sibling:u8, + pub neighbors:[usize;3], + pub vertices:[usize;3], +} +impl Cell { + pub fn new() -> Self + { + Self { + depth:0, + direction:3, + sibling:3, + neighbors:[0; 3], + vertices:[0; 3], + } + } +} + +struct Grid { + radius:usize, + vertices:Pool<Vec3>, + cells:Pool<Cell>, + + generator:noise::Perlin, +} + +impl Grid { + pub fn new(radius:usize) -> Self + { + Self { + radius:radius, + vertices:Pool::<Vec3>::new(), + cells:Pool::<Cell>::new(), + + generator:noise::Perlin::new(SEED), + }.init() + } + + fn init(mut self) -> Self + { + // Create vertices + let size = self.radius + 1; + + let z_offset = -GRID_SCALE * TR_CROS * (size as f32 / 2.); + for row in 0..=size { + let basis :f32 = -GRID_SCALE * TR_SIDH * row as f32; + + for col in 0..=row { + let x = basis + (GRID_SCALE * TR_SIDE * col as f32); + let z = z_offset + (GRID_SCALE * TR_CROS * row as f32); + self.add_vertex(Vec3::new(x, 0., z)); + } + } + + // Create cells and assign vertices + + let mut v_index = 0; + let mut c_index = 0; + for row in 0..size { + for col in 0..((2 * row) + 1) { + self.cells.add({ + let mut cell = Cell::new(); + let index = c_index + col; + + cell.vertices = if col & 1 == 0 {[ + 1 + v_index + row + (col / 2) + 2, + 1 + v_index + row + (col / 2) + 1, + 1 + v_index + (col / 2), + ]} else {[ + 1 + v_index + (col / 2), + 1 + v_index + (col / 2) + 1, + 1 + v_index + row + (col / 2) + 2, + ]}; + + cell.neighbors = if col & 1 == 0 {[ + if col > 0 { 1 + index - 1 } else { 0 }, + if col < (2 * row) { 1 + index + 1 } else { 0 }, + if row < self.radius { 1 + index + (2 * (row + 1)) } else { 0 }, + ]} else {[ + 1 + index + 1, + 1 + index - 1, + if row > 0 { 1 + index - (2 * row) } else { 0 }, + ]}; + + cell + }); + } + + v_index += row + 1; + c_index += (2 * row) + 1; + } + + self + } + + pub fn prepare_nodes(&mut self) + { + let mut data = self.cells.list(); + let mut data_len = data.len(); + + let mut passes = 0; + while data.len() > 0 { + let pass = data.clone(); + data.clear(); + + for id in pass { + if self.node_prepare(id) { + data.push(id); + } + } + + let new_data = self.cells.list(); + if new_data.len() > data_len { + data.append(&mut new_data[data_len..].to_vec()); + data_len = new_data.len(); + } + + passes += 1; + if passes % 10 == 0 { + println!("Pass {}", passes); + } + } + } + + fn node_prepare(&mut self, id:usize) -> bool + // Test the height change of the node to determine if it should be subdivided. + // + { + let cell = if let Some(data) = self.cells.get(id) { + *data + } else { return false; }; + + // Determine if cell should be subdivided. + let v = [ + *self.vertices.get(cell.vertices[0]).unwrap(), + *self.vertices.get(cell.vertices[1]).unwrap(), + *self.vertices.get(cell.vertices[2]).unwrap(), + ]; + let normal = (v[1] - v[0]).cross(v[2] - v[0]).normalize(); + + let mut neighbor_normal = Vec3::ZERO; + let mut count = 0.; + + for n in 0..3 { + let neighbor_id = cell.neighbors[n]; + if neighbor_id != 0 { + if let Some(neighbor) = self.cells.get(neighbor_id) { + let v = [ + *self.vertices.get(neighbor.vertices[0]).unwrap(), + *self.vertices.get(neighbor.vertices[1]).unwrap(), + *self.vertices.get(neighbor.vertices[2]).unwrap(), + ]; + + neighbor_normal += (v[1] - v[0]).cross(v[2] - v[0]).normalize(); + count += 1.; + } + } + } + neighbor_normal /= count; + + let delta = normal.angle_between(neighbor_normal); + let threshold = DELTA_THRESHOLD * (cell.depth + 1) as f32; + //println!("{:8} {} <> {}", delta > threshold, delta, threshold); + if delta > threshold { + //println!("subdiv"); + self.node_update(&vec![Action::Subdivide(id, 0)]); + + let new_cell = if let Some(data) = self.cells.get(id) { + *data + } else { return false; }; + + new_cell.depth != cell.depth + } else { + false + } + } + + fn node_update(&mut self, actions:&Vec<Action>) + { + let mut actions = actions.clone(); + while let Some(action) = actions.pop() { + actions.append(&mut match action { + Action::Check(id, caller) => self.node_check(id, caller), + Action::Subdivide(id, caller) => self.node_subdivide(id, caller), + Action::Split(id, caller) => self.node_split(id, caller), + }); + } + } + + fn node_check(&mut self, id:usize, caller:usize) -> Vec<Action> + // Determine if node needs to be subdivided or split. + // + { + let cell = if let Some(data) = self.cells.get(id) { + *data + } else { return vec![]; }; + + //println!("caller {}", caller); + self.print_cell("UPDATE", id, &cell); + + // Determine if relation with neighbors is stable. + // - Regular cell is stable if neighbors are same depth or depth +/- 1. + // - Split cell is stable if exactly 1 neighbor is depth +1 and rest are same or -1. + // Count number of regular neighbors of greater depth. + let mut diff_direction :usize = 0; + let mut diff_count :usize = 0; + for n in 0..cell.neighbors.len() { + let neighbor_id = cell.neighbors[n]; + + if neighbor_id != 0 { + let neighbor = self.cells.get(neighbor_id).unwrap().clone(); + if neighbor.depth >= (cell.depth & !1) + 2 { + diff_count += 1; + diff_direction = n; + } + } + } + + // Determine how cell should be handled. + if cell.depth & 1 == 0 { + match diff_count { + 0 => { vec![] } + 1 => { vec![Action::Split(id, diff_direction)] } + 2|3 => { vec![Action::Subdivide(id, caller)] } + _ => { panic!("invalid diff count") } + } + } + else { + match diff_count { + 0 => { vec![] } + 1 => { + if cell.direction as usize != diff_direction { + vec![Action::Subdivide(id, caller)] + } + else { + vec![] + } + } + 2|3 => { vec![Action::Subdivide(id, caller)] } + _ => { panic!("invalid diff count") } + } + } + + // Determine if neighbors need to be updated. + } + + pub fn node_subdivide(&mut self, id:usize, _caller:usize) -> Vec<Action> + { + let mut cell = if let Some(data) = self.cells.get(id) { + *data + } else { return vec![]; }; + if cell.depth >= MAX_DEPTH { return vec![]; } + + let mut actions = Vec::<Action>::new(); + + //println!("caller {}", caller); + self.print_cell("BEGDIV", id, &cell); + + // If half-depth, get twin information. + // If sibling 1, forward call to sibling 0. + // + let twin_dir = if cell.depth & 1 == 0 { 3 } else { Self::twin_neighbor(cell.direction, cell.sibling) }; + + let mut twin_id = 0; + let mut twin :Option<Cell> = None; + + let direction = cell.direction as usize; + let d_offset_0 = (direction + 1) % 3; + let d_offset_1 = (direction + 2) % 3; + + if cell.depth & 1 == 1 { + twin_id = cell.neighbors[twin_dir]; + + if cell.sibling == 1 { + return vec![Action::Subdivide(twin_id, id)]; + } + + twin = Some(self.cells.get(twin_id).unwrap().clone()); + //match &twin { + // Some(twin) => { self.print_cell("TWIN", twin_id, twin); } + // None => { } + //} + } + + // Get outer neighbors and vertices. + let (neighbors, vertices) = match twin { + Some(twin) => { + let mut neighbors = cell.neighbors; + let mut vertices = cell.vertices; + + neighbors[twin_dir] = twin.neighbors[twin_dir]; + vertices[d_offset_0] = twin.vertices[d_offset_0]; + + (neighbors, vertices) + } + + None => { + (cell.neighbors, cell.vertices) + } + }; + + let mut updates = Vec::<usize>::new(); + for n in 0..neighbors.len() { + let neighbor_id = neighbors[n]; + if let Some(neighbor) = self.cells.get(neighbor_id) { + if neighbor.neighbors[n] == id || (twin_id != 0 && neighbor.neighbors[n] == twin_id) { + updates.push(neighbor_id); + } + else { + let nd_offset_0 = (n + 2) % 3; + let nd_offset_1 = (n + 1) % 3; + + updates.push(neighbor.neighbors[nd_offset_0]); + updates.push(neighbor.neighbors[nd_offset_1]); + } + } + } + if let Some(twin) = &twin { + let neighbor_id = twin.neighbors[direction]; + if let Some(neighbor) = self.cells.get(neighbor_id) { + if neighbor.neighbors[direction] == id || neighbor.neighbors[direction] == twin_id { + updates.push(neighbor_id); + } + else { + updates.push(neighbor.neighbors[d_offset_0]); + updates.push(neighbor.neighbors[d_offset_1]); + } + } + } + + // If a neighbor is of lesser depth, that node needs to be subdivided + // before subdividing the current node. + // If node is subdivided as a result, no work to do. + // + let initial_depth = cell.depth; + for n in 0..neighbors.len() { + let neighbor_id = neighbors[n]; + if neighbor_id != 0 { + let neighbor = *self.cells.get(neighbor_id).unwrap(); + if neighbor.depth < initial_depth && neighbor.depth & 1 == 1 { + actions.push(Action::Subdivide(neighbor_id, id)); + } + + // Refresh cell data incase changed. + cell = if let Some(data) = self.cells.get(id) { + *data + } else { return vec![]; }; + } + } + if !actions.is_empty() { + return [vec![Action::Subdivide(id, id)], actions].concat(); + } + + + // Get vector values of outer vertices. + let vertex_values = [ + *self.vertices.get(vertices[0]).unwrap(), + *self.vertices.get(vertices[1]).unwrap(), + *self.vertices.get(vertices[2]).unwrap(), + ]; + + + // Get midpoints from adjacent nodes. + let mut midpoints = [0; 3]; + for n in 0..neighbors.len() { + let neighbor_id = neighbors[n]; + if neighbor_id != 0 { + let neighbor = *self.cells.get(neighbor_id).unwrap(); + + if (neighbor.depth > cell.depth && neighbor.depth & 1 == 0) || (neighbor.depth > cell.depth && neighbor.direction == n as u8) { + midpoints[n] = neighbor.vertices[n]; + } + } + } + match twin { + Some(_) => { + midpoints[direction] = cell.vertices[d_offset_0]; + } + None => { } + } + + // Fill missing midpoint vertices. + let subvertices = [ + if midpoints[0] != 0 { midpoints[0] } else { self.add_vertex(((vertex_values[2] - vertex_values[1]) / 2.) + vertex_values[1]) }, + if midpoints[1] != 0 { midpoints[1] } else { self.add_vertex(((vertex_values[0] - vertex_values[2]) / 2.) + vertex_values[2]) }, + if midpoints[2] != 0 { midpoints[2] } else { self.add_vertex(((vertex_values[1] - vertex_values[0]) / 2.) + vertex_values[0]) }, + ]; + + + // Prepare child cells. + let mut children = [ + Cell::new(), + Cell::new(), + Cell::new(), + Cell::new(), + ]; + let child_ids = [ + self.cells.add(Cell::new()), + self.cells.add(Cell::new()), + if twin.is_some() { twin_id } else { self.cells.add(Cell::new()) }, + id, + ]; + + cell.depth = (cell.depth + 2) & !1; + for c in 0..children.len() { + children[c].depth = cell.depth; + children[c].sibling = c as u8; + } + for c in 0..3 { + children[3].neighbors[c] = child_ids[c]; + children[c].neighbors[c] = id; + } + + // Set new cell vertices. + children[0].vertices = [ vertices[0], subvertices[2], subvertices[1] ]; + children[1].vertices = [ subvertices[2], vertices[1], subvertices[0] ]; + children[2].vertices = [ subvertices[1], subvertices[0], vertices[2] ]; + children[3].vertices = [ subvertices[0], subvertices[1], subvertices[2] ]; + + + // Link twin neighbor to center cell. + if twin.is_some() { + if let Some(neighbor) = self.cells.get_mut(neighbors[twin_dir]) { + if neighbor.neighbors[twin_dir] == twin_id { + neighbor.neighbors[twin_dir] = id; + } + } + } + + // Trade neighbor links with neighboring cells. + for n in 0..neighbors.len() { + let neighbor_id = neighbors[n]; + + let nd_offset_0 = (n + 2) % 3; + let nd_offset_1 = (n + 1) % 3; + + //println!("neighbor {} {}", n, neighbor_id); + + let mut processed = false; + if n == direction { + if let Some(twin) = &twin { + // Update both children that have edges in direction. + + let n0 = cell.neighbors[direction]; + let n1 = twin.neighbors[direction]; + + children[nd_offset_0].neighbors[direction] = n0; + children[nd_offset_1].neighbors[direction] = n1; + + //println!("d {} [{}] = {}, {} [{}] = {}", n0, n, child_ids[nd_offset_0], n1, n, child_ids[nd_offset_1]); + + if let Some(neighbor) = self.cells.get_mut(n0) { + neighbor.neighbors[n] = child_ids[nd_offset_0]; + } + if let Some(neighbor) = self.cells.get_mut(n1) { + neighbor.neighbors[n] = child_ids[nd_offset_1]; + } + + processed = true; + } + } + if !processed { + if neighbor_id != 0 { + let neighbor = self.cells.get(neighbor_id).unwrap().clone(); + + if neighbor.depth == cell.depth { + // Update both children that have edges in direction. + // Neighbor must be parent. + + let n0 = neighbor.neighbors[nd_offset_1]; + let n1 = neighbor.neighbors[nd_offset_0]; + + //println!("{} [{}] = {}, {} [{}] = {}", n0, n, child_ids[nd_offset_0], n1, n, child_ids[nd_offset_1]); + + children[nd_offset_0].neighbors[n] = n0; + children[nd_offset_1].neighbors[n] = n1; + + if let Some(neighbor) = self.cells.get_mut(n0) { + neighbor.neighbors[n] = child_ids[nd_offset_0]; + } + if let Some(neighbor) = self.cells.get_mut(n1) { + neighbor.neighbors[n] = child_ids[nd_offset_1]; + } + } + } + } + } + + // Update cells. + for i in 0..children.len() { + self.print_cell("SUBDIV", child_ids[i], &children[i]); + + self.cells.update(child_ids[i], children[i]).ok(); + } + + // Update neighbor cells + for update in updates { + if update != 0 { + actions.push(Action::Check(update, id)); + } + } + actions + } + + fn node_split(&mut self, id:usize, direction:usize) -> Vec<Action> + { + let mut cell = if let Some(data) = self.cells.get(id) { + *data + } else { return vec![]; }; + if cell.direction as usize == direction { return vec![]; } + + let actions = Vec::<Action>::new(); + + self.print_cell("SPLIT", id, &cell); + + let neighbors = cell.neighbors; + + if cell.depth & 1 == 0 { + let mut twin = Cell::new(); + + // Set cell and twin properties. + cell.depth += 1; + twin.depth = cell.depth; + + cell.direction = direction as u8; + twin.direction = direction as u8; + + cell.sibling = 0; + twin.sibling = 1; + + let neighbor_id = cell.neighbors[direction]; + let neighbor = self.cells.get(neighbor_id).unwrap().clone(); + let midpoint = neighbor.vertices[direction]; + + let d_offset_0 = (direction + 1) % 3; + let d_offset_1 = (direction + 2) % 3; + + // Set cell and twin vertices. + twin.vertices = cell.vertices; + twin.vertices[d_offset_1] = midpoint; + cell.vertices[d_offset_0] = midpoint; + + // Set cell and twin neighbors. + let n0 = neighbor.neighbors[d_offset_0]; + let n1 = neighbor.neighbors[d_offset_1]; + + twin.neighbors = cell.neighbors; + twin.neighbors[direction] = n1; + twin.neighbors[Self::twin_neighbor(direction as u8, 1)] = id; + + let twin_id = self.cells.add(twin); + cell.neighbors[direction] = n0; + cell.neighbors[Self::twin_neighbor(direction as u8, 0)] = twin_id; + + // Update links for outer neighbors + if let Some(neighbor) = self.cells.get_mut(n0) { + neighbor.neighbors[direction] = id; + } + if let Some(neighbor) = self.cells.get_mut(n1) { + neighbor.neighbors[direction] = twin_id; + } + if let Some(neighbor) = self.cells.get_mut(neighbors[d_offset_1]) { + neighbor.neighbors[d_offset_1] = twin_id; + } + + self.print_cell("SUBHAV", id, &cell); + self.print_cell("SUBHAV", twin_id, &twin); + + // Push updated data + self.cells.update(id, cell).ok(); + } + + // Node is already split, so cells only need to be rotated. + // This probably cannot happen, as it would require a neighbor to disappear + // and another to form before updating of this triangle. + else { + panic!("split node needs to be rotated"); + } + + actions + } + + fn twin_neighbor(direction:u8, sibling:u8) -> usize + { + ((direction + 2 - sibling) % 3) as usize + } + + fn add_vertex(&mut self, vertex:Vec3) -> usize + { + self.vertices.add(Vec3::new(vertex.x, self.vertex_height(vertex.x, vertex.z), vertex.z)) + } + + fn print_cell(&self, text:&str, id:usize, cell:&Cell) + { + if DEBUG_PRINTS { + println!("{:8} {:3} ( {:2} ) [{:3} {:3} {:3}] [{:3} {:3} {:3}]", + text, + id, + cell.depth, + cell.vertices[0], + cell.vertices[1], + cell.vertices[2], + cell.neighbors[0], + cell.neighbors[1], + cell.neighbors[2], + ); + } + } + + pub fn to_mesh(&self) -> Mesh + { + let mut mesh = Mesh::new(); + let mut conversion = Sparse::<usize>::new(); + + // Add vertices + for index in self.vertices.list() { + if let Some(vertex) = self.vertices.get(index) { + conversion.set(index, mesh.vertices.len()); + mesh.vertices.push(*vertex * MESH_SCALE); + } + } + + // Add faces + for index in self.cells.list() { + if let Some(cell) = self.cells.get(index) { + self.print_cell("FINAL", index, &cell); + + let a = *conversion.get(cell.vertices[0]).unwrap() as i32; + let b = *conversion.get(cell.vertices[1]).unwrap() as i32; + let c = *conversion.get(cell.vertices[2]).unwrap() as i32; + + mesh.faces.push(IVec3::new(a, c, b)); + } + } + + mesh + } + + fn vertex_height(&self, x:f32, y:f32) -> f32 + { + let mut value :f64 = 0.; + let mut scale = 1. / 8.; + let mut weight = 1.; + let mut result :f64; + + for _ in 0..6 { + result = self.generator.get([scale * (x as f64), scale * (y as f64)]); + value += result * result * weight; + scale *= 1. / 8.; + weight *= 4.; + } + value as f32 + } +} + +struct Mesh { + pub vertices:Vec<Vec3>, + pub faces:Vec<IVec3>, +} +impl Mesh { + pub fn new() -> Self + { + Self { + vertices:Vec::<Vec3>::new(), + faces:Vec::<IVec3>::new(), + } + } +} + +fn main() { + let size = GRID_SIZE; + let mut grid = Grid::new(size); + grid.prepare_nodes(); + + let mesh = grid.to_mesh(); + generate_obj("test.obj", &mesh).ok(); +} + +fn generate_obj(path:&str, mesh:&Mesh) -> Result<(),()> +{ + match std::fs::File::create(path) { + Ok(mut file) => { + let mut min = Vec3::ZERO; + let mut max = Vec3::ZERO; + + for v in &mesh.vertices { + if v.x < min.x { min.x = v.x } else if v.x > max.x { max.x = v.x }; + if v.z < min.z { min.z = v.z } else if v.z > max.z { max.z = v.z }; + + let v = *v * 20.; + file.write_all(format!("v {:.6} {:.6} {:.6}\n", v.x, v.y, v.z).as_bytes()).ok(); + } + + file.write_all("\n".as_bytes()).ok(); + + let rx = max.x - min.x; + let rz = max.z - min.z; + + for v in &mesh.vertices { + let ux = ((v.x / rx) + 0.5).clamp(0., 1.); + let uz = ((v.z / rz) + 0.5).clamp(0., 1.); + + file.write_all(format!("vt {:.6} {:.6}\n", ux, uz).as_bytes()).ok(); + } + + file.write_all("\n".as_bytes()).ok(); + + for f in &mesh.faces { + file.write_all(format!("f {}/{} {}/{} {}/{}\n", + f.x + 1, f.x + 1, + f.y + 1, f.y + 1, + f.z + 1, f.z + 1, + ).as_bytes()).ok(); + } + + Ok(()) + } + Err(_) => Err(()), + } +} diff --git a/src/bin/skybox.rs b/src/bin/skybox.rs new file mode 100644 index 0000000..1156dd9 --- /dev/null +++ b/src/bin/skybox.rs @@ -0,0 +1,4 @@ +fn main() +{ + +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..6ba3528 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod utility; diff --git a/src/utility.rs b/src/utility.rs new file mode 100644 index 0000000..f8d0194 --- /dev/null +++ b/src/utility.rs @@ -0,0 +1,4 @@ +pub fn f32_sign(value:f32) -> f32 +{ + ((value > 0.) as i32 - (value < 0.) as i32) as f32 +}