|
- use regex::{Regex, RegexBuilder, Captures};
- use std::sync::RwLock;
-
- use crate::instruction::{Instruction, InstructionType, Vector3, CameraData};
-
- lazy_static!{
- static ref REGEX_CACHE: RwLock<RegexPatterns> = RwLock::new(RegexPatterns{
- single_instruction: RegexBuilder::new(r"(\w+)\s*\((\d+(?:\.\d+)?),?\s*(\d+(?:\.\d+)?),?\s*(\d+(?:\.\d+)?)(?:,?\s*(\d+(?:\.\d+)?))?\s*\)").case_insensitive(true).build().unwrap(),
- //multi_instruction: RegexBuilder::new("").case_insensitive(true).build().unwrap(),
- });
- }
-
- struct RegexPatterns {
- single_instruction: Regex,
- }
-
-
- impl Instruction {
- pub fn parse_line(line: &str) -> Result<Instruction, String> {
- let cache_lock = REGEX_CACHE.read().unwrap();
- if count(line, '(') > 1 {
- // do multi parsing
- let mut instructions = Vec::<InstructionType>::new();
- for capture in cache_lock.single_instruction.captures_iter(line) {
- let ins = Self::parse_single(&capture)?;
- instructions.push(ins);
- }
- return Ok(Instruction {
- instr: InstructionType::Multi{instructions},
- start: 0.0,
- progress: 0.0,
- base: CameraData::default(),
- })
- } else {
- // assume single instruction on line
- if let Some(captures) = cache_lock.single_instruction.captures(line) {
- let instr = Self::parse_single(&captures)?;
- return Ok(Instruction {
- instr,
- start: 0.0,
- progress: 0.0,
- base: CameraData::default(),
- })
- } else {
- return Err("Invalid line".to_string());
- }
- }
- }
-
- fn parse_single(c: &Captures) -> Result<InstructionType, String> {
- let name = c.get(1).unwrap().as_str();
- let param1 = c.get(2).unwrap().as_str().parse::<f64>().unwrap();
- let param2 = c.get(3).unwrap().as_str().parse::<f64>().unwrap();
- let param3 = c.get(4).unwrap().as_str().parse::<f64>().unwrap();
- // optional 4th param
- // let param4 = c.get(5).unwrap().as_str().parse::<f64>();
- match name.to_uppercase().as_str() {
- "TRACK" => {
- if let Some(param4) = c.get(5) {
- Ok(InstructionType::Track {
- vector: Vector3{x: param1, y: param2, z: param3},
- time: param4.as_str().parse::<f64>().unwrap(),
- })
- } else {
- Ok(InstructionType::Track {
- vector: Vector3{x: param1, y: param2, z: param3},
- time: 0.0,
- })
- }
- },
- "MOVE" => Ok(InstructionType::Move {
- vector: Vector3{x: param1, y: param2, z: param3},
- }),
- "ROTATE" => {
- if let Some(param4) = c.get(5) {
- Ok(InstructionType::Rotate {
- vector: Vector3{x: param1, y: param2, z: param3},
- time: param4.as_str().parse::<f64>().unwrap(),
- })
- } else {
- Ok(InstructionType::Track {
- vector: Vector3{x: param1, y: param2, z: param3},
- time: 0.0,
- })
- }
- },
- "LOOK" => Ok(InstructionType::Look {
- vector: Vector3{x: param1, y: param2, z: param3},
- }),
- _ => Err(format!("Invalid instruction {}", name))
- }
- }
-
- pub fn start(&mut self, now: f64, base: CameraData) {
- self.start = now;
- self.base = base;
- }
-
- pub fn lerp(&mut self, now: f64) -> CameraData {
- self.progress += now;
- match self.instr {
- InstructionType::Look {..} | InstructionType::Move {..} => self.instr.lerp(self.start, now),
- InstructionType::Track {..} | InstructionType::Rotate {..} | InstructionType::Multi{..} => self.base + self.instr.lerp(self.start, now),
- }
- }
-
- pub fn done(&self) -> bool {
- !(self.progress < (self.start + self.instr.time()))
- }
- }
-
- // string helper functions
- fn count(target: &str, chr: char) -> usize {
- let mut times: usize = 0;
- for c in target.chars() {
- if chr == c {
- times+=1;
- }
- }
- times
- }
|