texture paths

This commit is contained in:
Robin Appelman 2023-12-09 23:28:00 +01:00
commit cd5ec8492e
8 changed files with 99 additions and 8 deletions

View file

@ -16,7 +16,7 @@ fn main() -> Result<(), vmdl::ModelError> {
let _vtx = Vtx::read(&data)?;
let data = fs::read(path.with_extension("vvd"))?;
let _vvd = Vvd::read(&data)?;
dbg!(mdl.body_parts);
dbg!(mdl.textures, mdl.texture_paths);
// let model = Model::from_parts(mdl, vtx, vvd);
// for strip in model.vertex_strips() {

View file

@ -1,3 +1,4 @@
use std::string::FromUtf8Error;
use thiserror::Error;
#[non_exhaustive]
@ -20,3 +21,15 @@ pub enum StringError {
#[error("String is not null-terminated")]
NotNullTerminated,
}
impl From<FromUtf8Error> for StringError {
fn from(value: FromUtf8Error) -> Self {
StringError::NonUTF8(value.utf8_error())
}
}
impl From<FromUtf8Error> for ModelError {
fn from(value: FromUtf8Error) -> Self {
StringError::NonUTF8(value.utf8_error()).into()
}
}

View file

@ -141,10 +141,28 @@ trait ReadRelative: Sized {
fn read(data: &[u8], header: Self::Header) -> Result<Self, ModelError>;
}
impl<T: Readable> ReadRelative for T {
trait ReadableRelative: Readable {}
impl ReadableRelative for u8 {}
impl ReadableRelative for u16 {}
impl ReadableRelative for u32 {}
impl ReadableRelative for i8 {}
impl ReadableRelative for i16 {}
impl ReadableRelative for i32 {}
impl<T: ReadableRelative> ReadRelative for T {
type Header = T;
fn read(_data: &[u8], header: Self::Header) -> Result<Self, ModelError> {
Ok(header)
}
}
impl ReadRelative for String {
type Header = ();
fn read(data: &[u8], _header: Self::Header) -> Result<Self, ModelError> {
let bytes = data.iter().copied().take_while(|byte| *byte != 0).collect();
String::from_utf8(bytes).map_err(ModelError::from)
}
}

View file

@ -4,9 +4,12 @@ pub use raw::header::*;
pub use raw::header2::*;
use std::mem::size_of;
use crate::mdl::raw::{BodyPartHeader, Bone, MeshHeader, ModelHeader};
use crate::mdl::raw::{BodyPartHeader, Bone, MeshHeader, MeshTexture, ModelHeader};
use crate::vvd::Vertex;
use crate::{read_indexes, read_relative, FixedString, ModelError, ReadRelative, Readable};
use crate::{
read_indexes, read_relative, read_relative_iter, FixedString, ModelError, ReadRelative,
Readable,
};
type Result<T> = std::result::Result<T, ModelError>;
@ -15,11 +18,22 @@ pub struct Mdl {
pub header: StudioHeader,
pub bones: Vec<Bone>,
pub body_parts: Vec<BodyPart>,
pub textures: Vec<TextureInfo>,
pub texture_paths: Vec<String>,
}
impl Mdl {
pub fn read(data: &[u8]) -> Result<Self> {
let header = <StudioHeader as Readable>::read(data)?;
let textures = read_relative_iter(data, header.texture_indexes())
.collect::<Result<Vec<TextureInfo>>>()?;
let texture_dirs_indexes =
read_relative_iter(data, header.texture_dir_indexes()).collect::<Result<Vec<u32>>>()?;
let texture_paths = read_relative::<String, _>(
data,
texture_dirs_indexes.into_iter().map(|index| index as usize),
)?;
let bones = read_indexes(header.bone_indexes(), data).collect::<Result<_>>()?;
Ok(Mdl {
bones,
@ -34,6 +48,8 @@ impl Mdl {
BodyPart::read(data, header)
})
.collect::<Result<_>>()?,
textures,
texture_paths,
header,
})
}
@ -94,3 +110,18 @@ impl ReadRelative for Mesh {
})
}
}
#[derive(Debug, Clone)]
pub struct TextureInfo {
pub name: String,
}
impl ReadRelative for TextureInfo {
type Header = MeshTexture;
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
Ok(TextureInfo {
name: String::read(&data[header.name_index as usize..], ())?,
})
}
}

View file

@ -229,11 +229,19 @@ impl StudioHeader {
}
pub fn texture_indexes(&self) -> impl Iterator<Item = usize> {
index_range(self.texture_offset, self.texture_count, 1)
index_range(
self.texture_offset,
self.texture_count,
size_of::<MeshTexture>(),
)
}
pub fn texture_dir_indexes(&self) -> impl Iterator<Item = usize> {
index_range(self.texture_dir_offset, self.texture_dir_count, 1)
index_range(
self.texture_dir_offset,
self.texture_dir_count,
size_of::<u32>(),
)
}
pub fn body_part_indexes(&self) -> impl Iterator<Item = usize> {

View file

@ -146,3 +146,18 @@ pub struct MeshVertexData {
model_vertex_data: i32,
lod_vertex_count: [i32; 8],
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)]
#[allow(dead_code)]
pub struct MeshTexture {
pub name_index: i32, // relative offset to this struct
pub flags: i32,
pub used: i32,
_padding: i32,
pub material_ptr: i32,
pub client_material_ptr: i32,
_padding2: [i32; 10],
}
static_assertions::const_assert_eq!(size_of::<MeshTexture>(), 16 * 4);

View file

@ -1,4 +1,4 @@
use crate::{index_range, Pod};
use crate::{index_range, Pod, ReadableRelative};
use bitflags::bitflags;
use bytemuck::Zeroable;
use std::mem::size_of;
@ -215,4 +215,6 @@ pub struct Vertex {
pub bone_id: [u8; 3],
}
impl ReadableRelative for Vertex {}
static_assertions::const_assert_eq!(size_of::<Vertex>(), 9);

View file

@ -1,4 +1,4 @@
use crate::{index_range, Vector};
use crate::{index_range, ReadableRelative, Vector};
use bytemuck::{Pod, Zeroable};
use std::mem::size_of;
@ -51,6 +51,8 @@ pub struct VertexFileFixup {
pub vertex_count: i32,
}
impl ReadableRelative for VertexFileFixup {}
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
#[repr(C)]
pub struct Vertex {
@ -60,6 +62,8 @@ pub struct Vertex {
pub texture_coordinates: [f32; 2],
}
impl ReadableRelative for Vertex {}
static_assertions::const_assert_eq!(size_of::<Vertex>(), 48);
#[derive(Debug, Clone, Zeroable, Pod, Copy)]