aboutsummaryrefslogtreecommitdiff
path: root/src/classes/mesh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/classes/mesh.rs')
-rw-r--r--src/classes/mesh.rs148
1 files changed, 125 insertions, 23 deletions
diff --git a/src/classes/mesh.rs b/src/classes/mesh.rs
index 7df7f8d..3883535 100644
--- a/src/classes/mesh.rs
+++ b/src/classes/mesh.rs
@@ -1,8 +1,9 @@
use super::streaminginfo::StreamingInfo;
use crate::object::{Value, parser::FromValue};
-use anyhow::Result;
+use anyhow::{Result, anyhow, bail};
use glam::Mat4;
use serde::Serialize;
+use std::mem::transmute;
#[derive(Debug, Serialize)]
pub struct Mesh {
@@ -13,6 +14,7 @@ pub struct Mesh {
pub index_buffer: Vec<u8>,
pub sub_meshes: Vec<SubMesh>,
pub stream_data: StreamingInfo,
+ pub vertex_data: VertexData,
}
#[derive(Debug, Serialize)]
@@ -28,14 +30,14 @@ pub struct SubMesh {
#[derive(Debug, Serialize)]
pub struct VertexData {
pub channels: Vec<ChannelInfo>,
- pub data_size: Vec<u8>,
+ pub data: Vec<u8>,
pub vertex_count: u32,
}
#[derive(Debug, Serialize)]
pub struct ChannelInfo {
pub dimension: u8,
- pub format: u8,
+ pub format: VertexFormat,
pub offset: u8,
pub stream: u8,
}
@@ -44,8 +46,10 @@ impl FromValue for Mesh {
fn from_value(v: Value) -> Result<Self> {
let mut fields = v.as_class("Mesh").unwrap();
Ok(Mesh {
- name: fields.remove("m_Name").unwrap().parse().unwrap(),
- index_format: fields.remove("m_IndexFormat").unwrap().parse().unwrap(),
+ name: fields.field("m_Name")?,
+ index_format: fields.field("m_IndexFormat")?,
+ vertex_data: fields.field("m_VertexData")?,
+ stream_data: fields.field("m_StreamData")?,
index_buffer: fields
.remove("m_IndexBuffer")
.unwrap()
@@ -62,7 +66,6 @@ impl FromValue for Mesh {
.into_iter()
.map(|e| e.parse().unwrap())
.collect(),
- stream_data: fields.remove("m_StreamData").unwrap().parse().unwrap(),
bind_pose: fields
.remove("m_BindPose")
.unwrap()
@@ -82,25 +85,86 @@ impl FromValue for Mesh {
})
}
}
+impl Mesh {
+ pub fn read_indecies(&self) -> Vec<[u32; 3]> {
+ if self.index_format == 0 {
+ self.index_buffer
+ .array_chunks::<2>()
+ .map(|x| u16::from_le_bytes(*x) as u32)
+ .array_chunks()
+ .collect()
+ } else {
+ self.index_buffer
+ .array_chunks::<4>()
+ .map(|x| u32::from_le_bytes(*x))
+ .array_chunks()
+ .collect()
+ }
+ }
+}
impl FromValue for VertexData {
fn from_value(v: Value) -> Result<Self> {
let mut fields = v.as_class("VertexData").unwrap();
Ok(VertexData {
- vertex_count: fields.remove("vertexCount").unwrap().parse().unwrap(),
+ vertex_count: fields.field("m_VertexCount")?,
+ data: fields.remove("m_DataSize").unwrap().as_typeless().unwrap(),
channels: fields
.remove("m_Channels")
.unwrap()
- .as_array()
+ .as_vector()
.unwrap()
.into_iter()
.map(|e| e.parse().unwrap())
.collect(),
- data_size: fields.remove("m_DataSize").unwrap().as_typeless().unwrap(),
})
}
}
+impl VertexData {
+ /// Returns (offset, stride) for each stream.
+ pub fn stream_layout(&self) -> Vec<(usize, usize)> {
+ let stream_count = self.channels.iter().map(|c| c.stream).max().unwrap() + 1;
+ let mut streams = Vec::new();
+ let mut offset = 0;
+ for si in 0..stream_count {
+ let stride = self
+ .channels
+ .iter()
+ .filter(|c| c.stream == si)
+ .map(|c| c.dimension as usize * c.format.component_size())
+ .sum();
+ streams.push((offset, stride));
+ offset += stride * self.vertex_count as usize
+ }
+ streams
+ }
+ /// Reads a vertex channel and returns dimension count and data converted to floats
+ pub fn read_channel(&self, channel: VertexDataChannel) -> Option<(usize, Vec<f32>)> {
+ let channel = &self.channels[channel as u8 as usize];
+ if channel.dimension == 0 {
+ return None;
+ }
+ let component_offset = channel.offset as usize;
+ let component_size = channel.format.component_size();
+ let (offset, stride) = self.stream_layout()[channel.stream as usize];
+
+ let mut out = Vec::new();
+ for vi in 0..self.vertex_count as usize {
+ for di in 0..channel.dimension as usize {
+ let off = offset + vi * stride + component_offset + component_size * di;
+ let e = &self.data[off..];
+ out.push(match channel.format {
+ VertexFormat::Float => f32::from_le_bytes([e[0], e[1], e[2], e[3]]),
+ VertexFormat::Float16 => f16::from_le_bytes([e[0], e[1]]) as f32,
+ x => todo!("vertex format {x:?}"),
+ })
+ }
+ }
+ Some((channel.dimension as usize, out))
+ }
+}
+
impl FromValue for ChannelInfo {
fn from_value(v: Value) -> Result<Self> {
let mut fields = v.as_class("ChannelInfo").unwrap();
@@ -130,18 +194,56 @@ impl FromValue for SubMesh {
#[repr(u8)]
#[derive(Debug, Serialize, Clone, Copy, PartialEq)]
pub enum VertexDataChannel {
- Position = 0,
- Normal = 1,
- Tangent = 2,
- Color = 3,
- TexCoord0 = 4,
- TexCoord1 = 5,
- TexCoord2 = 6,
- TexCoord3 = 7,
- TexCoord4 = 8,
- TexCoord5 = 9,
- TexCoord6 = 10,
- TexCoord7 = 11,
- BlendWeight = 12,
- BlendIndices = 13,
+ Position,
+ Normal,
+ Tangent,
+ Color,
+ TexCoord0,
+ TexCoord1,
+ TexCoord2,
+ TexCoord3,
+ TexCoord4,
+ TexCoord5,
+ TexCoord6,
+ TexCoord7,
+ BlendWeight,
+ BlendIndices,
+}
+
+#[repr(u8)]
+#[derive(Debug, Serialize, Clone, Copy, PartialEq)]
+pub enum VertexFormat {
+ Float,
+ Float16,
+ UNorm8,
+ SNorm8,
+ UNorm16,
+ SNorm16,
+ UInt8,
+ SInt8,
+ UInt16,
+ SInt16,
+ UInt32,
+ SInt32,
+}
+
+impl FromValue for VertexFormat {
+ fn from_value(v: Value) -> Result<Self> {
+ let x = v.as_u8().ok_or(anyhow!("expected u8 vertex format"))?;
+ if x < 12 {
+ Ok(unsafe { transmute(x) })
+ } else {
+ bail!("unknown vertex format")
+ }
+ }
+}
+impl VertexFormat {
+ pub fn component_size(&self) -> usize {
+ use VertexFormat::*;
+ match self {
+ Float | UInt32 | SInt32 => 4,
+ Float16 | UInt16 | SInt16 | UNorm16 | SNorm16 => 2,
+ UInt8 | SInt8 | UNorm8 | SNorm8 => 1,
+ }
+ }
}