implement envelope

This commit is contained in:
2023-05-10 00:20:42 +02:00
parent 9ee28da6a0
commit e9726a249e
6 changed files with 220 additions and 64 deletions

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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)]

View File

@@ -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<EnvelopeSubChunk>,
}
#[binread]
#[derive(Debug)]
pub enum EnvelopeSubChunk {
#[br(magic(b"TYPE"))]
EnvelopeType(SubChunk<EnvelopeType>),
#[br(magic(b"PRE"))]
PreBehavior(SubChunk<Behavior>),
#[br(magic(b"POST"))]
PostBehavior(SubChunk<Behavior>),
#[br(magic(b"KEY"))]
KeyframeTimeAndValue(SubChunk<KeyframeTimeAndValue>),
#[br(magic(b"SPAN"))]
IntervalInterpolation(SubChunk<IntervalInterpolation>),
#[br(magic(b"CHAN"))]
PluginChannelModifiers(SubChunk<PluginChannelModifiers>),
#[br(magic(b"NAME"))]
ChannelName(SubChunk<PluginChannelName>),
}
/// 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<u8>,
}
/// 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<f32>,
}
#[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,
}

View File

@@ -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<u8>,
}
#[binread]
#[br(repr = u16)]
#[derive(Debug)]
pub enum ThumbnailImageEncoding {
UncompressedRgb = 0,
}

View File

@@ -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<VertexMapParameter>),
#[br(magic(b"BBOX"))]
BoundingBox(Chunk<BoundingBox>),
#[br(magic(b"DESC"))]
DescriptionLine(Chunk<DescriptionLine>),
#[br(magic(b"TEXT"))]
CommentaryText(Chunk<DescriptionLine>),
#[br(magic(b"ICON"))]
ThumbnailIconImage(Chunk<ThumbnailIconImage>),
#[br(magic(b"POLS"))]
PolygonList(Chunk<PolygonLists>),
#[br(magic(b"SURF"))]
@@ -50,4 +59,3 @@ pub enum Tag {
#[br(magic(b"CLIP"))]
ImageClip(Chunk<ImageClip>),
}