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}