Skip to main content

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