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
+}