rpfm_lib/files/rigidmodel/vertices/
mod.rs1use getset::{Getters, MutGetters, Setters};
69use nalgebra::{Vector2, Vector4};
70use serde::{Deserialize, Serialize};
71
72use crate::binary::{ReadBytes, WriteBytes};
73use crate::error::{Result, RLibError};
74
75use super::materials::MaterialType;
76
77#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
86#[repr(u16)]
87pub enum VertexFormat {
88 #[default]
90 Static = 0,
91 Collision = 1,
93 Weighted = 3,
95 Cinematic = 4,
97 Grass = 5,
99 Uk8 = 8,
101 Uk12 = 12,
103 ClothSim = 25,
105}
106
107#[derive(Clone, Debug, Default, PartialEq, Getters, MutGetters, Setters, Serialize, Deserialize)]
130#[getset(get = "pub", get_mut = "pub", set = "pub")]
131pub struct Vertex {
132
133 position: Vector4<f32>,
136
137 texture_coordinate: Vector2<f32>,
140
141 texture_coordinate2: Vector2<f32>,
144
145 normal: Vector4<f32>,
148
149 tangent: Vector4<f32>,
152
153 bitangent: Vector4<f32>,
156
157 color: Vector4<f32>,
159
160 bone_indices: Vector4<u8>,
164
165 weights: Vector4<f32>,
168
169 uk_1: Vector4<u8>,
171}
172
173impl TryFrom<u16> for VertexFormat {
178 type Error = RLibError;
179 fn try_from(value: u16) -> Result<Self> {
180 match value {
181 _ if value == Self::Static as u16 => Ok(Self::Static),
182 _ if value == Self::Collision as u16 => Ok(Self::Collision),
183 _ if value == Self::Weighted as u16 => Ok(Self::Weighted),
184 _ if value == Self::Cinematic as u16 => Ok(Self::Cinematic),
185 _ if value == Self::Grass as u16 => Ok(Self::Grass),
186 _ if value == Self::Uk8 as u16 => Ok(Self::Uk8),
187 _ if value == Self::Uk12 as u16 => Ok(Self::Uk12),
188 _ if value == Self::ClothSim as u16 => Ok(Self::ClothSim),
189 _ => Err(RLibError::DecodingRigidModelUnknownVertexFormat(value))
190 }
191 }
192}
193
194impl From<VertexFormat> for u16 {
195 fn from(value: VertexFormat) -> u16 {
196 value as u16
197 }
198}
199
200impl Vertex {
201
202 pub fn read<R: ReadBytes>(data: &mut R, version: u32, vtype: VertexFormat, mtype: MaterialType) -> Result<Self> {
222 let mut v = Self::default();
223 match vtype {
224 VertexFormat::Static => match mtype {
225 MaterialType::DefaultMaterial => {
226 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
227 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
228 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
229 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
230 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
231 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
232 v.uk_1 = data.read_vector_4_u8()?;
233 },
234 MaterialType::RsTerrain => {
235 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
236 v.normal = data.read_vector_4_f32_normal_from_vector_4_f16()?;
237 },
238 MaterialType::WeightedTextureBlend => {
239 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
240 v.normal = data.read_vector_4_f32_normal_from_vector_4_f16()?;
241 },
242 MaterialType::ProjectedDecalV4 => {
243 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
244 },
245 MaterialType::RsRiver => {
246 v.position = data.read_vector_4_f32()?;
247 v.normal = data.read_vector_4_f32()?;
248 },
249 MaterialType::TerrainBlend => {
250 v.position = data.read_vector_4_f32()?;
251 v.normal = data.read_vector_4_f32()?;
252 },
253 MaterialType::TiledDirtmap => {
254 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
255 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
256 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
257 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
258 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
259 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
260
261 v.uk_1 = data.read_vector_4_u8()?;
262 },
263 MaterialType::ShipAmbientmap => {
264 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
265 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
266 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
267 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
268 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
269 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
270
271 v.uk_1 = data.read_vector_4_u8()?;
272 },
273 MaterialType::Decal => {
274 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
275 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
276 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
277 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
278 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
279 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
280
281 v.uk_1 = data.read_vector_4_u8()?;
282 }
283 MaterialType::Dirtmap => {
284 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
285 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
286 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
287 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
288 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
289 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
290
291 v.uk_1 = data.read_vector_4_u8()?;
292 }
293 MaterialType::AlphaBlend => {
294 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
295 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
296 }
297 MaterialType::Cloth => {
298 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
299 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
300 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
301 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
302 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
303 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
304
305 v.uk_1 = data.read_vector_4_u8()?;
306 }
307 _ => return Err(RLibError::DecodingRigidModelUnsupportedVertexFormatForMaterial(vtype.into(), mtype.into()))
308 },
309
310 VertexFormat::Collision => {
311 v.position = data.read_vector_4_f32_from_vec_3_f32()?;
312 v.normal = data.read_vector_4_f32_from_vec_3_f32()?;
313 }
314
315 VertexFormat::Weighted => {
316 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
317
318 let bone_indices = data.read_vector_2_u8()?;
319 v.bone_indices = Vector4::new(bone_indices.x, bone_indices.y, 0, 0);
320
321 let weights = data.read_vector_2_f32_pct_from_vector_2_u8()?;
322 v.weights = Vector4::new(weights.x, weights.y, 0.0, 0.0);
323
324 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
325 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
326 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
327 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
328
329 if version >= 8 {
330 v.uk_1 = data.read_vector_4_u8()?;
331 }
332 }
333 VertexFormat::Cinematic => {
334 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
335
336 v.bone_indices = data.read_vector_4_u8()?;
338 v.weights = data.read_vector_4_f32_pct_from_vector_4_u8()?;
339 v.normal = data.read_vector_4_f32_normal_from_vector_4_u8()?;
340 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
341 v.tangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
342 v.bitangent = data.read_vector_4_f32_normal_from_vector_4_u8()?;
343
344 if version >= 8 {
345 v.uk_1 = data.read_vector_4_u8()?;
346 }
347 }
348 VertexFormat::Uk8 => {
349 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
350 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
351 }
352 VertexFormat::Uk12 => {
353 v.position = data.read_vector_4_f32_normal_from_vector_4_f16()?;
354 v.texture_coordinate = data.read_vector_2_f32_from_vector_2_f16()?;
355 v.texture_coordinate2 = data.read_vector_2_f32_from_vector_2_f16()?;
356 v.uk_1 = data.read_vector_4_u8()?;
357 }
358 _ => return Err(RLibError::DecodingRigidModelUnknownVertexFormat(vtype.into()))
359 }
360
361 Ok(v)
362 }
363
364 pub fn write<W: WriteBytes>(&self, data: &mut W, version: u32, vtype: VertexFormat, mtype: MaterialType) -> Result<()> {
384 match vtype {
385 VertexFormat::Static => match mtype {
386 MaterialType::DefaultMaterial => {
387 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
388 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
389 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
390 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
391 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
392 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
393
394 data.write_vector_4_u8(self.uk_1)?;
396 }
397 MaterialType::RsTerrain => {
398 data.write_vector_4_f32_normal_as_vector_4_f16(*self.position())?;
399 data.write_vector_4_f32_normal_as_vector_4_f16(*self.normal())?;
400 }
401 MaterialType::WeightedTextureBlend => {
402 data.write_vector_4_f32_normal_as_vector_4_f16(*self.position())?;
403 data.write_vector_4_f32_normal_as_vector_4_f16(*self.normal())?;
404 }
405 MaterialType::ProjectedDecalV4 => {
406 data.write_vector_4_f32_normal_as_vector_4_f16(*self.position())?;
407 }
408 MaterialType::RsRiver => {
409 data.write_vector_4_f32(*self.position())?;
410 data.write_vector_4_f32(*self.normal())?;
411 }
412 MaterialType::TerrainBlend => {
413 data.write_vector_4_f32(*self.position())?;
414 data.write_vector_4_f32(*self.normal())?;
415 }
416 MaterialType::TiledDirtmap => {
417 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
418 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
419 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
420 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
421 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
422 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
423 data.write_vector_4_u8(self.uk_1)?;
424 }
425 MaterialType::ShipAmbientmap => {
426 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
427 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
428 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
429 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
430 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
431 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
432 data.write_vector_4_u8(self.uk_1)?;
433 }
434 MaterialType::Decal => {
435 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
436 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
437 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
438 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
439 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
440 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
441 data.write_vector_4_u8(self.uk_1)?;
442 }
443 MaterialType::Dirtmap => {
444 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
445 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
446 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
447 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
448 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
449 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
450 data.write_vector_4_u8(self.uk_1)?;
451 }
452 MaterialType::AlphaBlend => {
453 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
454 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
455 }
456 MaterialType::Cloth => {
457 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
458 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
459 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
460 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
461 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
462 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
463 data.write_vector_4_u8(self.uk_1)?;
464 }
465 _ => return Err(RLibError::DecodingRigidModelUnsupportedVertexFormatForMaterial(vtype.into(), mtype.into()))
466 },
467
468 VertexFormat::Collision => {
469 data.write_vector_4_f32_to_vector_3_f32(self.position)?;
470 data.write_vector_4_f32_to_vector_3_f32(self.normal)?;
471 }
472
473 VertexFormat::Weighted => {
474 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
475 data.write_vector_2_u8(Vector2::new(self.bone_indices.x, self.bone_indices.y))?;
476 data.write_vector_2_f32_pct_as_vector_2_u8(Vector2::new(self.weights.x, self.weights.y))?;
477 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
478 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
479 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
480 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
481
482 if version >= 8 {
483 data.write_vector_4_u8(self.uk_1)?;
484 }
485 }
486 VertexFormat::Cinematic => {
487 data.write_vector_4_f32_normal_as_vector_4_f16(self.position)?;
488 data.write_vector_4_u8(self.bone_indices)?;
489 data.write_vector_4_f32_pct_as_vector_4_u8(self.weights)?;
490 data.write_vector_4_f32_normal_as_vector_4_u8(self.normal)?;
491 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
492 data.write_vector_4_f32_normal_as_vector_4_u8(self.tangent)?;
493 data.write_vector_4_f32_normal_as_vector_4_u8(self.bitangent)?;
494
495 if version >= 8 {
496 data.write_vector_4_u8(self.uk_1)?;
497 }
498 }
499 VertexFormat::Uk8 => {
500 data.write_vector_4_f32_normal_as_vector_4_f16(*self.position())?;
501 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
502 }
503 VertexFormat::Uk12 => {
504 data.write_vector_4_f32_normal_as_vector_4_f16(*self.position())?;
505 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate)?;
506 data.write_vector_2_f32_as_vector_2_f16(self.texture_coordinate2)?;
507 data.write_vector_4_u8(self.uk_1)?;
508 }
509 _ => return Err(RLibError::DecodingRigidModelUnknownVertexFormat(vtype.into()))
510 }
511
512 Ok(())
513 }
514}
515