diff --git a/rust/lightwave/README.md b/rust/lightwave/README.md
index 15d4df3..e6d13a0 100644
--- a/rust/lightwave/README.md
+++ b/rust/lightwave/README.md
@@ -108,8 +108,8 @@ Progress: About 90% ([LWO2 Spec](http://static.lightwave3d.com/sdk/2015/html/fil
Ordinal Strings:
* ✅ [Image Texture Map](#image-texture-map) `IMAP`
* ❌ [Procedural Texture](#procedural-texture) `PROC`
-* ❌ [Gradient Texture](#gradient-texture) `GRAD`
-* ❌ Shader Plugin `SHDR`
+* ✅ [Gradient Texture](#gradient-texture) `GRAD`
+* ✅ [Shader Plugin](#shaders) `SHDR`
#### Shared
@@ -158,16 +158,16 @@ Ordinal Strings:
| Chunk | Tag | Status |
|----------------|-------------------|--------|
-| Parameter Name | `PNAM` | ❌ |
-| Item Name | `INAM` | ❌ |
-| Gradient Range | `GRST`
`GREN` | ❌ |
-| Repeat Mode | `GRPT` | ❌ |
-| Key Values | `FKEY` | ❌ |
-| Key Parameters | `IKEY` | ❌ |
+| Parameter Name | `PNAM` | ✅ |
+| Item Name | `INAM` | ✅ |
+| Gradient Range | `GRST`
`GREN` | ✅ |
+| Repeat Mode | `GRPT` | ✅ |
+| Key Values | `FKEY` | ✅ |
+| Key Parameters | `IKEY` | ✅ |
#### Shaders
| Chunk | Tag | Status |
|------------------|--------|--------|
-| Shader Algorithm | `FUNC` | ❌ |
+| Shader Algorithm | `FUNC` | ✅ |
diff --git a/rust/lightwave/src/lwo2/sub_tags/blocks/gradient_texture.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/gradient_texture.rs
new file mode 100644
index 0000000..7555b72
--- /dev/null
+++ b/rust/lightwave/src/lwo2/sub_tags/blocks/gradient_texture.rs
@@ -0,0 +1,68 @@
+use crate::iff::SubChunk;
+use crate::lwo2::sub_tags::Name;
+use binrw::binread;
+
+#[binread]
+#[derive(Debug)]
+pub enum GradientTextureSubChunk {
+ #[br(magic(b"PNAM"))]
+ ParameterName(SubChunk),
+ #[br(magic(b"INAM"))]
+ ItemName(SubChunk),
+ #[br(magic(b"GRST"))]
+ GradientRangeStart(SubChunk),
+ #[br(magic(b"GREN"))]
+ GradientRangeEnd(SubChunk),
+ #[br(magic(b"GRPT"))]
+ RepeatMode(SubChunk),
+ #[br(magic(b"FKEY"))]
+ KeyValues(SubChunk),
+ #[br(magic(b"IKEY"))]
+ KeyParameters(SubChunk),
+}
+
+/// The repeat mode. This is currently undefined.
+#[binread]
+#[br(import(length: u32))]
+#[derive(Debug)]
+pub struct KeyParameters {
+ #[br(count = length / 2)]
+ pub repeat_mode: Vec,
+}
+
+/// The transfer function is defined by an array of keys, each with an input value and an RGBA
+/// output vector. Given an input value, the gradient can be evaluated by selecting the keys whose
+/// positions bracket the value and interpolating between their outputs. If the input value is lower
+/// than the first key or higher than the last key, the gradient value is the value of the closest
+/// key.
+#[binread]
+#[br(import(length: u32))]
+#[derive(Debug)]
+pub struct KeyValues {
+ #[br(count = length / 18)]
+ pub key_values: Vec,
+}
+
+#[binread]
+#[derive(Debug)]
+pub struct KeyValue {
+ pub input: f32,
+ pub output: [f32; 4],
+}
+
+/// The start and end of the input range. These values only affect the display of the gradient
+/// in the user interface. They don't affect rendering.
+#[binread]
+#[br(import(_length: u32))]
+#[derive(Debug)]
+pub struct GradientRange {
+ pub name: f32,
+}
+
+/// The repeat mode. This is currently undefined.
+#[binread]
+#[br(import(_length: u32))]
+#[derive(Debug)]
+pub struct RepeatMode {
+ pub repeat_mode: u16,
+}
diff --git a/rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs
index 15411f7..688de19 100644
--- a/rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs
+++ b/rust/lightwave/src/lwo2/sub_tags/blocks/mod.rs
@@ -1,11 +1,16 @@
use crate::binrw_helpers::until_size_limit;
use crate::iff::SubChunk;
+use crate::lwo2::sub_tags::blocks::gradient_texture::GradientTextureSubChunk;
use crate::lwo2::sub_tags::blocks::image_texture::SurfaceBlockImageTextureSubChunk;
+use crate::lwo2::sub_tags::blocks::shaders::ShaderAlgorithm;
use crate::lwo2::sub_tags::EnableState;
use crate::lwo2::vx;
use binrw::binread;
+pub mod gradient_texture;
pub mod image_texture;
+pub mod procedural_texture;
+pub mod shaders;
pub mod texture_mapping;
#[binread]
@@ -21,9 +26,17 @@ pub enum SurfaceBlocks {
#[br(magic(b"PROC"))]
ProceduralTexture,
#[br(magic(b"GRAD"))]
- GradientTexture,
+ GradientTexture {
+ header: SubChunk,
+ #[br(parse_with = until_size_limit(length as u64 - (header.length as u64 + 2 + 4)))]
+ attributes: Vec,
+ },
#[br(magic(b"SHDR"))]
- ShaderPlugin,
+ ShaderPlugin {
+ header: SubChunk,
+ #[br(magic(b"FUNC"))]
+ algorithm: SubChunk,
+ },
}
#[binread]
diff --git a/rust/lightwave/src/lwo2/sub_tags/blocks/procedural_texture.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/procedural_texture.rs
new file mode 100644
index 0000000..e69de29
diff --git a/rust/lightwave/src/lwo2/sub_tags/blocks/shaders.rs b/rust/lightwave/src/lwo2/sub_tags/blocks/shaders.rs
new file mode 100644
index 0000000..c3d07a0
--- /dev/null
+++ b/rust/lightwave/src/lwo2/sub_tags/blocks/shaders.rs
@@ -0,0 +1,11 @@
+use binrw::{binread, NullString};
+
+#[binread]
+#[br(import(length: u32))]
+#[derive(Debug)]
+pub struct ShaderAlgorithm {
+ #[br(align_after = 2)]
+ pub algorithm_name: NullString,
+ #[br(count = length - (algorithm_name.len() as u32 + 1))]
+ pub data: Vec,
+}
diff --git a/rust/lightwave/src/lwo2/sub_tags/mod.rs b/rust/lightwave/src/lwo2/sub_tags/mod.rs
index 929f109..098cf8a 100644
--- a/rust/lightwave/src/lwo2/sub_tags/mod.rs
+++ b/rust/lightwave/src/lwo2/sub_tags/mod.rs
@@ -1,9 +1,9 @@
use crate::lwo2::vx;
-use binrw::binread;
+use binrw::{binread, NullString};
pub mod blocks;
-pub mod surface_parameters;
pub mod plugin;
+pub mod surface_parameters;
#[binread]
#[br(import(_length: u32))]
@@ -14,6 +14,14 @@ pub struct VectorEnvelope {
pub envelope: u32,
}
+#[binread]
+#[br(import(_length: u32))]
+#[derive(Debug)]
+pub struct Name {
+ #[br(align_after = 2)]
+ pub name: NullString,
+}
+
#[binread]
#[br(import(_length: u32))]
#[derive(Debug)]