lib3mf_core/model/
materials.rs

1use crate::model::ResourceId;
2use serde::{Deserialize, Serialize};
3
4/// Represents a color in sRGB space with alpha channel.
5///
6/// Colors in 3MF use 8-bit RGBA format, with values from 0-255.
7/// The alpha channel represents opacity (0 = fully transparent, 255 = fully opaque).
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
9pub struct Color {
10    /// Red component (0-255)
11    pub r: u8,
12    /// Green component (0-255)
13    pub g: u8,
14    /// Blue component (0-255)
15    pub b: u8,
16    /// Alpha/opacity component (0-255, where 255 is fully opaque)
17    pub a: u8,
18}
19
20impl Color {
21    pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
22        Self { r, g, b, a }
23    }
24
25    // Parse hex string #RRGGBB or #RRGGBBAA
26    pub fn from_hex(hex: &str) -> Option<Self> {
27        let hex = hex.trim_start_matches('#');
28        let val = u32::from_str_radix(hex, 16).ok()?;
29
30        match hex.len() {
31            6 => Some(Self {
32                r: ((val >> 16) & 0xFF) as u8,
33                g: ((val >> 8) & 0xFF) as u8,
34                b: (val & 0xFF) as u8,
35                a: 255,
36            }),
37            8 => Some(Self {
38                r: ((val >> 24) & 0xFF) as u8,
39                g: ((val >> 16) & 0xFF) as u8,
40                b: ((val >> 8) & 0xFF) as u8,
41                a: (val & 0xFF) as u8,
42            }),
43            _ => None,
44        }
45    }
46
47    /// Convert color to hex string #RRGGBBAA
48    pub fn to_hex(&self) -> String {
49        format!("#{:02X}{:02X}{:02X}{:02X}", self.r, self.g, self.b, self.a)
50    }
51}
52
53/// A base material with a name and display color.
54///
55/// Base materials represent named material types (e.g., "PLA", "ABS", "Steel")
56/// with an associated display color for visualization. The actual material
57/// properties are typically handled by the printer/slicer software based
58/// on the name.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct BaseMaterial {
61    /// Human-readable material name
62    pub name: String,
63    /// Display color for visualization
64    pub display_color: Color,
65}
66
67/// A resource group containing multiple base materials.
68///
69/// Base materials groups are referenced by triangles via property IDs,
70/// with the property index selecting which material from the group to use.
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct BaseMaterialsGroup {
73    /// Unique resource ID for this material group
74    pub id: ResourceId,
75    /// List of materials in this group
76    pub materials: Vec<BaseMaterial>,
77}
78
79/// A resource group containing multiple colors for per-vertex/per-triangle coloring.
80///
81/// Color groups allow assigning different colors to different parts of a mesh.
82/// Triangles reference the group via property ID and select specific colors
83/// via property indices. Colors use RGBA format.
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct ColorGroup {
86    /// Unique resource ID for this color group
87    pub id: ResourceId,
88    /// List of colors in this group
89    pub colors: Vec<Color>,
90}
91
92/// A resource group defining texture coordinates for 2D texture mapping.
93///
94/// Texture groups map UV coordinates to vertices for applying texture images
95/// to mesh surfaces. The texture image itself is stored as an attachment in
96/// the 3MF package and referenced by `texture_id`.
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct Texture2DGroup {
99    /// Unique resource ID for this texture coordinate group
100    pub id: ResourceId,
101    /// Reference to the texture image resource (attachment path)
102    pub texture_id: ResourceId,
103    /// List of UV coordinates
104    pub coords: Vec<Texture2DCoord>,
105}
106
107/// A 2D texture coordinate (UV mapping).
108///
109/// UV coordinates map vertices to positions in a texture image.
110/// Typically, u and v range from 0.0 to 1.0, where (0,0) is one corner
111/// of the texture and (1,1) is the opposite corner.
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct Texture2DCoord {
114    /// Horizontal texture coordinate (typically 0.0 to 1.0)
115    pub u: f32,
116    /// Vertical texture coordinate (typically 0.0 to 1.0)
117    pub v: f32,
118}
119
120/// A resource group for composite/mixed materials.
121///
122/// Composite materials allow blending multiple materials together with
123/// specified mixing ratios. This enables gradient materials, multi-material
124/// prints, and material transitions.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct CompositeMaterials {
127    /// Unique resource ID for this composite materials group
128    pub id: ResourceId,
129    /// Reference to the base materials group to blend from
130    pub base_material_id: ResourceId,
131    /// Indices specifying which base materials are used in composites
132    pub indices: Vec<u32>,
133    /// List of composite material definitions
134    pub composites: Vec<Composite>,
135}
136
137/// A single composite material definition specifying blend ratios.
138///
139/// The values specify mixing ratios for the materials referenced by
140/// the parent `CompositeMaterials`' indices. Values typically sum to 1.0.
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct Composite {
143    /// Mixing ratios for each material (typically summing to 1.0)
144    pub values: Vec<f32>,
145}
146
147/// A resource group for combining multiple property types.
148///
149/// Multi-properties allow applying multiple different property types
150/// (materials, colors, textures) to the same geometry, with specified
151/// blending methods to combine them.
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct MultiProperties {
154    /// Unique resource ID for this multi-properties group
155    pub id: ResourceId,
156    /// List of property resource IDs to combine
157    pub pids: Vec<ResourceId>,
158    /// Blending methods for combining each property
159    pub blend_methods: Vec<BlendMethod>,
160    /// List of multi-property index combinations
161    pub multis: Vec<Multi>,
162}
163
164/// A single multi-property combination specifying indices into each property group.
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct Multi {
167    /// Property indices for each property group (parallel to parent's pids)
168    pub pindices: Vec<u32>,
169}
170
171/// Method for blending multiple properties together.
172///
173/// Determines how multiple properties (e.g., base color and texture) are combined.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
175pub enum BlendMethod {
176    /// No blending - use first property only
177    NoBlend,
178    /// Linear interpolation/mixing
179    Mix,
180    /// Multiplicative blending
181    Multiply,
182}
183
184/// Texture channel for displacement mapping.
185#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
186pub enum Channel {
187    R,
188    #[default]
189    G,
190    B,
191    A,
192}
193
194/// Texture wrapping/tiling style.
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
196#[serde(rename_all = "lowercase")]
197pub enum TileStyle {
198    #[default]
199    Wrap,
200    Mirror,
201    Clamp,
202    None,
203}
204
205/// Texture filtering mode.
206#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
207#[serde(rename_all = "lowercase")]
208pub enum FilterMode {
209    #[default]
210    Linear,
211    Nearest,
212}
213
214/// A 2D displacement texture resource for surface detail.
215///
216/// Displacement textures modify surface geometry based on texture values,
217/// allowing fine surface detail without requiring dense meshes. The texture
218/// values are interpreted as height offsets along surface normals.
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct Displacement2D {
221    /// Unique resource ID for this displacement texture
222    pub id: ResourceId,
223    /// Path to the texture image in the 3MF package
224    pub path: String,
225    /// Which color channel to use for displacement values
226    #[serde(default)]
227    pub channel: Channel,
228    /// How the texture wraps/tiles
229    #[serde(default)]
230    pub tile_style: TileStyle,
231    /// Texture filtering mode
232    #[serde(default)]
233    pub filter: FilterMode,
234    /// Maximum displacement height in model units
235    pub height: f32,
236    /// Base displacement offset in model units
237    #[serde(default)]
238    pub offset: f32,
239}