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}