use godot::{ builtin::{Basis, Quaternion}, prelude::{Color, Transform3D, Vector3}, }; use rosc::{OscMessage, OscType}; pub trait MessageBehavior { fn to_osc_message(&self) -> OscMessage; fn from_osc_message(msg: OscMessage) -> Result where Self: Sized; } struct VmcExtOk { loaded: i32, calibration_state: Option, calibration_mode: Option, tracking_status: Option, } impl MessageBehavior for VmcExtOk { fn to_osc_message(&self) -> OscMessage { let addr = String::from("/VMC/Ext/OK"); let mut args: Vec = vec![OscType::from(self.loaded)]; if self.calibration_state.is_some() { args.append(&mut vec![ OscType::from(self.calibration_state.unwrap()), OscType::from(self.calibration_mode.unwrap()), ]); } if self.tracking_status.is_some() { args.push(OscType::from(self.tracking_status.unwrap())); } return OscMessage { addr, args }; } fn from_osc_message(msg: OscMessage) -> Result { let mut result = VmcExtOk { loaded: -1, calibration_state: None, calibration_mode: None, tracking_status: None, }; if msg.args.len() == 1 || msg.args.len() == 3 || msg.args.len() == 4 { match msg.args[0] { OscType::Int(i) => { result.loaded = i; } _ => { return Err(String::from("arg type invalid")); } } } else { return Err(String::from("arg count invalid")); } if msg.args.len() == 3 || msg.args.len() == 4 { match msg.args[1] { OscType::Int(i) => { result.calibration_state = Some(i); } _ => { return Err(String::from("arg type invalid")); } } match msg.args[2] { OscType::Int(i) => { result.calibration_mode = Some(i); } _ => { return Err(String::from("arg type invalid")); } } } if msg.args.len() == 4 { match msg.args[3] { OscType::Int(i) => { result.tracking_status = Some(i); } _ => { return Err(String::from("arg type invalid")); } } } return Ok(result); } } struct VmcExtT { time: f32, } impl MessageBehavior for VmcExtT { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/T"), args: vec![OscType::from(self.time)], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 1 { return Err(String::from("arg count invalid")); } match msg.args[0] { OscType::Float(f) => return Ok(VmcExtT { time: f }), _ => return Err(String::from("arg type invalid")), } } } struct VmcExtRootPos { name: String, transform: Transform3D, mr_scale: Option, mr_offset: Option, } impl MessageBehavior for VmcExtRootPos { fn to_osc_message(&self) -> OscMessage { let addr = String::from("/VMC/Ext/Root/Pos"); let quat = self.transform.basis.to_quat(); let mut args: Vec = vec![ OscType::from(self.name.to_owned()), OscType::from(self.transform.origin.x), OscType::from(self.transform.origin.y), OscType::from(self.transform.origin.z), OscType::from(quat.x), OscType::from(quat.y), OscType::from(quat.z), OscType::from(quat.w), ]; if self.mr_offset.is_some() { args.append(&mut vec![ OscType::from(self.mr_scale.unwrap().x), OscType::from(self.mr_scale.unwrap().y), OscType::from(self.mr_scale.unwrap().z), OscType::from(self.mr_offset.unwrap().x), OscType::from(self.mr_offset.unwrap().y), OscType::from(self.mr_offset.unwrap().z), ]); } return OscMessage { addr, args }; } fn from_osc_message(msg: OscMessage) -> Result { let mut result: VmcExtRootPos; if msg.args.len() == 8 || msg.args.len() == 14 { let mut origin = Vector3::new(0.0, 0.0, 0.0); let name: String; match &msg.args[0] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => origin.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Float(f) => origin.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => origin.z = f, _ => return Err(String::from("arg type invalid")), } let mut quat = Quaternion { x: 0.0, y: 0.0, z: 0.0, w: 0.0, }; match msg.args[4] { OscType::Float(f) => quat.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[5] { OscType::Float(f) => quat.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[6] { OscType::Float(f) => quat.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[7] { OscType::Float(f) => quat.w = f, _ => return Err(String::from("arg type invalid")), } result = VmcExtRootPos { name, transform: Transform3D::new(Basis::from_quat(quat), origin), mr_scale: None, mr_offset: None, }; } else { return Err(String::from("arg count invalid")); } if msg.args.len() == 14 { result.mr_scale = Some(Vector3 { x: 0.0, y: 0.0, z: 0.0, }); result.mr_offset = Some(Vector3 { x: 0.0, y: 0.0, z: 0.0, }); match msg.args[8] { OscType::Float(f) => result.mr_scale.unwrap().x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[9] { OscType::Float(f) => result.mr_scale.unwrap().y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[10] { OscType::Float(f) => result.mr_scale.unwrap().z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[11] { OscType::Float(f) => result.mr_offset.unwrap().x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[12] { OscType::Float(f) => result.mr_offset.unwrap().y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[13] { OscType::Float(f) => result.mr_offset.unwrap().z = f, _ => return Err(String::from("arg type invalid")), } } return Ok(result); } } struct VmcExtBonePos { name: String, transform: Transform3D, } impl MessageBehavior for VmcExtBonePos { fn to_osc_message(&self) -> OscMessage { let quat = self.transform.basis.to_quat(); return OscMessage { addr: String::from("/VMC/Ext/Bone/Pos"), args: vec![ OscType::from(self.name.to_owned()), OscType::from(self.transform.origin.x), OscType::from(self.transform.origin.y), OscType::from(self.transform.origin.z), OscType::from(quat.x), OscType::from(quat.y), OscType::from(quat.z), OscType::from(quat.w), ], }; } fn from_osc_message(msg: OscMessage) -> Result { let name: String; let mut origin = Vector3::new(0.0, 0.0, 0.0); if msg.args.len() != 8 { return Err(String::from("arg count invalid")); } match &msg.args[0] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => origin.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Float(f) => origin.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => origin.z = f, _ => return Err(String::from("arg type invalid")), } let mut quat = Quaternion { x: 0.0, y: 0.0, z: 0.0, w: 0.0, }; match msg.args[4] { OscType::Float(f) => quat.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[5] { OscType::Float(f) => quat.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[6] { OscType::Float(f) => quat.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[7] { OscType::Float(f) => quat.w = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtBonePos { name, transform: Transform3D::new(Basis::from_quat(quat), origin), }); } } struct VmcExtBlendVal { name: String, value: f32, } impl MessageBehavior for VmcExtBlendVal { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Blend/Val"), args: vec![ OscType::from(self.name.to_owned()), OscType::from(self.value), ], }; } fn from_osc_message(msg: OscMessage) -> Result { let name: String; let value: f32; if msg.args.len() != 2 { return Err(String::from("arg count invalid")); } match &msg.args[0] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => value = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtBlendVal { name, value }); } } struct VmcExtCam { name: String, transform: Transform3D, fov: f32, } impl MessageBehavior for VmcExtCam { fn to_osc_message(&self) -> OscMessage { let quat = self.transform.basis.to_quat(); return OscMessage { addr: String::from("/VMC/Ext/Cam"), args: vec![ OscType::from(self.name.to_owned()), OscType::from(self.transform.origin.x), OscType::from(self.transform.origin.y), OscType::from(self.transform.origin.z), OscType::from(quat.x), OscType::from(quat.y), OscType::from(quat.z), OscType::from(quat.w), OscType::from(self.fov), ], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 9 { return Err(String::from("arg count invalid")); } let name: String; let mut origin = Vector3::new(0.0, 0.0, 0.0); let mut quat = Quaternion::new(0.0, 0.0, 0.0, 0.0); let fov: f32; match &msg.args[0] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => origin.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Float(f) => origin.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => origin.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[4] { OscType::Float(f) => quat.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[5] { OscType::Float(f) => quat.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[6] { OscType::Float(f) => quat.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[7] { OscType::Float(f) => quat.w = f, _ => return Err(String::from("arg type invalid")), } match msg.args[8] { OscType::Float(f) => fov = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtCam { name, transform: Transform3D::new(Basis::from_quat(quat), origin), fov, }); } } struct VmcExtCon { active: i32, name: String, is_left: i32, is_touch: i32, axis: Vector3, } impl MessageBehavior for VmcExtCon { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Cam"), args: vec![ OscType::from(self.active), OscType::from(self.name.to_owned()), OscType::from(self.is_left), OscType::from(self.is_touch), OscType::from(self.axis.x), OscType::from(self.axis.y), OscType::from(self.axis.z), ], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 7 { return Err(String::from("arg count invalid")); } let active: i32; let name: String; let is_left: i32; let is_touch: i32; let mut axis = Vector3::new(0.0, 0.0, 0.0); match msg.args[0] { OscType::Int(i) => active = i, _ => return Err(String::from("arg type invalid")), } if active > 2 || active < 0 { return Err(String::from("arg value invalid")); } match &msg.args[1] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg value invalid")), } match msg.args[2] { OscType::Int(i) => is_left = i, _ => return Err(String::from("arg type invalid")), } if is_left < 0 || is_left > 1 { return Err(String::from("arg value invalid")); } match msg.args[3] { OscType::Int(i) => is_touch = i, _ => return Err(String::from("arg type invalid")), } if is_touch < 0 || is_touch > 1 { return Err(String::from("arg value invalid")); } match msg.args[4] { OscType::Float(f) => axis.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[5] { OscType::Float(f) => axis.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[6] { OscType::Float(f) => axis.z = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtCon { active, name, is_left, is_touch, axis, }); } } struct VmcExtKey { active: bool, name: String, keycode: i32, } impl MessageBehavior for VmcExtKey { fn to_osc_message(&self) -> OscMessage { let mut args: Vec; if self.active { args = vec![OscType::from(1)]; } else { args = vec![OscType::from(0)]; } args.append(&mut vec![ OscType::from(self.name.to_owned()), OscType::from(self.keycode), ]); return OscMessage { addr: String::from("/VMC/Ext/Key"), args, }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 3 { return Err(String::from("arg count invalid")); } let active: bool; let name: String; let keycode: i32; match msg.args[0] { OscType::Int(i) => { if i == 1 { active = true; } else if i == 0 { active = false; } else { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } match &msg.args[1] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Int(i) => keycode = i, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtKey { active, name, keycode, }); } } struct VmcExtMidiNote { active: bool, channel: i32, note: i32, velocity: f32, } impl MessageBehavior for VmcExtMidiNote { fn to_osc_message(&self) -> OscMessage { let mut args: Vec; if self.active { args = vec![OscType::from(1)]; } else { args = vec![OscType::from(0)]; } args.append(&mut vec![ OscType::from(self.channel), OscType::from(self.note), OscType::from(self.velocity), ]); return OscMessage { addr: String::from("/VMC/Ext/Midi/Note"), args, }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 4 { return Err(String::from("arg count invalid")); } let active: bool; let channel: i32; let note: i32; let velocity: f32; match msg.args[0] { OscType::Int(i) => { if i == 1 { active = true; } else if i == 0 { active = false; } else { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Int(i) => channel = i, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Int(i) => note = i, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => velocity = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtMidiNote { active, channel, note, velocity, }); } } struct VmcExtMidiCcVal { knob: i32, value: f32, } impl MessageBehavior for VmcExtMidiCcVal { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Midi/CC/Val"), args: vec![OscType::from(self.knob), OscType::from(self.value)], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 2 { return Err(String::from("arg count invalid")); } let knob: i32; let value: f32; match msg.args[0] { OscType::Int(i) => knob = i, _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => value = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtMidiCcVal { knob, value }); } } struct VmcExtMidiCcBit { knob: i32, active: bool, } impl MessageBehavior for VmcExtMidiCcBit { fn to_osc_message(&self) -> OscMessage { let mut args = vec![OscType::from(self.knob)]; if self.active { args.push(OscType::from(1)); } else { args.push(OscType::from(0)); } return OscMessage { addr: String::from("/VMC/Ext/Midi/CC/Val"), args, }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 2 { return Err(String::from("arg count invalid")); } let knob: i32; let active: bool; match msg.args[0] { OscType::Int(i) => knob = i, _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Int(i) => { if i == 0 { active = false; } else if i == 1 { active = true; } else { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtMidiCcBit { knob, active }); } } struct DeviceTranform { addr: String, serial: String, transform: Transform3D, } impl MessageBehavior for DeviceTranform { fn to_osc_message(&self) -> OscMessage { let quat = self.transform.basis.to_quat(); return OscMessage { addr: self.addr.to_owned(), args: vec![ OscType::from(self.serial.to_owned()), OscType::from(self.transform.origin.x), OscType::from(self.transform.origin.y), OscType::from(self.transform.origin.z), OscType::from(quat.x), OscType::from(quat.y), OscType::from(quat.z), OscType::from(quat.w), ], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 8 { return Err(String::from("arg count invalid")); } match msg.addr.as_str() { "/VMC/Ext/Hmd/Pos" | "/VMC/Ext/Con/Pos" | "/VMC/Ext/Tra/Pos" | "/VMC/Ext/Hmd/Pos/Local" | "/VMC/Ext/Con/Pos/Local" | "/VMC/Ext/Tra/Pos/Local" => {} _ => return Err(String::from("addr invalid")), } let serial: String; let mut origin = Vector3::new(0.0, 0.0, 0.0); let mut quat = Quaternion::new(0.0, 0.0, 0.0, 0.0); match &msg.args[0] { OscType::String(s) => serial = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => origin.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Float(f) => origin.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => origin.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[4] { OscType::Float(f) => quat.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[5] { OscType::Float(f) => quat.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[6] { OscType::Float(f) => quat.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[7] { OscType::Float(f) => quat.w = f, _ => return Err(String::from("arg type invalid")), } return Ok(DeviceTranform { addr: msg.addr.to_owned(), serial, transform: Transform3D::new(Basis::from_quat(quat), origin), }); } } struct VmcExtRvc { enable: bool, port: u16, ip_addr: Option, } impl MessageBehavior for VmcExtRvc { fn to_osc_message(&self) -> OscMessage { let mut args: Vec; if self.enable { args = vec![OscType::from(1)]; } else { args = vec![OscType::from(0)]; } args.push(OscType::from(self.port as i32)); if self.ip_addr.is_some() { args.push(OscType::from(self.ip_addr.clone().unwrap())); } return OscMessage { addr: String::from("/VMC/Ext/Rvc"), args, }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() < 2 || msg.args.len() > 3 { return Err(String::from("arg count invalid")); } let enable: bool; let port: u16; let mut ip_addr: Option = None; match msg.args[0] { OscType::Int(i) => { if i == 0 { enable = false; } else if i == 1 { enable = true; } else { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Int(i) => { if i >= 0 && i <= 65535 { port = i as u16; } else { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } if msg.args.len() == 3 { match &msg.args[2] { OscType::String(s) => ip_addr = Some(s.to_owned()), _ => return Err(String::from("arg type invalid")), } } return Ok(VmcExtRvc { enable, port, ip_addr, }); } } struct VmcExtLight { name: String, transform: Transform3D, color: Color, } impl MessageBehavior for VmcExtLight { fn to_osc_message(&self) -> OscMessage { let quat = self.transform.basis.to_quat(); return OscMessage { addr: String::from("/VMC/Ext/Light"), args: vec![ OscType::from(self.name.to_owned()), OscType::from(self.transform.origin.x), OscType::from(self.transform.origin.y), OscType::from(self.transform.origin.z), OscType::from(quat.x), OscType::from(quat.y), OscType::from(quat.z), OscType::from(quat.w), OscType::from(self.color.r), OscType::from(self.color.g), OscType::from(self.color.b), OscType::from(self.color.a), ], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 12 { return Err(String::from("arg count invalid")); } let name: String; let mut origin = Vector3::new(0.0, 0.0, 0.0); let mut quat = Quaternion::new(0.0, 0.0, 0.0, 0.0); let mut color = Color::from_rgba(0.0, 0.0, 0.0, 0.0); match &msg.args[0] { OscType::String(s) => name = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => origin.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Float(f) => origin.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => origin.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[4] { OscType::Float(f) => quat.x = f, _ => return Err(String::from("arg type invalid")), } match msg.args[5] { OscType::Float(f) => quat.y = f, _ => return Err(String::from("arg type invalid")), } match msg.args[6] { OscType::Float(f) => quat.z = f, _ => return Err(String::from("arg type invalid")), } match msg.args[7] { OscType::Float(f) => quat.w = f, _ => return Err(String::from("arg type invalid")), } match msg.args[8] { OscType::Float(f) => color.r = f, _ => return Err(String::from("arg type invalid")), } match msg.args[9] { OscType::Float(f) => color.g = f, _ => return Err(String::from("arg type invalid")), } match msg.args[10] { OscType::Float(f) => color.b = f, _ => return Err(String::from("arg type invalid")), } match msg.args[11] { OscType::Float(f) => color.a = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtLight { name, transform: Transform3D::new(Basis::from_quat(quat), origin), color, }); } } struct VmcExtVrm { path: String, title: String, hash: Option, } impl MessageBehavior for VmcExtVrm { fn to_osc_message(&self) -> OscMessage { let mut args = vec![ OscType::from(self.path.to_owned()), OscType::from(self.title.to_owned()), ]; if self.hash.is_some() { args.push(OscType::from(self.hash.clone().unwrap())); } return OscMessage { addr: String::from("/Vmc/Ext/VRM"), args, }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() < 2 || msg.args.len() > 3 { return Err(String::from("arg count invalid")); } let path: String; let title: String; let mut hash: Option = None; match &msg.args[0] { OscType::String(s) => path = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match &msg.args[1] { OscType::String(s) => title = s.to_owned(), _ => return Err(String::from("arg type invalid")), } if msg.args.len() == 3 { match &msg.args[2] { OscType::String(s) => hash = Some(s.to_owned()), _ => return Err(String::from("arg type invalid")), } } return Ok(VmcExtVrm { path, title, hash }); } } struct VmcExtRemote { service: String, json: String, } impl MessageBehavior for VmcExtRemote { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Remote"), args: vec![ OscType::from(self.service.to_owned()), OscType::from(self.json.to_owned()), ], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 2 { return Err(String::from("arg count invalid")); } let service: String; let json: String; match &msg.args[0] { OscType::String(s) => service = s.to_owned(), _ => return Err(String::from("arg type invalid")), } match &msg.args[1] { OscType::String(s) => json = s.to_owned(), _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtRemote { service, json }); } } struct VmcExtOpt { option: String, } impl MessageBehavior for VmcExtOpt { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Opt"), args: vec![OscType::from(self.option.to_owned())], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 1 { return Err(String::from("arg count invalid")); } match &msg.args[0] { OscType::String(s) => { return Ok(VmcExtOpt { option: s.to_owned(), }) } _ => return Err(String::from("arg type invalid")), } } } struct VmcExtSettingColor { color: Color, } impl MessageBehavior for VmcExtSettingColor { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Setting/Color"), args: vec![ OscType::from(self.color.r), OscType::from(self.color.g), OscType::from(self.color.b), OscType::from(self.color.a), ], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 4 { return Err(String::from("argj count invalid")); } let mut color = Color::from_rgba(0.0, 0.0, 0.0, 0.0); match msg.args[0] { OscType::Float(f) => color.r = f, _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Float(f) => color.g = f, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Float(f) => color.b = f, _ => return Err(String::from("arg type invalid")), } match msg.args[3] { OscType::Float(f) => color.a = f, _ => return Err(String::from("arg type invalid")), } return Ok(VmcExtSettingColor { color }); } } struct VmcExtSettingWin { is_top_most: bool, is_transparent: bool, window_click_through: i32, hide_border: i32, } impl MessageBehavior for VmcExtSettingWin { fn to_osc_message(&self) -> OscMessage { let mut args: Vec; if self.is_top_most { args = vec![OscType::from(1)]; } else { args = vec![OscType::from(0)]; } if self.is_transparent { args.push(OscType::from(1)); } else { args.push(OscType::from(0)); } args.append(&mut vec![ OscType::from(self.window_click_through), OscType::from(self.hide_border), ]); return OscMessage { addr: String::from("/VMC/Ext/Setting/Win"), args, }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.args.len() != 4 { return Err(String::from("arg count invalid")); } let mut result = Self { is_top_most: false, is_transparent: false, window_click_through: -1, hide_border: -1, }; match msg.args[0] { OscType::Int(i) => { if i == 1 { result.is_top_most = true; } else if i != 0 { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } match msg.args[1] { OscType::Int(i) => { if i == 1 { result.is_transparent = true; } else if i != 0 { return Err(String::from("arg value invalid")); } } _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Int(i) => result.window_click_through = i, _ => return Err(String::from("arg type invalid")), } match msg.args[2] { OscType::Int(i) => result.hide_border = i, _ => return Err(String::from("arg type invalid")), } return Ok(result); } } struct VmcExtConfig { path: String, } impl MessageBehavior for VmcExtConfig { fn to_osc_message(&self) -> OscMessage { return OscMessage { addr: String::from("/VMC/Ext/Config"), args: vec![OscType::from(self.path.to_owned())], }; } fn from_osc_message(msg: OscMessage) -> Result { if msg.addr.len() != 1 { return Err(String::from("arg count invalid")); } match &msg.args[0] { OscType::String(s) => return Ok(VmcExtConfig { path: s.to_owned() }), _ => return Err(String::from("arg type invalid")), } } }