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}