Improved system parser

master
Mark 2023-12-25 10:30:27 -08:00
parent 4f0d77eeea
commit fd94cd6701
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
4 changed files with 93 additions and 46 deletions

View File

@ -4,14 +4,25 @@ name = "12 Autumn above"
[object.star] [object.star]
sprite = "star::star" sprite = "star::star"
center = [0.0, 0.0] position = [0.0, 0.0]
size = 50 size = 1000
parallax = 1.0 parallax = 20.0
[object.earth] [object.earth]
sprite = "planet::earth" sprite = "planet::earth"
center = "star" position.center = "star"
radius = 1000 position.radius = 4000
angle = 0 position.angle = 0
size = 100 size = 1000
parallax = 1.0 parallax = 10.0
[object.luna]
sprite = "planet::luna"
position.center = "earth"
position.radius = 1600
position.angle = 135
size = 500
angle = -45
parallax = 7.8

View File

@ -1,6 +1,6 @@
use anyhow::{bail, Result}; use anyhow::{bail, Context, Result};
use cgmath::{Deg, Point2}; use cgmath::{Deg, Point2};
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use crate::physics::{Pfloat, Polar}; use crate::physics::{Pfloat, Polar};
@ -24,25 +24,37 @@ pub(in crate::content) mod toml {
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Object { pub struct Object {
pub sprite: String, pub sprite: String,
pub center: Center, pub position: Position,
pub size: Pfloat, pub size: Pfloat,
pub parallax: Pfloat, pub parallax: Pfloat,
#[serde(default)] pub radius: Option<Pfloat>,
pub angle: Option<Pfloat>,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum Position {
Polar(PolarCoords),
Cartesian(Coordinates),
}
#[derive(Debug, Deserialize)]
pub struct PolarCoords {
pub center: Coordinates,
pub radius: Pfloat, pub radius: Pfloat,
#[serde(default)]
pub angle: Pfloat, pub angle: Pfloat,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Center { pub enum Coordinates {
Label(String), Label(String),
Coords([Pfloat; 2]), Coords([Pfloat; 2]),
} }
impl ToString for Center { impl ToString for Coordinates {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
Self::Label(s) => s.to_owned(), Self::Label(s) => s.to_owned(),
@ -61,25 +73,57 @@ pub struct System {
#[derive(Debug)] #[derive(Debug)]
pub struct Object { pub struct Object {
pub sprite: String, pub sprite: String,
pub position: Polar, pub position: Point2<f32>,
pub size: Pfloat, pub size: Pfloat,
pub parallax: Pfloat, pub parallax: Pfloat,
pub angle: Deg<Pfloat>,
} }
fn resolve_center( fn resolve_coordinates(
objects: &HashMap<String, toml::Object>,
cor: &toml::Coordinates,
mut cycle_detector: HashSet<String>,
) -> Result<Point2<f32>> {
match cor {
toml::Coordinates::Coords(c) => Ok((*c).into()),
toml::Coordinates::Label(l) => {
if cycle_detector.contains(l) {
bail!(
"Found coordinate cycle: `{}`",
cycle_detector.iter().fold(String::new(), |sum, a| {
if sum.is_empty() {
a.to_string()
} else {
sum + " -> " + a
}
})
);
}
cycle_detector.insert(l.to_owned());
let p = match objects.get(l) {
Some(p) => p,
None => bail!("Could not resolve coordinate label `{l}`"),
};
Ok(resolve_position(&objects, &p, cycle_detector)
.with_context(|| format!("In object {:#?}", l))?)
}
}
}
fn resolve_position(
objects: &HashMap<String, toml::Object>, objects: &HashMap<String, toml::Object>,
obj: &toml::Object, obj: &toml::Object,
) -> Option<Point2<f32>> { cycle_detector: HashSet<String>,
match &obj.center { ) -> Result<Point2<f32>> {
toml::Center::Label(s) => Some( match &obj.position {
Polar { toml::Position::Cartesian(c) => Ok(resolve_coordinates(objects, c, cycle_detector)?),
center: resolve_center(&objects, objects.get(s)?)?, toml::Position::Polar(p) => Ok(Polar {
radius: obj.radius, center: resolve_coordinates(&objects, &p.center, cycle_detector)?,
angle: Deg(obj.angle), radius: p.radius,
angle: Deg(p.angle),
} }
.to_cartesian(), .to_cartesian()),
),
toml::Center::Coords(v) => Some((*v).into()),
} }
} }
@ -88,26 +132,16 @@ impl System {
let mut objects = Vec::new(); let mut objects = Vec::new();
for (label, obj) in &value.object { for (label, obj) in &value.object {
let center = match resolve_center(&value.object, obj) { let mut cycle_detector = HashSet::new();
Some(v) => v, cycle_detector.insert(label.to_owned());
None => {
bail!(
"could not resolve center label `{}` in `object.{}`",
obj.center.to_string(),
label
);
}
};
objects.push(Object { objects.push(Object {
sprite: obj.sprite.clone(), sprite: obj.sprite.clone(),
position: Polar { position: resolve_position(&value.object, &obj, cycle_detector)
center, .with_context(|| format!("In object {:#?}", label))?,
radius: obj.radius,
angle: Deg(obj.angle),
},
size: obj.size, size: obj.size,
parallax: obj.parallax, parallax: obj.parallax,
angle: Deg(obj.angle.unwrap_or(0.0)),
}); });
} }

View File

@ -7,15 +7,16 @@ pub struct Doodad {
pub pos: Point2<Pfloat>, pub pos: Point2<Pfloat>,
pub parallax: Pfloat, pub parallax: Pfloat,
pub size: Pfloat, pub size: Pfloat,
pub angle: Deg<Pfloat>,
} }
impl Spriteable for Doodad { impl Spriteable for Doodad {
fn get_sprite(&self) -> Sprite { fn get_sprite(&self) -> Sprite {
return Sprite { return Sprite {
texture: self.sprite.clone(), texture: self.sprite.clone(),
pos: self.pos,
angle: Deg(0.0),
scale: 1.0, scale: 1.0,
pos: self.pos,
angle: self.angle,
size: self.size, size: self.size,
parallax: self.parallax, parallax: self.parallax,
}; };

View File

@ -50,10 +50,11 @@ impl System {
for o in &ct.objects { for o in &ct.objects {
s.bodies.push(Doodad { s.bodies.push(Doodad {
pos: o.position.to_cartesian(), pos: o.position,
sprite: SpriteTexture(o.sprite.to_owned()), sprite: SpriteTexture(o.sprite.to_owned()),
size: o.size, size: o.size,
parallax: o.parallax, parallax: o.parallax,
angle: o.angle,
}); });
} }