box3d_rust/height_field/
factory.rs1use super::create::create_height_field;
7use super::types::{HeightFieldData, HeightFieldDef, HEIGHT_FIELD_HOLE};
8use crate::math_functions::{Vec3, PI};
9use std::fs::File;
10use std::io::{BufRead, BufReader, Write};
11use std::path::Path;
12
13pub fn create_grid(
15 row_count: i32,
16 column_count: i32,
17 scale: Vec3,
18 make_holes: bool,
19) -> HeightFieldData {
20 let height_count = (row_count * column_count) as usize;
21 let heights = vec![0.0f32; height_count];
22
23 let cell_count = ((row_count - 1) * (column_count - 1)) as usize;
24 let mut material_indices = vec![0u8; cell_count];
25
26 for i in 0..row_count - 1 {
27 for j in 0..column_count - 1 {
28 let k = (i * (column_count - 1) + j) as usize;
29 if make_holes && k > 0 && k % 16 == 0 {
30 material_indices[k] = HEIGHT_FIELD_HOLE;
31 }
32 }
33 }
34
35 let def = HeightFieldDef {
36 heights,
37 material_indices,
38 scale,
39 count_x: column_count,
40 count_z: row_count,
41 global_minimum_height: -256.0,
42 global_maximum_height: 256.0,
43 clockwise_winding: false,
44 };
45
46 create_height_field(&def)
47}
48
49pub fn create_wave(
54 row_count: i32,
55 column_count: i32,
56 scale: Vec3,
57 row_frequency: f32,
58 column_frequency: f32,
59 make_holes: bool,
60) -> HeightFieldData {
61 let height_count = (row_count * column_count) as usize;
62 let mut heights = vec![0.0f32; height_count];
63
64 let omega_z = 2.0 * PI * row_frequency;
65 let omega_x = 2.0 * PI * column_frequency;
66
67 for i in 0..row_count {
68 let row_height = (omega_z * (i as f32)).sin();
69 for j in 0..column_count {
70 let k = (i * column_count + j) as usize;
71 let column_height = (omega_x * (j as f32)).sin();
72 heights[k] = row_height * column_height;
73 }
74 }
75
76 let cell_count = ((row_count - 1) * (column_count - 1)) as usize;
77 let mut material_indices = vec![0u8; cell_count];
78
79 for i in 0..row_count - 1 {
80 for j in 0..column_count - 1 {
81 let k = (i * (column_count - 1) + j) as usize;
82 if make_holes && k > 0 && k % 16 == 0 {
83 material_indices[k] = HEIGHT_FIELD_HOLE;
84 }
85 }
86 }
87
88 let def = HeightFieldDef {
89 heights,
90 material_indices,
91 scale,
92 count_x: column_count,
93 count_z: row_count,
94 global_minimum_height: -256.0,
95 global_maximum_height: 256.0,
96 clockwise_winding: false,
97 };
98
99 create_height_field(&def)
100}
101
102pub fn dump_height_data(data: &HeightFieldDef, file_name: impl AsRef<Path>) {
104 let Ok(mut file) = File::create(file_name) else {
105 return;
106 };
107
108 let _ = writeln!(file, "{} {}", data.count_x, data.count_z);
109 let _ = writeln!(
110 file,
111 "{:.9} {:.9} {:.9}",
112 data.scale.x, data.scale.y, data.scale.z
113 );
114 let _ = writeln!(
115 file,
116 "{:.9} {:.9}",
117 data.global_minimum_height, data.global_maximum_height
118 );
119 let _ = writeln!(file, "{}", i32::from(data.clockwise_winding));
120
121 let height_count = (data.count_x * data.count_z) as usize;
122 for i in 0..height_count {
123 let _ = writeln!(file, "{:.9}", data.heights[i]);
124 }
125
126 let material_count = ((data.count_x - 1) * (data.count_z - 1)) as usize;
127 for i in 0..material_count {
128 let _ = writeln!(file, "{}", data.material_indices[i]);
129 }
130}
131
132pub fn load_height_field(file_name: impl AsRef<Path>) -> Option<HeightFieldData> {
135 let file = File::open(file_name).ok()?;
136 let mut lines = BufReader::new(file).lines().map_while(Result::ok);
137
138 let dim_line = lines.next()?;
139 let mut dim_parts = dim_line.split_whitespace();
140 let count_x: i32 = dim_parts.next()?.parse().ok()?;
141 let count_z: i32 = dim_parts.next()?.parse().ok()?;
142
143 let scale_line = lines.next()?;
144 let mut scale_parts = scale_line.split_whitespace();
145 let scale = Vec3 {
146 x: scale_parts.next()?.parse().ok()?,
147 y: scale_parts.next()?.parse().ok()?,
148 z: scale_parts.next()?.parse().ok()?,
149 };
150
151 let bounds_line = lines.next()?;
152 let mut bounds_parts = bounds_line.split_whitespace();
153 let global_minimum_height: f32 = bounds_parts.next()?.parse().ok()?;
154 let global_maximum_height: f32 = bounds_parts.next()?.parse().ok()?;
155
156 let clockwise_line = lines.next()?;
157 let clockwise: i32 = clockwise_line.trim().parse().ok()?;
158 let clockwise_winding = clockwise != 0;
159
160 let height_count = (count_x * count_z) as usize;
161 let mut heights = Vec::with_capacity(height_count);
162 for _ in 0..height_count {
163 let line = lines.next()?;
164 heights.push(line.trim().parse().ok()?);
165 }
166
167 let material_count = ((count_x - 1) * (count_z - 1)) as usize;
168 let mut material_indices = Vec::with_capacity(material_count);
169 for _ in 0..material_count {
170 let line = lines.next()?;
171 let material_index: i32 = line.trim().parse().ok()?;
172 material_indices.push(material_index as u8);
173 }
174
175 let def = HeightFieldDef {
176 heights,
177 material_indices,
178 scale,
179 count_x,
180 count_z,
181 global_minimum_height,
182 global_maximum_height,
183 clockwise_winding,
184 };
185
186 Some(create_height_field(&def))
187}