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 2D texture resource (image file reference).
121///
122/// Texture2D defines a reference to an image file within the 3MF package
123/// that can be applied to mesh surfaces. The actual image data is stored
124/// as an attachment and referenced by the path.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct Texture2D {
127    /// Unique resource ID for this texture
128    pub id: ResourceId,
129    /// Path to the texture image within the 3MF package (e.g., "/3D/Textures/diffuse.png")
130    pub path: String,
131    /// MIME content type of the texture (e.g., "image/png", "image/jpeg")
132    pub contenttype: String,
133}
134
135/// A resource group for composite/mixed materials.
136///
137/// Composite materials allow blending multiple materials together with
138/// specified mixing ratios. This enables gradient materials, multi-material
139/// prints, and material transitions.
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct CompositeMaterials {
142    /// Unique resource ID for this composite materials group
143    pub id: ResourceId,
144    /// Reference to the base materials group to blend from
145    pub base_material_id: ResourceId,
146    /// Indices specifying which base materials are used in composites
147    pub indices: Vec<u32>,
148    /// List of composite material definitions
149    pub composites: Vec<Composite>,
150}
151
152/// A single composite material definition specifying blend ratios.
153///
154/// The values specify mixing ratios for the materials referenced by
155/// the parent `CompositeMaterials`' indices. Values typically sum to 1.0.
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct Composite {
158    /// Mixing ratios for each material (typically summing to 1.0)
159    pub values: Vec<f32>,
160}
161
162/// A resource group for combining multiple property types.
163///
164/// Multi-properties allow applying multiple different property types
165/// (materials, colors, textures) to the same geometry, with specified
166/// blending methods to combine them.
167#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct MultiProperties {
169    /// Unique resource ID for this multi-properties group
170    pub id: ResourceId,
171    /// List of property resource IDs to combine
172    pub pids: Vec<ResourceId>,
173    /// Blending methods for combining each property
174    pub blend_methods: Vec<BlendMethod>,
175    /// List of multi-property index combinations
176    pub multis: Vec<Multi>,
177}
178
179/// A single multi-property combination specifying indices into each property group.
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct Multi {
182    /// Property indices for each property group (parallel to parent's pids)
183    pub pindices: Vec<u32>,
184}
185
186/// Method for blending multiple properties together.
187///
188/// Determines how multiple properties (e.g., base color and texture) are combined.
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
190pub enum BlendMethod {
191    /// No blending - use first property only
192    NoBlend,
193    /// Linear interpolation/mixing
194    Mix,
195    /// Multiplicative blending
196    Multiply,
197}
198
199/// Texture channel for displacement mapping.
200#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
201pub enum Channel {
202    R,
203    #[default]
204    G,
205    B,
206    A,
207}
208
209/// Texture wrapping/tiling style.
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
211#[serde(rename_all = "lowercase")]
212pub enum TileStyle {
213    #[default]
214    Wrap,
215    Mirror,
216    Clamp,
217    None,
218}
219
220/// Texture filtering mode.
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
222#[serde(rename_all = "lowercase")]
223pub enum FilterMode {
224    #[default]
225    Linear,
226    Nearest,
227}
228
229/// A 2D displacement texture resource for surface detail.
230///
231/// Displacement textures modify surface geometry based on texture values,
232/// allowing fine surface detail without requiring dense meshes. The texture
233/// values are interpreted as height offsets along surface normals.
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct Displacement2D {
236    /// Unique resource ID for this displacement texture
237    pub id: ResourceId,
238    /// Path to the texture image in the 3MF package
239    pub path: String,
240    /// Which color channel to use for displacement values
241    #[serde(default)]
242    pub channel: Channel,
243    /// How the texture wraps/tiles
244    #[serde(default)]
245    pub tile_style: TileStyle,
246    /// Texture filtering mode
247    #[serde(default)]
248    pub filter: FilterMode,
249    /// Maximum displacement height in model units
250    pub height: f32,
251    /// Base displacement offset in model units
252    #[serde(default)]
253    pub offset: f32,
254}