From 3f3d7ef00111793ed295b2af0211c8805885330f Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Sat, 31 Aug 2024 21:14:25 -0700 Subject: [PATCH] Parsing transform from tokens --- assets/scenes/00.scene | 2 +- assets/scenes/00/a.entity | 3 - assets/scenes/00/camera.entity | 2 + assets/scenes/00/light.entity | 3 + assets/scenes/00/van.entity | 3 + src/main.rs | 7 +- src/parser.rs | 354 +++++++++++++++++++++++++-------- src/save.rs | 16 +- 8 files changed, 294 insertions(+), 96 deletions(-) create mode 100644 assets/scenes/00/camera.entity create mode 100644 assets/scenes/00/light.entity create mode 100644 assets/scenes/00/van.entity diff --git a/assets/scenes/00.scene b/assets/scenes/00.scene index 37e8e3d..3b302a8 100644 --- a/assets/scenes/00.scene +++ b/assets/scenes/00.scene @@ -1 +1 @@ -00/a.entity +00/camera.entity diff --git a/assets/scenes/00/a.entity b/assets/scenes/00/a.entity index 05e88ff..e69de29 100644 --- a/assets/scenes/00/a.entity +++ b/assets/scenes/00/a.entity @@ -1,3 +0,0 @@ -name "Hello world" -# camera3d -# transform ... diff --git a/assets/scenes/00/camera.entity b/assets/scenes/00/camera.entity new file mode 100644 index 0000000..2d67142 --- /dev/null +++ b/assets/scenes/00/camera.entity @@ -0,0 +1,2 @@ +camera +; transform translation 2.0 2.0 2.0 ... diff --git a/assets/scenes/00/light.entity b/assets/scenes/00/light.entity new file mode 100644 index 0000000..fe09495 --- /dev/null +++ b/assets/scenes/00/light.entity @@ -0,0 +1,3 @@ +; spatial3d +; transform ... +; pointLight color #ffffff intensity 800 diff --git a/assets/scenes/00/van.entity b/assets/scenes/00/van.entity new file mode 100644 index 0000000..9a55bb2 --- /dev/null +++ b/assets/scenes/00/van.entity @@ -0,0 +1,3 @@ +# spatial3d +# transform ... +# model "models/van.glb" diff --git a/src/main.rs b/src/main.rs index 97978e6..3b575d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,12 @@ fn main() { // .add_plugins(menu::MenuPlugin) // .add_plugins(window::WindowPlugin) .add_plugins(save::SavePlugin { - fns: vec![parse_save_name], + fns: vec![ + parse_save_name, + parse_save_camera, + parse_save_visibility, + parse_save_transform, + ], }) .run(); } diff --git a/src/parser.rs b/src/parser.rs index f5d8cbe..bb2aa56 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,3 +1,15 @@ +use bevy::{ + core_pipeline::{ + core_3d::graph::Core3d, + tonemapping::{DebandDither, Tonemapping}, + }, + render::{ + camera::{CameraMainTextureUsages, CameraRenderGraph, Exposure}, + primitives::Frustum, + view::{ColorGrading, VisibleEntities}, + }, +}; + use crate::prelude::*; #[derive(Error, Debug)] @@ -33,21 +45,23 @@ pub(crate) fn tokenize(line: &str) -> Vec { let mut tokens = Vec::new(); // Check for comment - if let Ok((_, (_start, content))) = tuple((char::<&str, ()>('#'), not_line_ending))(line) { + if let Ok((_, (_start, content))) = tuple((char::<&str, ()>(';'), not_line_ending))(line) { tokens.push(Token::Comment(content.strip_prefix(" ").unwrap().into())); } else { // Check for all other token types in a loop while l.len() > 0 { - if let Ok((rem, (_, s, _))) = tuple(( + if let Ok((rem, (_, _, s, _, _))) = tuple(( + space0, char::<&str, ()>('"'), take_until("\""), char::<&str, ()>('"'), + space0, ))(l) { debug!("Parsed string {:?}", s); tokens.push(Token::Str(s.into())); l = rem; - } else if let Ok((rem, num)) = float::<&str, ()>(l) { + } else if let Ok((rem, (_, num, _))) = tuple((space0, float::<&str, ()>, space0))(l) { debug!("Parsed float {:?}", num); tokens.push(Token::Num(num.into())); l = rem; @@ -69,7 +83,6 @@ pub(crate) fn tokenize(line: &str) -> Vec { } } } - debug!("Parsed tokens: {:?}", tokens); tokens @@ -96,34 +109,156 @@ fn test_tokenize() { /// /// Returns reflected `Transform` /// +/// A fairly complicated parse function because Transform is sort of 3 components in one +/// (translation, rotation, scale). +/// +/// It might get more complicated as I add more ways to express rotation! +/// pub(crate) fn parse_save_transform( tokens: &Vec, -) -> Result, SaveEntityParseError> { - // Tag(Transform), - // Tag(Translation), Number, Number, Number - // Tag(Rotation), Number, Number, Number, Number - // Tag(Scale), Number, Number, Number - - // return Err(SaveEntityParseError::Transform); - - todo!("parse_save_transform"); +) -> Result>, SaveEntityParseError> { + if tokens[0] == Token::Tag("transform".into()) { + let mut t = Transform::default(); + let mut idx = 1; + while idx < tokens.len() { + match tokens.get(idx) { + Some(Token::Tag(attr)) => { + idx += 1; + match attr.as_str() { + "translation" => { + if let Token::Num(x) = tokens[idx] { + t.translation.x = x; + idx += 1; + } + if let Token::Num(y) = tokens[idx] { + t.translation.y = y; + idx += 1; + } + if let Token::Num(z) = tokens[idx] { + t.translation.z = z; + idx += 1; + } + info!("{:?}", t.translation); + } + "scale" => { + if let Token::Num(x) = tokens[idx] { + t.scale.x = x; + idx += 1; + } + if let Token::Num(y) = tokens[idx] { + t.scale.y = y; + idx += 1; + } + if let Token::Num(z) = tokens[idx] { + t.scale.z = z; + idx += 1; + } + } + "rotation" => { + let x = match tokens.get(idx) { + Some(Token::Num(x)) => { + idx += 1; + *x + } + _ => 0.0, + }; + let y = match tokens.get(idx) { + Some(Token::Num(y)) => { + idx += 1; + *y + } + _ => 0.0, + }; + let z = match tokens.get(idx) { + Some(Token::Num(z)) => { + idx += 1; + *z + } + _ => 0.0, + }; + let w = match tokens.get(idx) { + Some(Token::Num(w)) => { + idx += 1; + *w + } + _ => 1.0, + }; + t.rotation = Quat::from_xyzw(x, y, z, w); + } + _ => idx += 1, + } + } + _ => idx += 1, + } + } + println!("Parsed transform: {:?}", t); + Ok(vec![ + t.clone_value(), + GlobalTransform::default().clone_value(), + ]) + } else { + return Err(SaveEntityParseError::Component("Transform".into())); + } } #[test] fn test_parse_transform() { - let line = "transform translation 1.0 2.0 3.0 rotation 0.1 0.2 0.3 1.0 scale 1.1 1.2 1.3"; - let tokens = tokenize(line); - let parsed = parse_save_transform(&tokens).unwrap(); - let expected = Transform { - translation: Vec3::new(1.0, 2.0, 3.0), - rotation: Quat::from_xyzw(0.1, 0.2, 0.3, 1.0), - scale: Vec3::new(1.1, 1.2, 1.3), - }; - - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); + { + let line = "transform translation 1.0 2.0 3.0 rotation 0.1 0.2 0.3 1.0 scale 1.1 1.2 1.3"; + let tokens = tokenize(line); + let parsed = parse_save_transform(&tokens).unwrap(); + let t = Transform { + translation: Vec3::new(1.0, 2.0, 3.0), + rotation: Quat::from_xyzw(0.1, 0.2, 0.3, 1.0), + scale: Vec3::new(1.1, 1.2, 1.3), + }; + let gt = GlobalTransform::default(); + let expected = vec![t.clone_value(), gt.clone_value()]; + + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); + } + { + let line = "transform translation ... rotation ... scale ..."; + let tokens = tokenize(line); + let parsed = parse_save_transform(&tokens).unwrap(); + let t = Transform::default(); + let gt = GlobalTransform::default(); + let expected = vec![t.clone_value(), gt.clone_value()]; + + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); + } + { + let line = "transform ..."; + let tokens = tokenize(line); + let parsed = parse_save_transform(&tokens).unwrap(); + let t = Transform::default(); + let gt = GlobalTransform::default(); + let expected = vec![t.clone_value(), gt.clone_value()]; + + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); + } + { + let line = "transform translation 1.0 ... rotation 2.0 ... scale 3.0 ..."; + let tokens = tokenize(line); + let parsed = parse_save_transform(&tokens).unwrap(); + let t = Transform { + translation: Vec3::new(1.0, 0.0, 0.0), + rotation: Quat::from_xyzw(2.0, 0.0, 0.0, 1.0), + scale: Vec3::new(3.0, 1.0, 1.0), + }; + let gt = GlobalTransform::default(); + let expected = vec![t.clone_value(), gt.clone_value()]; + + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); + } } /// @@ -131,11 +266,11 @@ fn test_parse_transform() { /// pub(crate) fn parse_save_name( tokens: &Vec, -) -> Result, SaveEntityParseError> { +) -> Result>, SaveEntityParseError> { if let Some((Token::Tag(t), &[Token::Str(ref s)])) = tokens.split_first() && *t == String::from("name") { - Ok(Name::new(s.clone()).clone_value()) + Ok(vec![Name::new(s.clone()).clone_value()]) } else { Err(SaveEntityParseError::Component("Name".into())) } @@ -147,23 +282,21 @@ fn test_parse_name() { let line = "name Van"; let tokens = tokenize(line); let parsed = parse_save_name(&tokens).unwrap(); - let expected = Name::new("Van"); + let expected = vec![Name::new("Van").clone_value()]; - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); } { let line = "name Big Mike"; let tokens = tokenize(line); let parsed = parse_save_name(&tokens).unwrap(); - let expected = Name::new("Big Mike"); + let expected = vec![Name::new("Big Mike").clone_value()]; - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); } } @@ -215,7 +348,7 @@ fn test_parse_model() { .unwrap()); } -#[derive(Debug, Default, PartialEq, Reflect, Clone)] +#[derive(Component, Debug, Default, PartialEq, Reflect, Clone)] #[reflect_value(Component, Default, PartialEq)] pub(crate) enum SaveCameraRenderTarget { #[default] @@ -223,24 +356,29 @@ pub(crate) enum SaveCameraRenderTarget { Window(PathBuf), } -impl Component for SaveCameraRenderTarget { - const STORAGE_TYPE: StorageType = StorageType::Table; - - fn register_component_hooks(hooks: &mut ComponentHooks) { - todo!("Assign Render Target") - } -} - /// -/// Returns a reflected `SaveCameraRenderTarget +/// Returns a reflected `Camera3d` /// pub(crate) fn parse_save_camera( tokens: &Vec, -) -> Result, SaveEntityParseError> { - todo!("parse_save_camera"); - - // Nothing parsed well - // Err(SaveEntityParseError::Camera) +) -> Result>, SaveEntityParseError> { + if tokens[0] == Token::Tag("camera".into()) { + Ok(vec![ + Camera::default().clone_value(), + CameraRenderGraph::new(Core3d).clone_value(), + Projection::default().clone_value(), + VisibleEntities::default().clone_value(), + Frustum::default().clone_value(), + Camera3d::default().clone_value(), + Tonemapping::default().clone_value(), + DebandDither::default().clone_value(), + ColorGrading::default().clone_value(), + Exposure::default().clone_value(), + CameraMainTextureUsages::default().clone_value(), + ]) + } else { + Err(SaveEntityParseError::Component("camera".into())) + } } #[test] @@ -249,38 +387,56 @@ fn test_parse_camera() { let line = "camera"; let tokens = tokenize(line); let parsed = parse_save_camera(&tokens).unwrap(); - let expected = SaveCameraRenderTarget::Default; - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); - } - { - let line = "camera target window"; - let tokens = tokenize(line); - let parsed = parse_save_camera(&tokens).unwrap(); - let expected = SaveCameraRenderTarget::Default; - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); - } - { - let line = "camera target"; - let tokens = tokenize(line); - let parsed = parse_save_camera(&tokens); - assert!(parsed.is_err()); - } - { - let line = "camera target window \"some.entity\""; - let tokens = tokenize(line); - let parsed = parse_save_camera(&tokens).unwrap(); - let expected = SaveCameraRenderTarget::Window("some.entity".into()); - assert!(expected - .clone_value() - .reflect_partial_eq(parsed.as_reflect()) - .unwrap()); + let expected = vec![ + Camera::default().clone_value(), + CameraRenderGraph::new(Core3d).clone_value(), + Projection::default().clone_value(), + VisibleEntities::default().clone_value(), + Frustum::default().clone_value(), + Camera3d::default().clone_value(), + Tonemapping::default().clone_value(), + DebandDither::default().clone_value(), + ColorGrading::default().clone_value(), + Exposure::default().clone_value(), + CameraMainTextureUsages::default().clone_value(), + ]; + parsed + .iter() + .zip(expected) + .for_each(|(p, e)| match e.reflect_partial_eq(p.as_reflect()) { + Some(r) => assert!(r), + None => warn!( + "Type {:?} does not support reflection", + e.get_represented_type_info().unwrap() + ), + }); } + // { + // let line = "camera target window"; + // let tokens = tokenize(line); + // let parsed = parse_save_camera(&tokens).unwrap(); + // let expected = SaveCameraRenderTarget::Default; + // assert!(expected + // .clone_value() + // .reflect_partial_eq(parsed.as_reflect()) + // .unwrap()); + // } + // { + // let line = "camera target"; + // let tokens = tokenize(line); + // let parsed = parse_save_camera(&tokens); + // assert!(parsed.is_err()); + // } + // { + // let line = "camera target window \"some.entity\""; + // let tokens = tokenize(line); + // let parsed = parse_save_camera(&tokens).unwrap(); + // let expected = SaveCameraRenderTarget::Window("some.entity".into()); + // assert!(expected + // .clone_value() + // .reflect_partial_eq(parsed.as_reflect()) + // .unwrap()); + // } { let line = "notcamera"; let tokens = tokenize(line); @@ -289,6 +445,36 @@ fn test_parse_camera() { } } +/// encapsulates the spatial 3d bits of an entity +pub(crate) fn parse_save_visibility( + tokens: &Vec, +) -> Result>, SaveEntityParseError> { + if tokens[0] == Token::Tag("visible".into()) { + Ok(vec![ + Visibility::default().clone_value(), + InheritedVisibility::default().clone_value(), + ViewVisibility::default().clone_value(), + ]) + } else { + Err(SaveEntityParseError::Component("visibility".into())) + } +} + +#[test] +fn test_parse_visibility() { + let line = "visible"; + let tokens = tokenize(line); + let parsed = parse_save_visibility(&tokens).unwrap(); + let expected = vec![ + Visibility::default().clone_value(), + InheritedVisibility::default().clone_value(), + ViewVisibility::default().clone_value(), + ]; + parsed.iter().zip(expected).for_each(|(p, e)| { + assert!(e.clone_value().reflect_partial_eq(p.as_reflect()).unwrap()); + }); +} + /// SaveParent entity which is a reference to which entity this is a child of /// A run-time system converts this to a bevy Parent component #[derive(PartialEq, Debug, Reflect, Clone)] diff --git a/src/save.rs b/src/save.rs index 79cc67a..a90efc7 100644 --- a/src/save.rs +++ b/src/save.rs @@ -3,7 +3,7 @@ use std::any::TypeId; use crate::prelude::*; type ParseFn = - for<'a> fn(&'a Vec) -> Result, SaveEntityParseError>; + for<'a> fn(&'a Vec) -> Result>, SaveEntityParseError>; /// Menu Plugin; contains parser functions pub(crate) struct SavePlugin { @@ -84,12 +84,14 @@ impl SaveEntity { } else { // Run line against all parsers for f in fns { - if let Ok(c) = f(&tokens) { - // Bundle the Type ID with this entry for auditing purposes - let t = c.get_represented_type_info().unwrap().type_id(); - entity.components.push(SaveEntityComponent { - type_id: t, - data: c, + if let Ok(p) = f(&tokens) { + p.iter().for_each(|c| { + // Bundle the Type ID with this entry for auditing purposes + let t = c.get_represented_type_info().unwrap().type_id(); + entity.components.push(SaveEntityComponent { + type_id: t, + data: c.clone_value(), + }); }); good = true; }