rpfm_lib/files/rigidmodel/materials/mod.rs
1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Material system for RigidModel files.
12//!
13//! # Overview
14//!
15//! Materials define how meshes are rendered in Total War games. Each material type
16//! has specific properties that control textures, shaders, vertex formats, and
17//! rendering behavior. The material system supports 40+ different material types
18//! for various rendering scenarios.
19//!
20//! # Material Types
21//!
22//! Materials are categorized by their rendering purpose:
23//!
24//! ## Standard Rendering
25//! - **DefaultMaterial (68)**: Full-featured material for most meshes
26//! - **Decal (71)**: Applied decals on surfaces
27//! - **Tree (74)**, **TreeLeaf (75)**: Vegetation rendering
28//! - **Grass (69)**: Grass
29//! - **Water (83)**: Water surfaces
30//! - **Unlit (84)**: No lighting calculations
31//!
32//! ## Skeletal Animation (Weighted)
33//! - **WeightedSkin (70)**: Character skin with bone weights
34//! - **WeightedCloth (58)**, **Cloth (60)**: Cloth simulation
35//! - **Weighted (65)**: Generic weighted material
36//!
37//! ## Terrain
38//! - **RsTerrain (66)**: Minimal terrain material
39//! - **CustomTerrain (49)**, **GlobalTerrain (98)**: Terrain variants
40//! - **WeightedTextureBlend (96)**, **TerrainBlend (86)**: Texture blending
41//! - **TiledDirtmap (63)**: Tiled dirt textures
42//!
43//! ## Special Effects
44//! - **Collision (61)**, **CollisionShape (62)**: Collision meshes (invisible)
45//! - **DebugGeometry (46)**: Debug visualization
46//! - **PointLight (38)**, **StaticPointLight (45)**: Light sources
47//! - **Rope (93)**: Rope rendering
48//!
49//! ## Projected Decals
50//! - **ProjectedDecal (67)**, **ProjectedDecalV2 (87)**, **ProjectedDecalV3 (95)**, **ProjectedDecalV4 (97)**
51//!
52//! # Material Data Structure
53//!
54//! Materials contain:
55//! - **Vertex format**: Determines vertex data layout
56//! - **Textures**: Diffuse, normal, specular, masks, etc.
57//! - **Transformation matrices**: 3x4 matrices for positioning/attachment
58//! - **Attachment points**: Named locations for effects/weapons
59//! - **Shader parameters**: Strings, floats, integers, vectors
60//! - **Cloth-specific data**: Physics simulation parameters (cloth materials only)
61//!
62//! # Texture Types
63//!
64//! Materials reference textures by type:
65//! - **Diffuse (0)**: Base color texture
66//! - **Normal (1)**: Normal mapping for surface detail
67//! - **Specular (11)**, **GlossMap (12)**: Reflectivity
68//! - **Mask (3)**: Alpha/transparency mask
69//! - **AmbientOcclusion (5)**: Baked ambient lighting
70//! - **Decal variants**: Special decal textures
71//!
72//! # Implementation Details
73//!
74//! Different material types have different data structures:
75//! - **Default materials**: Full data (textures, params, attachment points)
76//! - **RsTerrain**: Minimal (name + 5 unknown u32 fields)
77//! - **WeightedTextureBlend**: Name + 6 unknown u32 fields
78//! - **AlphaBlend**: Name only
79//! - **Cloth**: Default data + cloth simulation sections (uk_7, uk_8, uk_9)
80//!
81//! See individual material variant modules for format-specific details.
82
83use getset::{Getters, MutGetters, Setters};
84use nalgebra::{Matrix3x4, Vector3, Vector4};
85use serde::{Deserialize, Serialize};
86
87use crate::binary::{ReadBytes, WriteBytes};
88use crate::error::{Result, RLibError};
89
90use super::vertices::VertexFormat;
91use super::{PADDED_SIZE_32, PADDED_SIZE_256};
92
93mod alpha_blend;
94mod cloth;
95mod default;
96mod rs_terrain;
97mod rs_river;
98mod projected_decal_v4;
99mod weighted_texture_blend;
100
101//---------------------------------------------------------------------------//
102// Enum & Structs
103//---------------------------------------------------------------------------//
104
105/// Material type identifier determining rendering behavior and data structure.
106///
107/// Each material type corresponds to a specific shader and vertex format combination.
108/// The numeric value is stored in the RigidModel file format as a u16.
109///
110/// # Categories
111///
112/// - **22-46**: Effects and special materials (BowWave, PointLight, DebugGeometry)
113/// - **49-64**: Terrain and campaign materials
114/// - **65-82**: Weighted (skeletal) materials and variants
115/// - **83-100**: Water, unlit, terrain blends, projected decals
116#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
117#[repr(u16)]
118pub enum MaterialType {
119 /// Boat bow wave effect (water displacement).
120 BowWave = 22,
121 /// Non-rendered material (collision, occlusion, etc.).
122 NonRenderable = 26,
123 /// Texture combo with vertex-based wind animation.
124 TextureComboVertexWind = 29,
125 /// Combined texture material.
126 TextureCombo = 30,
127 /// Waterfall decal effect.
128 DecalWaterfall = 31,
129 /// Simplified standard material.
130 StandardSimple = 32,
131 /// Campaign map tree rendering.
132 CampaignTrees = 34,
133 /// Dynamic point light source.
134 PointLight = 38,
135 /// Static baked point light.
136 StaticPointLight = 45,
137 /// Debug visualization geometry (wireframe, normals, etc.).
138 DebugGeometry = 46,
139 /// Custom terrain material variant.
140 CustomTerrain = 49,
141 /// Cloth material with skeletal weights and physics.
142 WeightedCloth = 58,
143 /// Cloth material with physics simulation.
144 Cloth = 60,
145 /// Collision mesh (invisible, physics only).
146 Collision = 61,
147 /// Collision shape variant.
148 CollisionShape = 62,
149 /// Tiled dirt texture mapping.
150 TiledDirtmap = 63,
151 /// Ship ambient mapping (possibly incorrect identification).
152 ShipAmbientmap = 64,
153 /// Generic weighted material (skeletal animation).
154 Weighted = 65,
155 /// Minimal terrain material (Rome 2 style).
156 RsTerrain = 66,
157 /// Projected decal (first version).
158 ProjectedDecal = 67,
159 /// Default full-featured material (most common).
160 #[default]
161 DefaultMaterial = 68,
162 /// Grass and vegetation material.
163 Grass = 69,
164 /// Weighted skin material (characters with bone weights).
165 WeightedSkin = 70,
166 /// Surface decal material.
167 Decal = 71,
168 /// Decal with dirt mapping.
169 DecalDirtmap = 72,
170 /// Dirt map material.
171 Dirtmap = 73,
172 /// Tree trunk/branch material.
173 Tree = 74,
174 /// Tree leaf material (alpha transparency).
175 TreeLeaf = 75,
176 /// Weighted decal (animated decals on characters).
177 WeightedDecal = 77,
178 /// Weighted decal with dirt mapping.
179 WeightedDecalDirtmap = 78,
180 /// Weighted dirt mapping.
181 WeightedDirtmap = 79,
182 /// Weighted skin with decal overlay.
183 WeightedSkinDecal = 80,
184 /// Weighted skin with decal and dirt mapping.
185 WeightedSkinDecalDirtmap = 81,
186 /// Weighted skin with dirt mapping.
187 WeightedSkinDirtmap = 82,
188 /// Water surface material.
189 Water = 83,
190 /// Unlit material (no lighting calculations, full bright).
191 Unlit = 84,
192 /// Weighted unlit material.
193 WeightedUnlit = 85,
194 /// Terrain texture blending material.
195 TerrainBlend = 86,
196 /// Projected decal version 2.
197 ProjectedDecalV2 = 87,
198 /// Ignored/placeholder material.
199 Ignore = 88,
200 /// Billboard-style tree material (always faces camera).
201 TreeBillboardMaterial = 89,
202 /// River rendering material (Rome 2 style).
203 RsRiver = 90,
204 /// Water displacement volume (physics interaction).
205 WaterDisplaceVolume = 91,
206 /// Rope rendering material.
207 Rope = 93,
208 /// Campaign map vegetation.
209 CampaignVegetation = 94,
210 /// Projected decal version 3.
211 ProjectedDecalV3 = 95,
212 /// Weighted texture blending.
213 WeightedTextureBlend = 96,
214 /// Projected decal version 4 (latest).
215 ProjectedDecalV4 = 97,
216 /// Global terrain material.
217 GlobalTerrain = 98,
218 /// Overlay decal material.
219 DecalOverlay = 99,
220 /// Alpha-blended material.
221 AlphaBlend = 100,
222}
223
224/// Complete material definition with textures, transforms, and shader parameters.
225///
226/// Materials contain all rendering data except geometry. The exact fields present
227/// depend on the material type - some types use only a subset of these fields.
228///
229/// # Field Organization
230///
231/// - **Identification**: `vertex_format`, `name`
232/// - **Unknown fields**: `uk_1` through `uk_6` (only in certain material types)
233/// - **Textures**: `texture_directory`, `textures` list
234/// - **Transforms**: `v_pivot`, `matrix1/2/3`, matrix indices
235/// - **Attachments**: `attachment_points` for effects/weapons
236/// - **Shader params**: `params_string`, `params_f32`, `params_i32`, `params_vector4df32`
237/// - **Cloth physics**: `uk_7`, `uk_8`, `uk_9` (cloth materials only)
238///
239/// # Matrix Storage
240///
241/// 3x4 matrices are stored in the same format as skeleton bind pose matrices.
242/// The implicit fourth row `[0, 0, 0, 1]` must be added when converting to 4x4.
243#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
244#[getset(get = "pub", get_mut = "pub", set = "pub")]
245pub struct Material {
246 /// Vertex format determining vertex data layout.
247 vertex_format: VertexFormat,
248
249 /// Material name (human-readable identifier).
250 name: String,
251
252 /// Unknown field 1 (only in RsTerrain and projected decal materials).
253 uk_1: u32,
254 /// Unknown field 2 (only in RsTerrain and projected decal materials).
255 uk_2: u32,
256 /// Unknown field 3 (only in RsTerrain and projected decal materials).
257 uk_3: u32,
258 /// Unknown field 4 (only in RsTerrain and projected decal materials).
259 uk_4: u32,
260 /// Unknown field 5 (only in RsTerrain and projected decal materials).
261 uk_5: u32,
262 /// Unknown field 6 (only in RsTerrain and projected decal materials).
263 uk_6: u32,
264
265 /// Directory path for texture files (relative to game data directory).
266 texture_directory: String,
267
268 /// Filter settings (NOT part of file format, runtime-only).
269 filters: String,
270
271 /// Padding byte 0 (alignment/reserved).
272 padding_byte0: u8,
273 /// Padding byte 1 (alignment/reserved).
274 padding_byte1: u8,
275
276 /// Pivot point for transformations.
277 v_pivot: Vector3<f32>,
278
279 /// Transform matrix 1 (3x4, implicit 4th row: [0, 0, 0, 1]).
280 matrix1: Matrix3x4<f32>,
281 /// Transform matrix 2 (3x4, implicit 4th row: [0, 0, 0, 1]).
282 matrix2: Matrix3x4<f32>,
283 /// Transform matrix 3 (3x4, implicit 4th row: [0, 0, 0, 1]).
284 matrix3: Matrix3x4<f32>,
285
286 /// Matrix index in hierarchy.
287 i_matrix_index: i32,
288 /// Parent matrix index for hierarchical transforms.
289 i_parent_matrix_index: i32,
290
291 /// Additional padding bytes (variable length).
292 sz_padding: Vec<u8>,
293
294 /// Named attachment points for weapons, effects, banners, etc.
295 attachment_points: Vec<AttachmentPointEntry>,
296
297 /// Texture list with type and path for each texture.
298 textures: Vec<Texture>,
299
300 /// String shader parameters (index, value pairs).
301 params_string: Vec<(i32, String)>,
302 /// Float shader parameters (index, value pairs).
303 params_f32: Vec<(i32, f32)>,
304 /// Integer shader parameters (index, value pairs).
305 params_i32: Vec<(i32, i32)>,
306 /// Vector4 shader parameters (index, value pairs).
307 params_vector4df32: Vec<(i32, Vector4<f32>)>,
308
309 /// Cloth physics data section 1 (cloth materials only, format undocumented).
310 uk_7: Vec<Uk7>,
311 /// Cloth physics data section 2 (cloth materials only, format undocumented).
312 uk_8: Vec<Uk8>,
313 /// Cloth physics data section 3 (cloth materials only, format undocumented).
314 uk_9: Vec<Uk9>,
315}
316
317/// Named attachment point for visual effects, weapons, or equipment.
318///
319/// Attachment points define locations on a model where other objects can be attached,
320/// such as weapon hardpoints, banner poles, or particle effect emitters.
321#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
322#[getset(get = "pub", get_mut = "pub", set = "pub")]
323pub struct AttachmentPointEntry {
324 /// Attachment point name (e.g., "weapon_1", "engine_exhaust").
325 name: String,
326
327 /// 3x4 transform matrix positioning the attachment point (implicit 4th row: [0, 0, 0, 1]).
328 matrix: Matrix3x4<f32>,
329
330 /// Bone ID for skeletal attachment (0 for non-skeletal).
331 bone_id: u32,
332}
333
334/// Texture reference with type and file path.
335#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
336#[getset(get = "pub", get_mut = "pub", set = "pub")]
337pub struct Texture {
338 /// Texture type/slot (diffuse, normal, specular, etc.).
339 tex_type: TextureType,
340
341 /// Relative path to texture file (from `texture_directory`).
342 path: String,
343}
344
345/// Texture type identifier for shader texture slots.
346///
347/// Determines which shader texture slot this texture is bound to during rendering.
348/// The numeric value is stored as an i32 in the file format.
349#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
350#[repr(i32)]
351pub enum TextureType {
352 /// Base color/albedo texture.
353 #[default]
354 Diffuse = 0,
355 /// Normal map for surface detail (tangent space).
356 Normal = 1,
357 /// Alpha/transparency mask.
358 Mask = 3,
359 /// Baked ambient occlusion.
360 AmbientOcclusion = 5,
361 /// Tiling dirt texture (UV set 2).
362 TilingDirtUV2 = 7,
363 /// Dirt alpha mask.
364 DirtAlphaMask = 8,
365 /// Skin mask texture.
366 SkinMask = 10,
367 /// Specular reflectivity map.
368 Specular = 11,
369 /// Gloss/smoothness map (specular roughness).
370 GlossMap = 12,
371 /// Decal dirt map.
372 DecalDirtmap = 13,
373 /// Decal dirt mask.
374 DecalDirtmask = 14,
375 /// Decal alpha mask.
376 DecalMask = 15,
377 /// Damaged diffuse texture variant.
378 DiffuseDamage = 17,
379 /// PBR base color.
380 BaseColor = 27,
381 /// PBR material properties (metallic/roughness/AO packed).
382 MaterialMap = 29,
383}
384
385/// Cloth physics data structure 1 (format undocumented).
386///
387/// This structure appears only in cloth materials and likely contains cloth simulation
388/// parameters. The exact meaning of the fields is not yet reverse-engineered.
389#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
390#[getset(get = "pub", get_mut = "pub", set = "pub")]
391pub struct Uk7 {
392 /// Unknown integer field 1 (possibly constraint/spring index).
393 uk1: i32,
394 /// Unknown integer field 2 (possibly vertex/node index).
395 uk2: i32,
396 /// Unknown float field (possibly stiffness/damping coefficient).
397 uk3: f32,
398}
399
400/// Cloth physics data structure 2 (format undocumented).
401///
402/// This structure appears only in cloth materials and likely contains cloth simulation
403/// parameters. The exact meaning of the field is not yet reverse-engineered.
404#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
405#[getset(get = "pub", get_mut = "pub", set = "pub")]
406pub struct Uk8 {
407 /// Unknown integer field (possibly fixed vertex/anchor point index).
408 uk1: i32,
409}
410
411/// Cloth physics data structure 3 (format undocumented).
412///
413/// This structure appears only in cloth materials and likely contains cloth simulation
414/// parameters. The exact meaning of the fields is not yet reverse-engineered.
415#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
416#[getset(get = "pub", get_mut = "pub", set = "pub")]
417pub struct Uk9 {
418 /// Unknown integer field 1 (possibly triangle/face index).
419 uk1: i32,
420 /// Unknown integer field 2 (possibly collision group).
421 uk2: i32,
422 /// Unknown integer field 3 (possibly property flags).
423 uk3: i32,
424}
425
426//---------------------------------------------------------------------------//
427// Implementation
428//---------------------------------------------------------------------------//
429
430
431impl Material {
432
433 /// Reads a material from binary data based on the material type.
434 ///
435 /// Different material types have different binary layouts. This function
436 /// dispatches to the appropriate type-specific reader.
437 ///
438 /// # Errors
439 ///
440 /// Returns [`RLibError::DecodingRigidModelUnsupportedMaterialType`] if the
441 /// material type is not supported.
442 pub fn read<R: ReadBytes>(data: &mut R, mtype: MaterialType) -> Result<Self> {
443 Ok(match mtype {
444 MaterialType::RsTerrain => Self::read_rs_terrain(data)?,
445 MaterialType::RsRiver => Self::read_rs_river(data)?,
446 MaterialType::WeightedTextureBlend => Self::read_weighted_texture_blend(data)?,
447 //MaterialType::ProjectedDecalV4 => Self::read_projected_decal_v4(data)?,
448 MaterialType::AlphaBlend => Self::read_alpha_blend(data)?,
449 MaterialType::Cloth => Self::read_cloth(data)?,
450 MaterialType::ProjectedDecalV4 |
451 MaterialType::Water |
452 MaterialType::TiledDirtmap |
453 MaterialType::ShipAmbientmap |
454 MaterialType::TerrainBlend |
455 MaterialType::Weighted |
456 MaterialType::DefaultMaterial => Self::read_default(data)?,
457 _ => return Err(RLibError::DecodingRigidModelUnsupportedMaterialType(mtype.into()))
458 })
459 }
460
461 /// Writes a material to binary data based on the material type.
462 ///
463 /// Different material types have different binary layouts. This function
464 /// dispatches to the appropriate type-specific writer.
465 ///
466 /// # Errors
467 ///
468 /// Returns [`RLibError::DecodingRigidModelUnsupportedMaterialType`] if the
469 /// material type is not supported.
470 pub fn write<W: WriteBytes>(&self, buffer: &mut W, mtype: MaterialType) -> Result<()> {
471 match mtype {
472 MaterialType::RsTerrain => self.write_rs_terrain(buffer)?,
473 MaterialType::RsRiver => self.write_rs_river(buffer)?,
474 MaterialType::WeightedTextureBlend => self.write_weighted_texture_blend(buffer)?,
475 //MaterialType::ProjectedDecalV4 => self.write_projected_decal_v4(buffer)?,
476 MaterialType::AlphaBlend => self.write_alpha_blend(buffer)?,
477 MaterialType::Cloth => self.write_cloth(buffer)?,
478 MaterialType::ProjectedDecalV4 |
479 MaterialType::Water |
480 MaterialType::TiledDirtmap |
481 MaterialType::ShipAmbientmap |
482 MaterialType::TerrainBlend |
483 MaterialType::Weighted |
484 MaterialType::DefaultMaterial => self.write_default(buffer)?,
485 _ => return Err(RLibError::DecodingRigidModelUnsupportedMaterialType(mtype.into()))
486 }
487
488 Ok(())
489 }
490}
491
492impl TryFrom<u16> for MaterialType {
493 type Error = RLibError;
494 fn try_from(value: u16) -> Result<Self> {
495 match value {
496 _ if value == Self::BowWave as u16 => Ok(Self::BowWave),
497 _ if value == Self::NonRenderable as u16 => Ok(Self::NonRenderable),
498 _ if value == Self::TextureComboVertexWind as u16 => Ok(Self::TextureComboVertexWind),
499 _ if value == Self::TextureCombo as u16 => Ok(Self::TextureCombo),
500 _ if value == Self::DecalWaterfall as u16 => Ok(Self::DecalWaterfall),
501 _ if value == Self::StandardSimple as u16 => Ok(Self::StandardSimple),
502 _ if value == Self::CampaignTrees as u16 => Ok(Self::CampaignTrees),
503 _ if value == Self::PointLight as u16 => Ok(Self::PointLight),
504 _ if value == Self::StaticPointLight as u16 => Ok(Self::StaticPointLight),
505 _ if value == Self::DebugGeometry as u16 => Ok(Self::DebugGeometry),
506 _ if value == Self::CustomTerrain as u16 => Ok(Self::CustomTerrain),
507 _ if value == Self::WeightedCloth as u16 => Ok(Self::WeightedCloth),
508 _ if value == Self::Cloth as u16 => Ok(Self::Cloth),
509 _ if value == Self::Collision as u16 => Ok(Self::Collision),
510 _ if value == Self::CollisionShape as u16 => Ok(Self::CollisionShape),
511 _ if value == Self::TiledDirtmap as u16 => Ok(Self::TiledDirtmap),
512 _ if value == Self::ShipAmbientmap as u16 => Ok(Self::ShipAmbientmap),
513 _ if value == Self::Weighted as u16 => Ok(Self::Weighted),
514 _ if value == Self::RsTerrain as u16 => Ok(Self::RsTerrain),
515 _ if value == Self::ProjectedDecal as u16 => Ok(Self::ProjectedDecal),
516 _ if value == Self::DefaultMaterial as u16 => Ok(Self::DefaultMaterial),
517 _ if value == Self::Grass as u16 => Ok(Self::Grass),
518 _ if value == Self::WeightedSkin as u16 => Ok(Self::WeightedSkin),
519 _ if value == Self::Decal as u16 => Ok(Self::Decal),
520 _ if value == Self::DecalDirtmap as u16 => Ok(Self::DecalDirtmap),
521 _ if value == Self::Dirtmap as u16 => Ok(Self::Dirtmap),
522 _ if value == Self::Tree as u16 => Ok(Self::Tree),
523 _ if value == Self::TreeLeaf as u16 => Ok(Self::TreeLeaf),
524 _ if value == Self::WeightedDecal as u16 => Ok(Self::WeightedDecal),
525 _ if value == Self::WeightedDecalDirtmap as u16 => Ok(Self::WeightedDecalDirtmap),
526 _ if value == Self::WeightedDirtmap as u16 => Ok(Self::WeightedDirtmap),
527 _ if value == Self::WeightedSkinDecal as u16 => Ok(Self::WeightedSkinDecal),
528 _ if value == Self::WeightedSkinDecalDirtmap as u16 => Ok(Self::WeightedSkinDecalDirtmap),
529 _ if value == Self::WeightedSkinDirtmap as u16 => Ok(Self::WeightedSkinDirtmap),
530 _ if value == Self::Water as u16 => Ok(Self::Water),
531 _ if value == Self::Unlit as u16 => Ok(Self::Unlit),
532 _ if value == Self::WeightedUnlit as u16 => Ok(Self::WeightedUnlit),
533 _ if value == Self::TerrainBlend as u16 => Ok(Self::TerrainBlend),
534 _ if value == Self::ProjectedDecalV2 as u16 => Ok(Self::ProjectedDecalV2),
535 _ if value == Self::Ignore as u16 => Ok(Self::Ignore),
536 _ if value == Self::TreeBillboardMaterial as u16 => Ok(Self::TreeBillboardMaterial),
537 _ if value == Self::RsRiver as u16 => Ok(Self::RsRiver),
538 _ if value == Self::WaterDisplaceVolume as u16 => Ok(Self::WaterDisplaceVolume),
539 _ if value == Self::Rope as u16 => Ok(Self::Rope),
540 _ if value == Self::CampaignVegetation as u16 => Ok(Self::CampaignVegetation),
541 _ if value == Self::ProjectedDecalV3 as u16 => Ok(Self::ProjectedDecalV3),
542 _ if value == Self::WeightedTextureBlend as u16 => Ok(Self::WeightedTextureBlend),
543 _ if value == Self::ProjectedDecalV4 as u16 => Ok(Self::ProjectedDecalV4),
544 _ if value == Self::GlobalTerrain as u16 => Ok(Self::GlobalTerrain),
545 _ if value == Self::DecalOverlay as u16 => Ok(Self::DecalOverlay),
546 _ if value == Self::AlphaBlend as u16 => Ok(Self::AlphaBlend),
547 _ => Err(RLibError::DecodingRigidModelUnsupportedMaterialType(value))
548 }
549 }
550}
551
552impl From<MaterialType> for u16 {
553 fn from(value: MaterialType) -> u16 {
554 value as u16
555 }
556}
557
558impl TryFrom<i32> for TextureType {
559 type Error = RLibError;
560 fn try_from(value: i32) -> Result<Self> {
561 match value {
562 _ if value == Self::Diffuse as i32 => Ok(Self::Diffuse),
563 _ if value == Self::Normal as i32 => Ok(Self::Normal),
564 _ if value == Self::Mask as i32 => Ok(Self::Mask),
565 _ if value == Self::AmbientOcclusion as i32 => Ok(Self::AmbientOcclusion),
566 _ if value == Self::TilingDirtUV2 as i32 => Ok(Self::TilingDirtUV2),
567 _ if value == Self::DirtAlphaMask as i32 => Ok(Self::DirtAlphaMask),
568 _ if value == Self::SkinMask as i32 => Ok(Self::SkinMask),
569 _ if value == Self::Specular as i32 => Ok(Self::Specular),
570 _ if value == Self::GlossMap as i32 => Ok(Self::GlossMap),
571 _ if value == Self::DecalDirtmap as i32 => Ok(Self::DecalDirtmap),
572 _ if value == Self::DecalDirtmask as i32 => Ok(Self::DecalDirtmask),
573 _ if value == Self::DecalMask as i32 => Ok(Self::DecalMask),
574 _ if value == Self::DiffuseDamage as i32 => Ok(Self::DiffuseDamage),
575 _ if value == Self::BaseColor as i32 => Ok(Self::BaseColor),
576 _ if value == Self::MaterialMap as i32 => Ok(Self::MaterialMap),
577 _ => Err(RLibError::DecodingRigidModelUnknownTextureType(value))
578 }
579 }
580}
581
582impl TryFrom<TextureType> for i32 {
583 type Error = RLibError;
584 fn try_from(value: TextureType) -> Result<i32> {
585 Ok(value as i32)
586 }
587}