mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
texture paths
This commit is contained in:
parent
1fa7a67515
commit
cd5ec8492e
8 changed files with 99 additions and 8 deletions
|
|
@ -16,7 +16,7 @@ fn main() -> Result<(), vmdl::ModelError> {
|
||||||
let _vtx = Vtx::read(&data)?;
|
let _vtx = Vtx::read(&data)?;
|
||||||
let data = fs::read(path.with_extension("vvd"))?;
|
let data = fs::read(path.with_extension("vvd"))?;
|
||||||
let _vvd = Vvd::read(&data)?;
|
let _vvd = Vvd::read(&data)?;
|
||||||
dbg!(mdl.body_parts);
|
dbg!(mdl.textures, mdl.texture_paths);
|
||||||
|
|
||||||
// let model = Model::from_parts(mdl, vtx, vvd);
|
// let model = Model::from_parts(mdl, vtx, vvd);
|
||||||
// for strip in model.vertex_strips() {
|
// for strip in model.vertex_strips() {
|
||||||
|
|
|
||||||
13
src/error.rs
13
src/error.rs
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::string::FromUtf8Error;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
|
@ -20,3 +21,15 @@ pub enum StringError {
|
||||||
#[error("String is not null-terminated")]
|
#[error("String is not null-terminated")]
|
||||||
NotNullTerminated,
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
20
src/lib.rs
20
src/lib.rs
|
|
@ -141,10 +141,28 @@ trait ReadRelative: Sized {
|
||||||
fn read(data: &[u8], header: Self::Header) -> Result<Self, ModelError>;
|
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;
|
type Header = T;
|
||||||
|
|
||||||
fn read(_data: &[u8], header: Self::Header) -> Result<Self, ModelError> {
|
fn read(_data: &[u8], header: Self::Header) -> Result<Self, ModelError> {
|
||||||
Ok(header)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,12 @@ pub use raw::header::*;
|
||||||
pub use raw::header2::*;
|
pub use raw::header2::*;
|
||||||
use std::mem::size_of;
|
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::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>;
|
type Result<T> = std::result::Result<T, ModelError>;
|
||||||
|
|
||||||
|
|
@ -15,11 +18,22 @@ pub struct Mdl {
|
||||||
pub header: StudioHeader,
|
pub header: StudioHeader,
|
||||||
pub bones: Vec<Bone>,
|
pub bones: Vec<Bone>,
|
||||||
pub body_parts: Vec<BodyPart>,
|
pub body_parts: Vec<BodyPart>,
|
||||||
|
pub textures: Vec<TextureInfo>,
|
||||||
|
pub texture_paths: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mdl {
|
impl Mdl {
|
||||||
pub fn read(data: &[u8]) -> Result<Self> {
|
pub fn read(data: &[u8]) -> Result<Self> {
|
||||||
let header = <StudioHeader as Readable>::read(data)?;
|
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<_>>()?;
|
let bones = read_indexes(header.bone_indexes(), data).collect::<Result<_>>()?;
|
||||||
Ok(Mdl {
|
Ok(Mdl {
|
||||||
bones,
|
bones,
|
||||||
|
|
@ -34,6 +48,8 @@ impl Mdl {
|
||||||
BodyPart::read(data, header)
|
BodyPart::read(data, header)
|
||||||
})
|
})
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
|
textures,
|
||||||
|
texture_paths,
|
||||||
header,
|
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..], ())?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,11 +229,19 @@ impl StudioHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture_indexes(&self) -> impl Iterator<Item = usize> {
|
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> {
|
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> {
|
pub fn body_part_indexes(&self) -> impl Iterator<Item = usize> {
|
||||||
|
|
|
||||||
|
|
@ -146,3 +146,18 @@ pub struct MeshVertexData {
|
||||||
model_vertex_data: i32,
|
model_vertex_data: i32,
|
||||||
lod_vertex_count: [i32; 8],
|
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);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{index_range, Pod};
|
use crate::{index_range, Pod, ReadableRelative};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use bytemuck::Zeroable;
|
use bytemuck::Zeroable;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
@ -215,4 +215,6 @@ pub struct Vertex {
|
||||||
pub bone_id: [u8; 3],
|
pub bone_id: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReadableRelative for Vertex {}
|
||||||
|
|
||||||
static_assertions::const_assert_eq!(size_of::<Vertex>(), 9);
|
static_assertions::const_assert_eq!(size_of::<Vertex>(), 9);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{index_range, Vector};
|
use crate::{index_range, ReadableRelative, Vector};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
|
|
@ -51,6 +51,8 @@ pub struct VertexFileFixup {
|
||||||
pub vertex_count: i32,
|
pub vertex_count: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReadableRelative for VertexFileFixup {}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
|
|
@ -60,6 +62,8 @@ pub struct Vertex {
|
||||||
pub texture_coordinates: [f32; 2],
|
pub texture_coordinates: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReadableRelative for Vertex {}
|
||||||
|
|
||||||
static_assertions::const_assert_eq!(size_of::<Vertex>(), 48);
|
static_assertions::const_assert_eq!(size_of::<Vertex>(), 48);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
#[derive(Debug, Clone, Zeroable, Pod, Copy)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue