1use crate::generation2::disp::Displacement;
5use crate::prelude::Texture;
6use crate::prelude::UVAxis;
7use crate::utils::Vec2d;
8use crate::utils::{NextChunk, TryMap};
9use crate::{
10 generation::region::Room,
11 map::{DispInfo, Entity, Map, Side, Solid},
12 prelude::{Plane, Vector3},
13 StrType,
14};
15use std::fmt::Display;
16use std::str::FromStr;
17use vmf_parser_nom::ast::{Block, Property, Vmf};
18
19pub trait ToLower<T>: Clone {
26 fn into_lower(self) -> T {
28 self.to_lower()
29 }
30
31 fn to_lower(&self) -> T {
33 self.clone().into_lower()
34 }
35}
36
37pub(crate) trait ToHigher<T>: Clone {
40 fn into_higher(self) -> T {
42 self.to_higher()
43 }
44 fn to_higher(&self) -> T {
46 self.clone().into_higher()
47 }
48}
49
50impl<'a> ToLower<Vmf<StrType<'a>>> for Map<'a> {
53 fn into_lower(self) -> Vmf<StrType<'a>> {
54 let mut vmf = Vmf::default();
55 let mut solid_blocks: Vec<_> = self.solids.iter().map(|s| s.to_lower()).collect();
56 if let Some(cordon) = self.options.cordon.clone() {
57 solid_blocks
59 .extend(Room::new(cordon).construct_sky_inside().iter().map(|s| s.to_lower()));
60 }
61
62 vmf.inner.blocks.push(Block {
63 name: "versioninfo".into(),
64 props: vec![
65 Property::new("editorversion", "400"),
66 Property::new("editorbuild", "9540"),
67 Property::new("mapversion", "1"),
68 Property::new("formatversion", "100"),
69 Property::new("prefab", "0"),
70 ],
71 blocks: vec![],
72 });
73 vmf.inner
74 .blocks
75 .push(Block { name: "visgroups".into(), props: vec![], blocks: vec![] });
76 vmf.inner.blocks.push(Block {
77 name: "viewsettings".into(),
78 props: vec![
79 Property::new("bSnapToGrid", "1"),
80 Property::new("bShowGrid", "1"),
81 Property::new("bShowLogicalGrid", "0"),
82 Property::new("nGridSpacing", "64"),
83 Property::new("bShow3DGrid", "0"),
84 ],
85 blocks: vec![],
86 });
87 vmf.inner.blocks.push(Block {
88 name: "world".into(),
89 props: vec![
90 Property::new("mapversion", "1"),
91 Property::new("classname", "worldspawn"),
92 Property::new("skyname", self.options.sky_name),
93 ],
94 blocks: solid_blocks,
95 });
96 vmf.inner.blocks.extend(self.entities.iter().map(|e| e.to_lower()));
98 vmf
102 }
103}
104
105impl<'a> ToLower<Block<StrType<'a>>> for Solid<'a> {
106 fn into_lower(self) -> Block<StrType<'a>> {
107 Block {
108 name: "solid".into(),
109 props: vec![],
111 blocks: self.sides.iter().map(|x| x.to_lower()).collect(),
112 }
113 }
114}
115
116impl<'a> ToLower<Block<StrType<'a>>> for Side<'a> {
117 fn into_lower(self) -> Block<StrType<'a>> {
118 let props = vec![
119 Property::new("plane", self.plane.to_string()),
121 Property::new("material", self.texture.material.to_string()),
122 Property::new("uaxis", self.texture.uaxis.to_string()),
123 Property::new("vaxis", self.texture.vaxis.to_string()),
124 Property::new("lightmapscale", self.texture.light_scale.to_string()),
128 Property::new("smoothing_groups", "0".to_string()),
129 ];
130 let blocks = match self.disp {
131 Some(disp) => {
132 let disp_info = disp.into_disp_info();
133 vec![disp_info.into_lower()]
134 }
135 None => vec![],
136 };
137 Block::new("side", props, blocks)
138 }
139}
140
141impl<'a> ToLower<Block<StrType<'a>>> for DispInfo {
148 fn into_lower(self) -> Block<StrType<'a>> {
149 use std::fmt::Write;
150 let props = vec![
151 Property::new("power", self.power.to_string()),
152 Property::new("startposition", format!("[{}]", self.start_position)),
153 Property::new("flags", self.flags.to_string()),
154 Property::new("elevation", self.elevation.to_string()),
155 Property::new("subdiv", (self.is_subdiv as i32).to_string()),
156 ];
157 let mut allowed_verts = String::new();
158 for int in self.allowed_verts {
159 write!(&mut allowed_verts, "{} ", int).unwrap();
160 }
161 allowed_verts.truncate(allowed_verts.len() - 1);
162 let allowed_verts = Property::new("10", allowed_verts);
163 let blocks = vec![
164 Block::new("normals", self.normals.to_lower(), vec![]),
165 Block::new("distances", self.distances.to_lower(), vec![]),
166 Block::new("offsets", self.offsets.to_lower(), vec![]),
167 Block::new("offset_normals", self.offset_normals.to_lower(), vec![]),
168 Block::new("alphas", self.alphas.to_lower(), vec![]),
169 Block::new("triangle_tags", self.triangle_tags.to_lower(), vec![]),
170 Block::new("allowed_verts", vec![allowed_verts], vec![]),
171 ];
172 Block::new("dispinfo", props, blocks)
173 }
174}
175
176impl<'a> ToLower<Block<StrType<'a>>> for Entity<StrType<'a>> {
177 fn into_lower(self) -> Block<StrType<'a>> {
178 Block {
179 name: "entity".into(),
181 props: self.props,
182 blocks: vec![],
183 }
184 }
185}
186
187impl<'a, T: Clone + Display> ToLower<Vec<Property<StrType<'a>, StrType<'a>>>> for Vec2d<T> {
188 fn to_lower(&self) -> Vec<Property<StrType<'a>, StrType<'a>>> {
190 use std::fmt::Write;
191 let mut i = 0;
192 let row_to_prop = |row: &[T]| {
193 let key = format!("row{}", i);
194 i += 1;
195
196 let mut value = String::new();
198
199 for item in row {
202 write!(&mut value, "{item} ").unwrap();
203 }
204 value.truncate(value.len() - 1);
205
206 Property::new(key, value)
207 };
208
209 let rows = self.rows();
212
213 rows.into_iter().map(row_to_prop).collect()
214 }
215}
216
217pub(crate) fn block_to_solid<'a>(block: &'a Block<impl AsRef<str>>) -> Solid<'a> {
220 assert_eq!(block.name.as_ref(), "solid");
221
222 let mut sides = Vec::with_capacity(6); for block in block.blocks.iter() {
226 match block.name.as_ref() {
227 "side" => {
228 sides.push(parse_side(block));
229 }
230 "editor" => {}
231 block => panic!("Unexpected block {block}"),
232 }
233 }
234
235 Solid::new(sides)
236}
237
238pub(crate) fn parse_side<'a>(block: &'a Block<impl AsRef<str>>) -> Side<'a> {
239 assert_eq!(block.name.as_ref(), "side");
240
241 let mut plane = None;
243 let mut material = None;
244 let mut uaxis = None;
245 let mut vaxis = None;
246 let mut lightmapscale = None;
247 let mut smoothing_groups = None;
248 for prop in block.props.iter() {
249 let Property { key, value } = prop;
250 let key = key.as_ref();
251 let value = value.as_ref();
252
253 match key {
254 "id" => {}
255 "plane" => {
256 let s = value.trim_start_matches('(').trim_end_matches(')');
258 let spaces_split = s.split(") (");
259 let triplets: Vec<Vector3<f32>> = spaces_split
262 .map(|three_floats| {
263 let three_floats: Vec<f32> = three_floats
264 .split(' ')
265 .map(|float| float.parse::<f32>().expect("Error parsing float"))
266 .collect();
267 assert_eq!(three_floats.len(), 3, "A point must have 3 numbers");
268 let array: [_; 3] = three_floats.try_into().unwrap();
269 Vector3::from(array)
270 })
271 .collect();
272
273 let [bl, tl, tr]: [_; 3] = triplets.try_into().expect("A plane must have 3 points");
275
276 plane = Some(Plane::new(bl, tl, tr));
277 }
278 "material" => {
279 material = Some(value);
280 }
281 "uaxis" => {
282 uaxis = Some(parse_uvaxis(value));
283 }
284 "vaxis" => {
285 vaxis = Some(parse_uvaxis(value));
286 }
287 "rotation" => {}
288 "lightmapscale" => {
289 lightmapscale = value.parse::<u8>().ok();
290 }
291 "smoothing_groups" => {
292 smoothing_groups = value.parse::<i32>().ok();
293 }
294 key => panic!("Unexpected key {key}"),
295 }
296 }
297
298 let mut disp_info = None;
300 for block in block.blocks.iter() {
301 let name = block.name.as_ref();
302 match name {
303 "dispinfo" => {
304 disp_info = Some(parse_dispinfo(block).unwrap());
305 }
306 block => panic!("Unexpected block {block}"),
307 }
308 }
309
310 let texture = Texture::new(
311 material.unwrap().into(),
312 uaxis.unwrap(),
313 vaxis.unwrap(),
314 lightmapscale.unwrap(),
315 );
316 let plane = plane.unwrap();
317 let disp = disp_info.map(|disp_info| Displacement::from_disp_info(disp_info, plane.clone()));
318
319 Side { plane, texture, disp }
320}
321
322fn parse_uvaxis(s: &str) -> UVAxis<f32> {
323 let mut floats = s
325 .split(|char| "[] ".contains(char))
326 .filter(|s| !s.is_empty())
327 .map(|s| s.parse::<f32>().expect("Error parsing f32"));
328 let [x, y, z, trans, scale] = floats.next_chunk2().expect("Bad UVAxis");
329 assert!(floats.next().is_none(), "Too many");
330 UVAxis::new(x, y, z, trans, scale)
331}
332
333fn parse_dispinfo<'a>(block: &Block<impl AsRef<str>>) -> Result<DispInfo, &'static str> {
334 assert_eq!(block.name.as_ref(), "dispinfo");
335
336 let mut power = None;
338 let mut start_position = None;
339 let mut flags = None;
340 let mut elevation = None;
341 let mut is_subdiv = None;
342
343 for prop in block.props.iter() {
344 let Property { key, value } = prop;
345 let key = key.as_ref();
346 let value = value.as_ref();
347
348 match key {
349 "power" => {
350 power = value.parse::<u32>().ok();
351 }
352 "startposition" => {
353 start_position = value.parse::<Vector3<_>>().ok();
354 }
355 "flags" => {
356 flags = value.parse::<i32>().ok();
357 }
358 "elevation" => {
359 elevation = value.parse::<f32>().ok();
360 }
361 "subdiv" => {
362 is_subdiv = value.parse::<i32>().ok();
363 }
364 _ => return Err("Unexpected key"),
365 }
366 }
367
368 let mut normals = None;
370 let mut distances = None;
371 let mut offsets = None;
372 let mut offset_normals = None;
373 let mut alphas = None;
374 let mut triangle_tags = None;
375 let mut allowed_verts = None;
376
377 for block in block.blocks.iter() {
378 let name = block.name.as_ref();
379
380 match name {
381 "normals" => {
382 normals = parse_vec2d::<f32>(block).ok();
383 }
384 "distances" => {
385 distances = parse_vec2d::<f32>(block).ok();
386 }
387 "offsets" => {
388 offsets = parse_vec2d::<f32>(block).ok();
389 }
390 "offset_normals" => {
391 offset_normals = parse_vec2d::<f32>(block).ok();
392 }
393 "alphas" => {
394 alphas = parse_vec2d::<f32>(block).ok();
395 }
396 "triangle_tags" => {
397 triangle_tags = parse_vec2d::<i32>(block).ok();
398 }
399 "allowed_verts" => {
400 allowed_verts = parse_seps_chunks_exact(block.props[0].value.as_ref(), " ").ok();
401 }
402 _ => return Err("Unexpected block"),
403 }
404 }
405
406 let normals = vec2d_f32_to_vector3(normals.ok_or("Normal misparse or missing")?);
407 let offsets = vec2d_f32_to_vector3(offsets.ok_or("offsets misparse or missing")?);
408 let offset_normals =
409 vec2d_f32_to_vector3(offset_normals.ok_or("offset_normals misparse or missing")?);
410
411 Ok(DispInfo {
414 power: power.ok_or("power is missing")?,
415 start_position: start_position.ok_or("start_position is missing")?,
416 flags: flags.ok_or("flags is missing")?,
417 elevation: elevation.ok_or("elevation is missing")?,
418 is_subdiv: is_subdiv.ok_or("is_subdiv is missing")? != 0,
419 normals,
420 distances: distances.ok_or("distances is missing")?,
421 offsets,
422 offset_normals,
423 alphas: alphas.ok_or("alphas is missing")?,
424 triangle_tags: triangle_tags.ok_or("triangle_tags is missing")?,
425 allowed_verts: allowed_verts.ok_or("allowed_verts is missing")?,
426 })
427}
428
429fn parse_seps_chunks_exact<const N: usize, T: FromStr>(
433 s: &str, seperators: &str,
434) -> Result<[T; N], &'static str> {
435 let mut strs = s.split(|char| seperators.contains(char)).filter(|s| !s.is_empty());
437 let str_arr = strs.next_chunk2().ok_or("Too short")?;
438 if strs.next().is_some() {
439 return Err("Too long");
441 }
442 let parsed = str_arr.try_map2(|s| s.parse::<T>()).map_err(|_| "Error parsing")?;
443
444 Ok(parsed)
445}
446
447fn parse_seps_chunks<'a, 'b, T: FromStr + std::fmt::Debug>(
451 s: &'a str, seperators: &'b str,
452) -> Result<Vec<T>, &'static str>
453where
454 <T as FromStr>::Err: std::fmt::Debug,
455{
456 let strs = s.split(|char| seperators.contains(char)).filter(|s| !s.is_empty());
458 dbg!(strs.clone().map(|s| s.parse::<T>()).collect::<Vec<_>>());
459 strs.map(|s| s.parse::<T>().map_err(|_| "Error parsing")).collect()
460}
461
462impl FromStr for Vector3<f32> {
463 type Err = &'static str;
464
465 fn from_str(s: &str) -> Result<Self, Self::Err> {
466 dbg!(s);
467 match parse_seps_chunks_exact(s, "()[] ") {
468 Ok(array) => Ok(Vector3::from(array)),
469 Err(_) => Err("Error parsing Vector3"),
470 }
471 }
472}
473
474fn vec2d_f32_to_vector3(vec2d: Vec2d<f32>) -> Vec2d<Vector3<f32>> {
475 Vec2d::from_parts(f32s_to_vector3s(&vec2d.inner), [vec2d.strides[0] / 3, 1])
476}
477
478fn f32s_to_vector3s(f32s: &[f32]) -> Vec<Vector3<f32>> {
479 f32s.chunks_exact(3)
480 .map(|slice| {
481 let arr: [_; 3] = slice.try_into().unwrap();
482 Vector3::from(arr)
483 })
484 .collect()
485}
486
487fn parse_vec2d<'a, T: FromStr + std::fmt::Debug>(
488 block: &Block<impl AsRef<str>>,
489) -> Result<Vec2d<T>, &'static str>
490where
491 <T as FromStr>::Err: std::fmt::Debug,
492{
493 let mut output = Vec::new();
494 let mut lens = Vec::with_capacity(block.props.len());
496
497 for (i, prop) in block.props.iter().enumerate() {
498 let Property { key, value } = prop;
499 let key = key.as_ref();
500 let value = value.as_ref();
501 let row_key = format!("row{i}");
502
503 if row_key == key {
505 let values = parse_seps_chunks(value, " ")?.into_iter();
506 lens.push(values.len());
507 output.extend(values);
508 } else {
509 return Err("Bad row key");
510 }
511 }
512
513 let width = lens.first().copied().unwrap_or(0);
514 if !lens.iter().copied().all(|v| v == width) {
515 return Err("Rows must be the same length");
516 }
517
518 Ok(Vec2d::from_parts(output, Vec2d::strides(width)))
519}
520
521