diff --git a/rust/lightwave/README.md b/rust/lightwave/README.md index 4145081..aef50e5 100644 --- a/rust/lightwave/README.md +++ b/rust/lightwave/README.md @@ -44,7 +44,7 @@ Progress: About 90% ([LWO2 Spec](http://static.lightwave3d.com/sdk/2015/html/fil | Image Sequence | `ISEQ` | ✅ | | Plugin Animation | `ANIM` | ❌ | | Reference (Clone) | `XREF` | ✅ | - | Flag (Undocumented) | `FLAG` | 🚧 | +| Flag (Undocumented) | `FLAG` | ⚠️ | | Color-cycling Still | `STCC` | ✅ | | Time | `TIME` | ✅ | | Color Space RGB | `CLRS` | ✅ | @@ -76,19 +76,19 @@ Progress: About 90% ([LWO2 Spec](http://static.lightwave3d.com/sdk/2015/html/fil | Max Smoothing Angle | `SMAN` | ✅ | | Reflection Options | `RFOP` | ✅ | | Reflection Map Image | `RIMG` | ✅ | -| Reflection Map Image Seam Angle | `RSAN` | ❌ | -| Reflection Blurring | `RBLR` | ❌ | -| Refractive Index | `RIND` | ❌ | -| Transparency Options | `TROP` | ❌ | -| Refraction Map Image | `TIMG` | ❌ | +| Reflection Map Image Seam Angle | `RSAN` | ✅ | +| Reflection Blurring | `RBLR` | ✅ | +| Refractive Index | `RIND` | ✅ | +| Transparency Options | `TROP` | ✅ | +| Refraction Map Image | `TIMG` | ✅ | | Refraction Blurring | `TBLR` | ✅ | | Color Highlights | `CLRH` | ✅ | | Color Filter | `CLRF` | ✅ | | Additive Transparency | `ADRT` | ✅ | -| Glow Effect | `GLOW` | ❌ | -| Render Outlines | `LINE` | ❌ | -| Alpha Mode | `ALPH` | ❌ | -| Vertex Color Map | `VCOL` | ❌ | +| Glow Effect | `GLOW` | ✅ | +| Render Outlines | `LINE` | ✅ | +| Alpha Mode | `ALPH` | ✅ | +| Vertex Color Map | `VCOL` | ✅ | | [Surface Blocks](#surface-blocks) | `BLOK` | 🚧 | ### Surface Blocks @@ -107,7 +107,7 @@ Ordinal Strings: | Enable State | `ENAB` | ✅ | | Opacity | `OPAC` | ✅ | | Displacement Axis | `AXIS` | ✅ | -| Negative (Undocumented) | `NEGA` | 🚧 | +| Negative (Undocumented) | `NEGA` | ⚠️ | #### Texture Mapping diff --git a/rust/lightwave/src/lwo2/sub_tags/surface_block_image_texture.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/image_texture.rs similarity index 73% rename from rust/lightwave/src/lwo2/sub_tags/surface_block_image_texture.rs rename to rust/lightwave/src/lwo2/sub_tags/blocks/image_texture.rs index 76269e4..bb57f64 100644 --- a/rust/lightwave/src/lwo2/sub_tags/surface_block_image_texture.rs +++ b/rust/lightwave/src/lwo2/sub_tags/blocks/image_texture.rs @@ -1,5 +1,5 @@ use crate::iff::SubChunk; -use crate::lwo2::sub_tags::texture_mapping::TextureMapping; +use crate::lwo2::sub_tags::blocks::texture_mapping::TextureMapping; use crate::lwo2::sub_tags::{ValueEnvelope, VxReference}; use crate::lwo2::vx; use binrw::{binread, NullString}; @@ -27,6 +27,8 @@ pub enum SurfaceBlockImageTextureSubChunk { AntialiasingStrength(SubChunk), #[br(magic(b"PIXB"))] PixelBlending(SubChunk), + #[br(magic(b"STICK"))] + StickyProjection(SubChunk), #[br(magic(b"TAMP"))] TextureAmplitude(SubChunk), } @@ -60,6 +62,8 @@ pub struct AntialiasingStrength { pub strength: f32, } +/// For UV projection, which depends on texture coordinates at each vertex, this selects the name of +/// the TXUV vertex map that contains those coordinates. #[binread] #[br(import(_length: u32))] #[derive(Debug)] @@ -68,6 +72,8 @@ pub struct UvMap { pub txuv_map_name: NullString, } +/// For cylindrical and spherical projections, these parameters control how many times the image +/// repeats over each full interval. #[binread] #[br(import(_length: u32))] #[derive(Debug)] @@ -77,6 +83,7 @@ pub struct ImageWrapAmount { pub envelope: u32, } +/// Specifies how the color of the texture is derived for areas outside the image. #[binread] #[br(import(_length: u32))] #[derive(Debug)] @@ -89,9 +96,15 @@ pub struct ImageWrapOptions { #[br(repr = u16)] #[derive(Debug)] pub enum ImageWrapType { + /// Areas outside the image are assumed to be black. The ultimate effect of this depends on + /// the opacity settings. For an additive texture layer on the color channel, the final color + /// will come from the preceding layers or from the base color of the surface. Reset = 0, + /// The image is repeated or tiled. Repeat = 1, + /// Like repeat, but alternate tiles are mirror-reversed. Mirror = 2, + /// The color is taken from the image's nearest edge pixel. Edge = 3, } diff --git a/rust/lightwave/src/lwo2/sub_tags/surface_blocks.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs similarity index 94% rename from rust/lightwave/src/lwo2/sub_tags/surface_blocks.rs rename to rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs index bae8323..15411f7 100644 --- a/rust/lightwave/src/lwo2/sub_tags/surface_blocks.rs +++ b/rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs @@ -1,10 +1,13 @@ use crate::binrw_helpers::until_size_limit; use crate::iff::SubChunk; -use crate::lwo2::sub_tags::surface_block_image_texture::SurfaceBlockImageTextureSubChunk; +use crate::lwo2::sub_tags::blocks::image_texture::SurfaceBlockImageTextureSubChunk; use crate::lwo2::sub_tags::EnableState; use crate::lwo2::vx; use binrw::binread; +pub mod image_texture; +pub mod texture_mapping; + #[binread] #[br(import(length: u32))] #[derive(Debug)] diff --git a/rust/lightwave/src/lwo2/sub_tags/texture_mapping.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/texture_mapping.rs similarity index 100% rename from rust/lightwave/src/lwo2/sub_tags/texture_mapping.rs rename to rust/lightwave/src/lwo2/sub_tags/blocks/texture_mapping.rs diff --git a/rust/lightwave/src/lwo2/sub_tags/mod.rs b/rust/lightwave/src/lwo2/sub_tags/mod.rs index c06d870..4970e21 100644 --- a/rust/lightwave/src/lwo2/sub_tags/mod.rs +++ b/rust/lightwave/src/lwo2/sub_tags/mod.rs @@ -2,11 +2,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_block_image_texture; -pub mod surface_blocks; pub mod surface_parameters; -pub mod texture_mapping; #[binread] #[derive(Debug)] diff --git a/rust/lightwave/src/lwo2/sub_tags/surface_parameters.rs b/rust/lightwave/src/lwo2/sub_tags/surface_parameters.rs index 1512e92..2dde5a7 100644 --- a/rust/lightwave/src/lwo2/sub_tags/surface_parameters.rs +++ b/rust/lightwave/src/lwo2/sub_tags/surface_parameters.rs @@ -1,7 +1,8 @@ use crate::iff::SubChunk; -use crate::lwo2::sub_tags::surface_blocks::SurfaceBlocks; +use crate::lwo2::sub_tags::blocks::SurfaceBlocks; use crate::lwo2::sub_tags::{ValueEnvelope, VectorEnvelope, VxReference}; -use binrw::binread; +use crate::lwo2::vx; +use binrw::{binread, NullString}; #[binread] #[derive(Debug)] @@ -30,12 +31,20 @@ pub enum SurfaceParameterSubChunk { PolygonSidedness(SubChunk), #[br(magic(b"SMAN"))] MaxSmoothingAngle(SubChunk), - #[br(magic(b"BLOK"))] - Blocks(SubChunk), #[br(magic(b"RFOP"))] ReflectionOptions(SubChunk), #[br(magic(b"RIMG"))] ReflectionMapImage(SubChunk), + #[br(magic(b"RSAN"))] + ReflectionMapSeamAngle(SubChunk), + #[br(magic(b"RBLR"))] + ReflectionBlurring(SubChunk), + #[br(magic(b"RIND"))] + RefractiveIndex(SubChunk), + #[br(magic(b"TROP"))] + TransparencyOptions(SubChunk), + #[br(magic(b"TIMG"))] + RefractionMapImage(SubChunk), #[br(magic(b"TBLR"))] RefractionBlurring(SubChunk), #[br(magic(b"CLRH"))] @@ -44,6 +53,103 @@ pub enum SurfaceParameterSubChunk { ColorFilter(SubChunk), #[br(magic(b"ADTR"))] AdditiveTransparency(SubChunk), + #[br(magic(b"GLOW"))] + GlowEffect(SubChunk), + #[br(magic(b"LINE"))] + RenderOutlines(SubChunk), + #[br(magic(b"ALPH"))] + AlphaMode(SubChunk), + #[br(magic(b"VCOL"))] + VertexColorMap(SubChunk), + #[br(magic(b"BLOK"))] + Blocks(SubChunk), +} + +/// The vertex color map subchunk identifies an RGB or RGBA VMAP that will be used to color the surface. +#[binread] +#[br(import(_length: u32))] +#[derive(Debug)] +pub struct VertexColorMap { + pub intensity: f32, + #[br(parse_with = vx)] + pub envelope: u32, + pub vmap_type: [u8; 4], + #[br(align_after = 2)] + pub name: NullString, +} + +/// The alpha mode defines the alpha channel output options for the surface. +#[binread] +#[br(import(_length: u32))] +#[derive(Debug)] +pub struct AlphaMode { + pub mode: AlphaModeMode, + pub value: f32, +} + +#[binread] +#[br(repr = u16)] +#[derive(Debug)] +pub enum AlphaModeMode { + /// The surface has no effect on the alpha channel when rendered. + UnaffectedBySurface = 0, + /// The alpha channel will be written with the constant value following the mode in the subchunk. + ConstantValue = 1, + /// The alpha value is derived from surface opacity, which is the default if the ALPH chunk is missing. + SurfaceOpacity = 2, + /// The alpha value comes from the shadow density. + ShadowDensity = 3, +} + +/// The line effect draws the surface as a wireframe of the polygon edges. Currently the only flag +/// defined is an enable switch in the low bit. The size is the thickness of the lines in pixels, +/// and the color, if not given, is the base color of the surface. Note that you may encounter +/// LINE subchunks with no color information (these will have a subchunk length of 8 bytes) and +/// possibly without size information (subchunk length 2). +#[binread] +#[br(import(length: u32))] +#[derive(Debug)] +pub struct RenderOutlines { + pub flags: u16, + #[br(if(length > 2))] + pub size: f32, + #[br(if(length > 2))] + #[br(parse_with = vx)] + pub size_envelope: u32, + #[br(if(length > 8))] + pub color: [f32; 3], + #[br(if(length > 8))] + #[br(parse_with = vx)] + pub color_envelope: u32, +} + +/// The glow effect causes a surface to spread and affect neighboring areas of the image. The type +/// can be 0 for Hastings glow, and 1 for image convolution. The size and intensity define how large +/// and how strong the effect is. +/// +/// You may also encounter glow information written in a GVAL subchunk containing only the intensity +/// and its envelope (the subchunk length is 6). +#[binread] +#[br(import(length: u32))] +#[derive(Debug)] +pub struct GlowEffect { + pub kind: GlowType, + pub intensity: f32, + #[br(parse_with = vx)] + pub intensity_envelope: u32, + #[br(if(length > 6))] + pub size: f32, + #[br(if(length > 6))] + #[br(parse_with = vx)] + pub size_envelope: u32, +} + +#[binread] +#[br(repr = u16)] +#[derive(Debug)] +pub enum GlowType { + HastingsGlow = 0, + ImageConvolution = 1, } #[binread]