Initialize repository.
This commit is contained in:
commit
1f3b920570
|
@ -0,0 +1,3 @@
|
|||
/target
|
||||
Cargo.lock
|
||||
*.obj
|
|
@ -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" }
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
|
@ -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(()),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
fn main()
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod utility;
|
|
@ -0,0 +1,4 @@
|
|||
pub fn f32_sign(value:f32) -> f32
|
||||
{
|
||||
((value > 0.) as i32 - (value < 0.) as i32) as f32
|
||||
}
|
Loading…
Reference in New Issue