From e9726a249ea30af03243a1465955430c0027badc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Wed, 10 May 2023 00:20:42 +0200 Subject: [PATCH] implement envelope --- rust/lightwave/README.md | 22 +-- .../src/lwo2/sub_tags/envelope_type.rs | 43 ----- rust/lightwave/src/lwo2/sub_tags/mod.rs | 9 - rust/lightwave/src/lwo2/tags/envelope.rs | 165 ++++++++++++++++++ rust/lightwave/src/lwo2/tags/meta.rs | 35 ++++ rust/lightwave/src/lwo2/tags/mod.rs | 10 +- 6 files changed, 220 insertions(+), 64 deletions(-) delete mode 100644 rust/lightwave/src/lwo2/sub_tags/envelope_type.rs create mode 100644 rust/lightwave/src/lwo2/tags/envelope.rs create mode 100644 rust/lightwave/src/lwo2/tags/meta.rs diff --git a/rust/lightwave/README.md b/rust/lightwave/README.md index 40e3ff8..bd472b8 100644 --- a/rust/lightwave/README.md +++ b/rust/lightwave/README.md @@ -26,26 +26,26 @@ Progress: About 90% ([LWO2 Spec](http://static.lightwave3d.com/sdk/2015/html/fil | Polygon Tag Mapping | `PTAG` | ✅ | | Discontinuous Vertex Mapping | `VMAD` | ✅ | | Vertex Map Parameter | `VMPA` | ✅ | -| [Envelope Definition](#envelope-subchunks) | `ENVL` | ❌ | +| [Envelope Definition](#envelope-subchunks) | `ENVL` | ✅ | | [Image (-Sequence)](#clip-subchunks) | `CLIP` | 🚧 | | [Surface Definition](#surface-subchunks) | `SURF` | 🚧 | | Bounding Box | `BBOX` | ✅ | -| Description Line | `DESC` | ❌ | -| Commentary Text | `TEXT` | ❌ | -| Thumbnail Icon Image | `ICON` | ❌ | +| Description Line | `DESC` | ✅ | +| Commentary Text | `TEXT` | ✅ | +| Thumbnail Icon Image | `ICON` | ✅ | ### Envelope Subchunks | Chunk | Tag | Status | |--------------------------|--------|--------| -| Envelope Type | `TYPE` | ❌ | -| Pre-Behavior | `PRE` | ❌ | -| Post-Behavior | `POST` | ❌ | -| Keyframe Time and Value | `KEY` | ❌ | -| Interval Interpolation | `SPAN` | ❌ | -| Plugin Channel Modifiers | `CHAN` | ❌ | -| Channel Name | `NAME` | ❌ | +| Envelope Type | `TYPE` | ✅ | +| Pre-Behavior | `PRE` | ✅ | +| Post-Behavior | `POST` | ✅ | +| Keyframe Time and Value | `KEY` | ✅ | +| Interval Interpolation | `SPAN` | ✅ | +| Plugin Channel Modifiers | `CHAN` | ✅ | +| Channel Name | `NAME` | ✅ | ### Clip Subchunks diff --git a/rust/lightwave/src/lwo2/sub_tags/envelope_type.rs b/rust/lightwave/src/lwo2/sub_tags/envelope_type.rs deleted file mode 100644 index b9e3996..0000000 --- a/rust/lightwave/src/lwo2/sub_tags/envelope_type.rs +++ /dev/null @@ -1,43 +0,0 @@ -use binrw::binread; - -/// The type subchunk records the format in which the envelope is displayed to the user and a type -/// code that identifies the components of certain predefined envelope triples. The user format has -/// no effect on the actual values, only the way they're presented in LightWave®'s interface. -#[binread] -#[br(import(_length: u32))] -#[derive(Debug)] -pub struct EnvelopeType { - pub user_format: UserFormat, - pub kind: EnvelopeKind, -} - -#[binread] -#[br(repr = u8)] -#[derive(Debug)] -pub enum UserFormat { - Float = 2, - Distance = 3, - Percent = 4, - Angle = 5, -} - -#[binread] -#[br(repr = u8)] -#[derive(Debug)] -pub enum EnvelopeKind { - PositionX = 0x1, - PositionY = 0x2, - PositionZ = 0x3, - RotHeading = 0x4, - RotPitch = 0x5, - RotBank = 0x6, - ScaleX = 0x7, - ScaleY = 0x8, - ScaleZ = 0x9, - ColorR = 0xa, - ColorG = 0xb, - ColorB = 0xc, - FalloffX = 0xd, - FalloffY = 0xe, - FalloffZ = 0xf, -} diff --git a/rust/lightwave/src/lwo2/sub_tags/mod.rs b/rust/lightwave/src/lwo2/sub_tags/mod.rs index 4970e21..ba2e010 100644 --- a/rust/lightwave/src/lwo2/sub_tags/mod.rs +++ b/rust/lightwave/src/lwo2/sub_tags/mod.rs @@ -1,18 +1,9 @@ -use crate::lwo2::sub_tags::envelope_type::EnvelopeType; use crate::lwo2::vx; use binrw::binread; pub mod blocks; -pub mod envelope_type; pub mod surface_parameters; -#[binread] -#[derive(Debug)] -pub enum SubTag { - #[br(magic(b"TYPE"))] - EnvelopeType(EnvelopeType), -} - #[binread] #[br(import(_length: u32))] #[derive(Debug)] diff --git a/rust/lightwave/src/lwo2/tags/envelope.rs b/rust/lightwave/src/lwo2/tags/envelope.rs new file mode 100644 index 0000000..d58a206 --- /dev/null +++ b/rust/lightwave/src/lwo2/tags/envelope.rs @@ -0,0 +1,165 @@ +use crate::binrw_helpers::until_size_limit; +use crate::iff::SubChunk; +use crate::lwo2::vx; +use binrw::{binread, NullString, PosValue}; + +#[binread] +#[br(import(length: u32))] +#[derive(Debug)] +pub struct EnvelopeDefinition { + #[br(temp)] + pos_start: PosValue<()>, + #[br(parse_with = vx)] + pub index: u32, + #[br(temp)] + pos_end: PosValue<()>, + #[br(parse_with = until_size_limit(length as u64 - (pos_end.pos - pos_start.pos)))] + pub attributes: Vec, +} + +#[binread] +#[derive(Debug)] +pub enum EnvelopeSubChunk { + #[br(magic(b"TYPE"))] + EnvelopeType(SubChunk), + #[br(magic(b"PRE"))] + PreBehavior(SubChunk), + #[br(magic(b"POST"))] + PostBehavior(SubChunk), + #[br(magic(b"KEY"))] + KeyframeTimeAndValue(SubChunk), + #[br(magic(b"SPAN"))] + IntervalInterpolation(SubChunk), + #[br(magic(b"CHAN"))] + PluginChannelModifiers(SubChunk), + #[br(magic(b"NAME"))] + ChannelName(SubChunk), +} + +/// An optional name for the envelope. LightWave® itself ignores the names of surface envelopes, +/// but plug-ins can browse the envelope database by name. +#[binread] +#[br(import(_length: u32))] +#[derive(Debug)] +pub struct PluginChannelName { + #[br(align_after = 2)] + pub channel_name: NullString, +} + +/// Channel modifiers can be associated with an envelope. Each channel chunk contains the name of +/// the plug-in and some flag bits. Only the first flag bit is defined; if set, the plug-in is +/// disabled. The data that follows this, if any, is owned by the plug-in. +#[binread] +#[br(import(length: u32))] +#[derive(Debug)] +pub struct PluginChannelModifiers { + #[br(temp)] + start_pos: PosValue<()>, + #[br(align_after = 2)] + pub server_name: NullString, + pub flags: u16, + #[br(temp)] + end_pos: PosValue<()>, + #[br(count = length as u64 - (end_pos.pos - start_pos.pos))] + pub parameters: Vec, +} + +/// Defines the interpolation between the most recent KEY chunk and the KEY immediately before it in +/// time. The type identifies the interpolation algorithm and can be STEP, LINE, TCB +/// (Kochanek-Bartels), HERM (Hermite), BEZI (1D Bezier) or BEZ2 (2D Bezier). +/// Different parameters are stored for each of these. +#[binread] +#[br(import(length: u32))] +#[derive(Debug)] +pub struct IntervalInterpolation { + pub kind: IntervalInterpolationType, + #[br(count = (length - 4) / 4)] + pub parameters: Vec, +} + +#[binread] +#[derive(Debug)] +pub enum IntervalInterpolationType { + #[br(magic(b"STEP"))] + Step, + #[br(magic(b"LINE"))] + Line, + #[br(magic(b"TCB\0"))] + KochanekBartels, + #[br(magic(b"HERM"))] + Hermite, + #[br(magic(b"BEZI"))] + Bezier1D, + #[br(magic(b"BEZ2"))] + Bezier2D, +} + +/// The value of the envelope at the specified time in seconds. The signal value between keyframes +/// is interpolated. The time of a keyframe isn't restricted to integer frames. +#[binread] +#[br(import(_length: u32))] +#[derive(Debug)] +pub struct KeyframeTimeAndValue { + pub time: f32, + pub value: f32, +} + +#[binread] +#[br(repr = u16, import(_length: u32))] +#[derive(Debug)] +pub enum Behavior { + /// Sets the value to 0.0. + Reset = 0, + /// Sets the value to the value at the nearest key. + Constant = 1, + /// Repeats the interval between the first and last keys (the primary interval). + Repeat = 2, + /// Like Repeat, but alternating copies of the primary interval are time-reversed. + Oscillate = 3, + /// Like Repeat, but offset by the difference between the values of the first and last keys. + OffsetRepeat = 4, + /// Linearly extrapolates the value based on the tangent at the nearest key. + Linear = 5, +} + +/// The type subchunk records the format in which the envelope is displayed to the user and a type +/// code that identifies the components of certain predefined envelope triples. The user format has +/// no effect on the actual values, only the way they're presented in LightWave®'s interface. +#[binread] +#[br(import(_length: u32))] +#[derive(Debug)] +pub struct EnvelopeType { + pub user_format: UserFormat, + pub kind: EnvelopeKind, +} + +#[binread] +#[br(repr = u8)] +#[derive(Debug)] +pub enum UserFormat { + Float = 2, + Distance = 3, + Percent = 4, + Angle = 5, +} + +#[binread] +#[br(repr = u8)] +#[derive(Debug)] +pub enum EnvelopeKind { + PositionX = 0x1, + PositionY = 0x2, + PositionZ = 0x3, + RotHeading = 0x4, + RotPitch = 0x5, + RotBank = 0x6, + ScaleX = 0x7, + ScaleY = 0x8, + ScaleZ = 0x9, + ColorR = 0xa, + ColorG = 0xb, + ColorB = 0xc, + FalloffX = 0xd, + FalloffY = 0xe, + FalloffZ = 0xf, +} diff --git a/rust/lightwave/src/lwo2/tags/meta.rs b/rust/lightwave/src/lwo2/tags/meta.rs new file mode 100644 index 0000000..fa102fc --- /dev/null +++ b/rust/lightwave/src/lwo2/tags/meta.rs @@ -0,0 +1,35 @@ +use binrw::{binread, NullString}; + +/// Store an object description. Optional. This should be a simple line of upper and lowercase +/// characters, punctuation and spaces which describes the contents of the object file. There +/// should be no control characters in this text string and it should generally be kept short. +#[binread] +#[br(import(_length: u32))] +#[derive(Debug)] +pub struct DescriptionLine { + #[br(align_after = 2)] + pub description_line: NullString, +} + +/// An iconic or thumbnail image for the object which can be used when viewing the file in a +/// browser. Currently the only suported encoding is 0, meaning uncompressed RGB byte triples. +/// The width is the number of pixels in each row of the image, and the height (number of rows) +/// is (chunkSize - 4)/width. This chunk is optional. +#[binread] +#[br(import(length: u32))] +#[derive(Debug)] +pub struct ThumbnailIconImage { + pub encoding: ThumbnailImageEncoding, + pub width: u16, + #[br(calc = (length as u16 - 4) / width)] + pub height: u16, + #[br(count = length - 4)] + pub data: Vec, +} + +#[binread] +#[br(repr = u16)] +#[derive(Debug)] +pub enum ThumbnailImageEncoding { + UncompressedRgb = 0, +} diff --git a/rust/lightwave/src/lwo2/tags/mod.rs b/rust/lightwave/src/lwo2/tags/mod.rs index c7e102d..d1d9959 100644 --- a/rust/lightwave/src/lwo2/tags/mod.rs +++ b/rust/lightwave/src/lwo2/tags/mod.rs @@ -3,6 +3,7 @@ use crate::lwo2::tags::bounding_box::BoundingBox; use crate::lwo2::tags::discontinuous_vertex_mapping::DiscontinuousVertexMappings; use crate::lwo2::tags::image_clip::ImageClip; use crate::lwo2::tags::layer::Layer; +use crate::lwo2::tags::meta::{DescriptionLine, ThumbnailIconImage}; use crate::lwo2::tags::point_list::PointList; use crate::lwo2::tags::polygon_list::PolygonLists; use crate::lwo2::tags::polygon_tag_mapping::PolygonTagMappings; @@ -14,8 +15,10 @@ use binrw::binread; pub mod bounding_box; pub mod discontinuous_vertex_mapping; +pub mod envelope; pub mod image_clip; pub mod layer; +pub mod meta; pub mod point_list; pub mod polygon_list; pub mod polygon_tag_mapping; @@ -43,6 +46,12 @@ pub enum Tag { VertexMapParameter(Chunk), #[br(magic(b"BBOX"))] BoundingBox(Chunk), + #[br(magic(b"DESC"))] + DescriptionLine(Chunk), + #[br(magic(b"TEXT"))] + CommentaryText(Chunk), + #[br(magic(b"ICON"))] + ThumbnailIconImage(Chunk), #[br(magic(b"POLS"))] PolygonList(Chunk), #[br(magic(b"SURF"))] @@ -50,4 +59,3 @@ pub enum Tag { #[br(magic(b"CLIP"))] ImageClip(Chunk), } -