use std::io::{Read, Seek, SeekFrom};
use crate::chunk_ids::*;
use crate::error::{ImodError, ImodResult};
use crate::model::*;
trait ReadImod: Read + Seek {
fn read_u32(&mut self) -> ImodResult<u32> {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
Ok(u32::from_be_bytes(buf))
}
fn read_i32(&mut self) -> ImodResult<i32> {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
Ok(i32::from_be_bytes(buf))
}
fn read_f32(&mut self) -> ImodResult<f32> {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
Ok(f32::from_be_bytes(buf))
}
fn read_u16(&mut self) -> ImodResult<u16> {
let mut buf = [0u8; 2];
self.read_exact(&mut buf)?;
Ok(u16::from_be_bytes(buf))
}
fn read_u8(&mut self) -> ImodResult<u8> {
let mut buf = [0u8; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
}
fn read_i32s(&mut self, n: usize) -> ImodResult<Vec<i32>> {
let mut v = vec![0i32; n];
let mut buf = vec![0u8; n * 4];
self.read_exact(&mut buf)?;
for (i, chunk) in buf.chunks_exact(4).enumerate() {
v[i] = i32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
}
Ok(v)
}
fn read_f32s(&mut self, n: usize) -> ImodResult<Vec<f32>> {
let mut v = vec![0f32; n];
let mut buf = vec![0u8; n * 4];
self.read_exact(&mut buf)?;
for (i, chunk) in buf.chunks_exact(4).enumerate() {
v[i] = f32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
}
Ok(v)
}
fn read_bytes(&mut self, n: usize) -> ImodResult<Vec<u8>> {
let mut buf = vec![0u8; n];
self.read_exact(&mut buf)?;
Ok(buf)
}
fn read_padded_string(&mut self, len: usize) -> ImodResult<String> {
let bytes = self.read_bytes(len)?;
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
Ok(String::from_utf8_lossy(&bytes[..end]).to_string())
}
fn skip(&mut self, n: u32) -> ImodResult<()> {
if n > 0 {
self.seek(SeekFrom::Current(n as i64))?;
}
Ok(())
}
}
impl<T: Read + Seek> ReadImod for T {}
pub fn read_binary<R: Read + Seek>(reader: &mut R) -> ImodResult<Imod> {
let magic = reader.read_u32()?;
if magic != ID_IMOD {
return Err(ImodError::InvalidMagic);
}
let version = reader.read_u32()?;
if version == ID_V01 {
return read_v01(reader);
}
read_header_v02(reader, version)
}
fn read_v01<R: Read + Seek>(reader: &mut R) -> ImodResult<Imod> {
let mut model = Imod::default();
model.name = reader.read_padded_string(IMOD_STRSIZE)?;
let header_ints = reader.read_i32s(9)?;
model.xmax = header_ints[0];
model.ymax = header_ints[1];
model.zmax = header_ints[2];
model.objsize = header_ints[3];
model.flags = header_ints[4] as u32;
model.drawmode = header_ints[5];
model.mousemode = header_ints[6];
model.blacklevel = header_ints[7];
model.whitelevel = header_ints[8];
let ofs = reader.read_f32s(3)?;
model.xoffset = ofs[0];
model.yoffset = ofs[1];
model.zoffset = ofs[2];
model.obj = Vec::with_capacity(model.objsize as usize);
for _ in 0..model.objsize {
let obj = read_object_v01(reader)?;
model.obj.push(obj);
}
Ok(model)
}
fn read_object_v01<R: ReadImod>(reader: &mut R) -> ImodResult<Iobj> {
loop {
let pos__ = reader.seek(std::io::SeekFrom::Current(0)).unwrap_or(0);
eprintln!(" DBG chunk at pos {}", pos__);
let id = reader.read_u32()?;
if id == ID_OBJT {
break;
}
let size = reader.read_u32()?;
reader.skip(size)?;
}
let mut obj = Iobj::default();
obj.name = reader.read_padded_string(IMOD_STRSIZE)?;
let extra_ints = reader.read_i32s(4)?;
obj.contsize = extra_ints[0];
obj.flags = extra_ints[1] as u32;
obj.axis = extra_ints[2];
obj.drawmode = extra_ints[3];
let colors = reader.read_f32s(3)?;
obj.red = colors[0];
obj.green = colors[1];
obj.blue = colors[2];
obj.pdrawsize = reader.read_i32()?;
if obj.pdrawsize < 1 {
obj.pdrawsize = 1;
}
obj.linewidth = reader.read_i32()? as u8;
if obj.linewidth < 1 {
obj.linewidth = 1;
}
obj.linewidth2 = 1;
obj.symbol = 0;
obj.symsize = 3;
obj.linesty = 0;
obj.symflags = 0;
obj.sympad = 0;
obj.trans = reader.read_i32()? as u8;
obj.meshsize = reader.read_i32()?;
if obj.contsize > 0 {
obj.cont = Vec::with_capacity(obj.contsize as usize);
for _ in 0..obj.contsize {
let cont = read_contour_v01(reader)?;
obj.cont.push(cont);
}
}
Ok(obj)
}
fn read_contour_v01<R: ReadImod>(reader: &mut R) -> ImodResult<Icont> {
loop {
let pos__ = reader.seek(std::io::SeekFrom::Current(0)).unwrap_or(0);
eprintln!(" DBG chunk at pos {}", pos__);
let id = reader.read_u32()?;
if id == ID_CONT {
break;
}
let size = reader.read_u32()?;
reader.skip(size)?;
}
let header = reader.read_i32s(4)?;
let psize = header[0];
let pnts_id = reader.read_u32()?;
if pnts_id != ID_PNTS {
return Err(ImodError::CorruptData("expected ID_PNTS in V0.1 contour".into()));
}
let pts = if psize > 0 {
let coords = reader.read_f32s((psize * 3) as usize)?;
coords
.chunks_exact(3)
.map(|c| Ipoint {
x: c[0],
y: c[1],
z: c[2],
})
.collect()
} else {
Vec::new()
};
Ok(Icont {
psize,
pts,
..Icont::default()
})
}
fn read_header_v02<R: Read + Seek>(reader: &mut R, _version: u32) -> ImodResult<Imod> {
let mut model = Imod::default();
model.name = reader.read_padded_string(IMOD_STRSIZE)?;
let h9 = reader.read_i32s(9)?;
model.xmax = h9[0];
model.ymax = h9[1];
model.zmax = h9[2];
model.objsize = h9[3];
model.flags = h9[4] as u32;
model.drawmode = h9[5];
model.mousemode = h9[6];
model.blacklevel = h9[7];
model.whitelevel = h9[8];
let h6f = reader.read_f32s(6)?;
model.xoffset = h6f[0];
model.yoffset = h6f[1];
model.zoffset = h6f[2];
model.xscale = h6f[3];
model.yscale = h6f[4];
model.zscale = h6f[5];
let h5 = reader.read_i32s(5)?;
model.cindex.object = h5[0];
model.cindex.contour = h5[1];
model.cindex.point = h5[2];
model.ctime = h5[3];
model.tmax = h5[4];
model.pixsize = reader.read_f32()?;
model.units = reader.read_i32()?;
model.csum = reader.read_u32()?;
let alpha_r = reader.read_f32s(3)?;
model.alpha = alpha_r[0];
model.beta = alpha_r[1];
model.gamma = alpha_r[2];
model.obj = Vec::with_capacity(model.objsize.max(0) as usize);
let mut obj_ind: i32 = -1;
let mut cont_ind: i32 = -1;
let mut mesh_ind: i32 = -1;
let mut need_cont_array = false;
let mut need_mesh_array = false;
loop {
let id = match reader.read_u32() {
Ok(id) => id,
Err(ImodError::Io(ref e))
if e.kind() == std::io::ErrorKind::UnexpectedEof =>
{
break;
}
Err(e) => return Err(e),
};
match id {
ID_OBJT => {
obj_ind += 1;
if obj_ind >= model.objsize {
return Err(ImodError::CorruptData(format!(
"object index {} out of range ({})",
obj_ind, model.objsize
)));
}
let obj = read_object(reader)?;
model.obj.push(obj);
cont_ind = -1;
mesh_ind = -1;
need_cont_array = true;
need_mesh_array = true;
}
ID_OLBL => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("OLBL without object".into()));
}
let label = read_label(reader)?;
model.obj[obj_ind as usize].label = Some(label);
}
ID_CONT => {
cont_ind += 1;
let obj = &mut model.obj[obj_ind as usize];
if need_cont_array && obj.contsize > 0 {
obj.cont = Vec::with_capacity(obj.contsize as usize);
need_cont_array = false;
}
if cont_ind >= obj.contsize {
return Err(ImodError::CorruptData(format!(
"contour index {} out of range ({})",
cont_ind, obj.contsize
)));
}
let cont = read_contour(reader)?;
obj.cont.push(cont);
}
ID_LABL => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("LABL without object".into()));
}
let obj = &mut model.obj[obj_ind as usize];
if cont_ind < 0 || cont_ind as usize >= obj.cont.len() {
return Err(ImodError::CorruptData("LABL without contour".into()));
}
let label = read_label(reader)?;
obj.cont[cont_ind as usize].label = Some(label);
}
ID_SIZE => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("SIZE without object".into()));
}
let obj = &model.obj[obj_ind as usize];
if cont_ind < 0 || cont_ind as usize >= obj.cont.len() {
return Err(ImodError::CorruptData("SIZE without contour".into()));
}
let psize = obj.cont[cont_ind as usize].psize as usize;
reader.read_u32()?;
let sizes = if psize > 0 {
Some(reader.read_f32s(psize)?)
} else {
None
};
let obj = &mut model.obj[obj_ind as usize];
obj.cont[cont_ind as usize].sizes = sizes;
}
ID_MESH => {
mesh_ind += 1;
let obj = &mut model.obj[obj_ind as usize];
if need_mesh_array && obj.meshsize > 0 {
obj.mesh = Vec::with_capacity(obj.meshsize as usize);
need_mesh_array = false;
}
if mesh_ind >= obj.meshsize {
return Err(ImodError::CorruptData(format!(
"mesh index {} out of range ({})",
mesh_ind, obj.meshsize
)));
}
let mesh = read_mesh(reader)?;
obj.mesh.push(mesh);
}
ID_CLIP => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("CLIP without object".into()));
}
let clips = read_clip_planes(reader, model.flags)?;
model.obj[obj_ind as usize].clips = clips;
}
ID_IMAT => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("IMAT without object".into()));
}
_ = reader.read_u32()?; read_material(reader, &mut model.obj[obj_ind as usize], model.flags)?;
}
ID_VIEW => {
read_view(reader, &mut model)?;
}
ID_MCLP => {
read_view_clip(reader, &mut model)?;
}
ID_IMNX => {
let ref_img = read_ref_image(reader)?;
model.ref_image = Some(ref_img);
}
ID_MOST => {
model.store = read_store(reader)?;
}
ID_OBST => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("OBST without object".into()));
}
model.obj[obj_ind as usize].store = read_store(reader)?;
}
ID_COST => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("COST without object".into()));
}
let obj = &model.obj[obj_ind as usize];
if cont_ind < 0 || cont_ind as usize >= obj.cont.len() {
return Err(ImodError::CorruptData("COST without contour".into()));
}
let store = read_store(reader)?;
let obj = &mut model.obj[obj_ind as usize];
obj.cont[cont_ind as usize].store = store;
}
ID_MEST => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("MEST without object".into()));
}
let obj = &model.obj[obj_ind as usize];
if mesh_ind < 0 || mesh_ind as usize >= obj.mesh.len() {
return Err(ImodError::CorruptData("MEST without mesh".into()));
}
let store = read_store(reader)?;
let obj = &mut model.obj[obj_ind as usize];
obj.mesh[mesh_ind as usize].store = store;
}
ID_MEPA => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("MEPA without object".into()));
}
_ = reader.read_u32()?; let mp = read_mesh_params(reader)?;
model.obj[obj_ind as usize].mesh_param = Some(mp);
}
ID_SKLI => {
if obj_ind < 0 || obj_ind as usize >= model.obj.len() {
return Err(ImodError::CorruptData("SKLI without object".into()));
}
let size = reader.read_u32()?;
let n_ints = (size / 4) as usize;
let skip_list = reader.read_i32s(n_ints)?;
if let Some(ref mut mp) = model.obj[obj_ind as usize].mesh_param {
mp.cap_skip_zlist = skip_list;
} else {
}
}
ID_SLAN => {
_ = reader.read_u32()?; let slan = read_slicer_angles(reader)?;
model.slicer_angles.push(slan);
}
ID_OGRP => {
let size = reader.read_u32()?;
reader.skip(size)?;
}
ID_IEOF => {
break;
}
_ => {
let size = match reader.read_u32() {
Ok(s) => s,
Err(_) => break,
};
reader.skip(size)?;
}
}
}
if model.objsize > 0 {
if model.cindex.object >= model.objsize {
model.cindex.object = model.objsize - 1;
}
} else {
model.cindex.object = -1;
}
if model.cindex.object < 0 {
model.cindex.contour = -1;
model.cindex.point = -1;
}
Ok(model)
}
fn read_object<R: ReadImod>(reader: &mut R) -> ImodResult<Iobj> {
let mut obj = Iobj::default();
obj.name = reader.read_padded_string(IOBJ_STRSIZE)?;
obj.extra = reader.read_i32s(IOBJ_EXSIZE)?;
obj.contsize = reader.read_i32()?;
obj.flags = reader.read_u32()?;
obj.axis = reader.read_i32()?;
obj.drawmode = reader.read_i32()?;
obj.red = reader.read_f32()?;
obj.green = reader.read_f32()?;
obj.blue = reader.read_f32()?;
obj.pdrawsize = reader.read_i32()?;
obj.symbol = reader.read_u8()?;
obj.symsize = reader.read_u8()?;
if obj.symsize == 0 {
obj.symsize = 3;
}
obj.linewidth2 = reader.read_u8()?;
if obj.linewidth2 == 0 {
obj.linewidth2 = 1;
}
obj.linewidth = reader.read_u8()?;
obj.linesty = reader.read_u8()?;
obj.symflags = reader.read_u8()?;
obj.sympad = reader.read_u8()?;
obj.trans = reader.read_u8()?;
obj.meshsize = reader.read_i32()?;
obj.surfsize = reader.read_i32()?;
Ok(obj)
}
fn read_contour<R: ReadImod>(reader: &mut R) -> ImodResult<Icont> {
let mut cont = Icont::default();
cont.psize = reader.read_i32()?;
cont.flags = reader.read_u32()?;
cont.time = reader.read_i32()?;
cont.surf = reader.read_i32()?;
if cont.psize > 0 {
let coords = reader.read_f32s((cont.psize * 3) as usize)?;
cont.pts = coords
.chunks_exact(3)
.map(|c| Ipoint {
x: c[0],
y: c[1],
z: c[2],
})
.collect();
}
Ok(cont)
}
fn read_mesh<R: ReadImod>(reader: &mut R) -> ImodResult<Imesh> {
let mut mesh = Imesh::default();
mesh.vsize = reader.read_i32()?;
mesh.lsize = reader.read_i32()?;
mesh.flag = reader.read_u32()?;
mesh.time = reader.read_u16()?;
mesh.surf = reader.read_u16()?;
if mesh.vsize > 0 {
let coords = reader.read_f32s((mesh.vsize * 3) as usize)?;
mesh.vert = coords
.chunks_exact(3)
.map(|c| Ipoint {
x: c[0],
y: c[1],
z: c[2],
})
.collect();
}
if mesh.lsize > 0 {
mesh.list = reader.read_i32s(mesh.lsize as usize)?;
}
Ok(mesh)
}
fn read_label<R: ReadImod>(reader: &mut R) -> ImodResult<Ilabel> {
let _chunk_size = reader.read_u32()?;
let nl = reader.read_i32()?; let name_len = reader.read_i32()? as usize;
let name = if name_len > 0 {
let bytes = reader.read_bytes(name_len)?;
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
if end > 0 {
Some(String::from_utf8_lossy(&bytes[..end]).to_string())
} else {
None
}
} else {
None
};
let mut items = Vec::with_capacity(nl.max(0) as usize);
for _ in 0..nl {
let index = reader.read_i32()?;
let item_len = reader.read_i32()? as usize;
let bytes = reader.read_bytes(item_len)?;
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
let name_str = if end > 0 {
String::from_utf8_lossy(&bytes[..end]).to_string()
} else {
String::new()
};
items.push(IlabelItem {
name: name_str,
index,
});
}
Ok(Ilabel {
name,
items,
})
}
fn read_clip_planes<R: ReadImod>(reader: &mut R, flags: u32) -> ImodResult<IclipPlanes> {
let mut clips = IclipPlanes::default();
let _size = reader.read_i32()?;
clips.count = reader.read_u8()? as i32;
let flag_bytes = reader.read_bytes(3)?;
clips.flags = u32::from_le_bytes([flag_bytes[0], flag_bytes[1], flag_bytes[2], 0]);
if clips.count > 0 && clips.count <= IMOD_CLIPSIZE as i32 {
let n = clips.count as usize;
let norm_data = reader.read_f32s(n * 3)?;
let pt_data = reader.read_f32s(n * 3)?;
clips.normal = norm_data
.chunks_exact(3)
.map(|c| Ipoint {
x: c[0],
y: c[1],
z: c[2],
})
.collect();
clips.point = pt_data
.chunks_exact(3)
.map(|c| Ipoint {
x: c[0],
y: c[1],
z: c[2],
})
.collect();
}
if clips.count == 0
&& (clips.point[0].x != 0.0
|| clips.point[0].y != 0.0
|| clips.point[0].z != 0.0
|| clips.normal[0].x != 0.0
|| clips.normal[0].y != 0.0
|| clips.normal[0].z != -1.0)
{
clips.flags &= 0xFE;
clips.count = 1;
} else if clips.count != 0 && (flags & IMODF_MULTIPLE_CLIP) == 0 {
clips.flags |= 1;
clips.count = 1;
}
Ok(clips)
}
fn read_material<R: ReadImod>(reader: &mut R, obj: &mut Iobj, flags: u32) -> ImodResult<()> {
if flags & IMODF_MAT1_IS_BYTES != 0 {
obj.ambient = reader.read_u8()?;
obj.diffuse = reader.read_u8()?;
obj.specular = reader.read_u8()?;
obj.shininess = reader.read_u8()?;
obj.fillred = reader.read_u8()?;
obj.fillgreen = reader.read_u8()?;
obj.fillblue = reader.read_u8()?;
obj.quality = reader.read_u8()?;
obj.mat2 = reader.read_i32()?;
obj.valblack = reader.read_u8()?;
obj.valwhite = reader.read_u8()?;
obj.matflags2 = reader.read_u8()? as i32;
obj.mesh_thickness = reader.read_u8()?;
} else {
obj.ambient = reader.read_u8()?;
obj.diffuse = reader.read_u8()?;
obj.specular = reader.read_u8()?;
obj.shininess = reader.read_u8()?;
let fillred = reader.read_i32()?;
obj.fillred = fillred as u8;
let fillgreen = reader.read_i32()?;
obj.fillgreen = fillgreen as u8;
let fillblue = reader.read_i32()?;
obj.fillblue = fillblue as u8;
}
if (flags & IMODF_HAS_MESH_THICK) == 0 {
obj.mesh_thickness = 0;
}
Ok(())
}
fn read_mesh_params<R: ReadImod>(reader: &mut R) -> ImodResult<ImeshParams> {
let mut mp = ImeshParams::default();
let flags = reader.read_i32s(9)?;
mp.flags.copy_from_slice(&flags);
let overlap = reader.read_f32s(10)?;
mp.overlap.copy_from_slice(&overlap);
Ok(mp)
}
fn read_slicer_angles<R: ReadImod>(reader: &mut R) -> ImodResult<SlicerAngles> {
let mut slan = SlicerAngles::default();
slan.time = reader.read_i32()?;
let floats = reader.read_f32s(6)?;
slan.angles = [floats[0], floats[1], floats[2]];
slan.center = Ipoint {
x: floats[3],
y: floats[4],
z: floats[5],
};
slan.label = reader.read_padded_string(ANGLE_STRSIZE)?;
Ok(slan)
}
fn read_view<R: ReadImod>(reader: &mut R, model: &mut Imod) -> ImodResult<()> {
let lbuf = reader.read_i32()?;
if lbuf == 4 {
model.cview = reader.read_i32()?;
if model.view.is_empty() {
model.view.push(Iview::default());
model.viewsize = 1;
}
return Ok(());
}
let mut view = Iview::default();
let mut bytes_read: i32 = 0;
if lbuf >= 56 {
let core = reader.read_f32s(14)?;
view.fovy = core[0];
view.rad = core[1];
view.aspect = core[2];
view.cnear = core[3];
view.cfar = core[4];
view.rot = Ipoint { x: core[5], y: core[6], z: core[7] };
view.trans = Ipoint { x: core[8], y: core[9], z: core[10] };
view.scale = Ipoint { x: core[11], y: core[12], z: core[13] };
bytes_read += 56;
}
if lbuf >= 156 {
let mat = reader.read_f32s(16)?;
view.mat.copy_from_slice(&mat);
view.world = reader.read_u32()?;
view.label = reader.read_padded_string(VIEW_STRSIZE)?;
bytes_read += 100;
}
if lbuf >= 176 {
let extras = reader.read_f32s(5)?;
view.dcstart = extras[0];
view.dcend = extras[1];
view.lightx = extras[2];
view.lighty = extras[3];
view.plax = extras[4];
bytes_read += 20;
}
if lbuf >= 180 {
let objvsize = reader.read_i32()?;
let bytes_objv = reader.read_i32()?;
bytes_read += 8;
if objvsize > 0 {
let bytes_missing = BYTES_PER_OBJVIEW - (if objvsize > 0 { bytes_objv / objvsize } else { 0 });
for _ in 0..objvsize {
let _flags = reader.read_u32()?;
let _red = reader.read_f32()?;
let _green = reader.read_f32()?;
let _blue = reader.read_f32()?;
let _pdrawsize = reader.read_i32()?;
let _linewidth = reader.read_u8()?;
let _linesty = reader.read_u8()?;
let _trans = reader.read_u8()?;
let _clips_count = reader.read_u8()?;
let _clips_flags = reader.read_u8()?;
let _clips_trans = reader.read_u8()?;
let _clips_plane = reader.read_u8()?;
let _clips_normal = reader.read_f32s(3)?;
let _clips_point = reader.read_f32s(3)?;
let _ambient = reader.read_u8()?;
let _diffuse = reader.read_u8()?;
let _specular = reader.read_u8()?;
let _shininess = reader.read_u8()?;
let _fillred = reader.read_u8()?;
let _fillgreen = reader.read_u8()?;
let _fillblue = reader.read_u8()?;
let _quality = reader.read_u8()?;
let _mat2 = reader.read_i32()?;
let _valblack = reader.read_u8()?;
let _valwhite = reader.read_u8()?;
let _matflags2 = reader.read_u8()?;
let _mat3b3 = reader.read_u8()?;
if bytes_missing <= 0 {
for _ in 1..IMOD_CLIPSIZE {
let _nx = reader.read_f32()?; let _ny = reader.read_f32()?; let _nz = reader.read_f32()?;
let _px = reader.read_f32()?; let _py = reader.read_f32()?; let _pz = reader.read_f32()?;
}
}
if bytes_missing < 0 {
reader.skip((-bytes_missing) as u32)?;
}
bytes_read += 67;
}
}
}
let remaining = lbuf - bytes_read;
if remaining > 0 {
reader.skip(remaining as u32)?;
}
model.view.push(view);
model.viewsize = model.view.len() as i32;
Ok(())
}
fn read_view_clip<R: ReadImod>(reader: &mut R, model: &mut Imod) -> ImodResult<()> {
let _size = reader.read_i32()?;
let count = reader.read_i32()?;
let flags = reader.read_u32()?;
let trans = reader.read_u32()?;
let plane = reader.read_u32()?;
if !model.view.is_empty() {
let last_idx = model.view.len() - 1;
let view = &mut model.view[last_idx];
view.clips.count = count;
view.clips.flags = flags;
view.clips.trans = trans;
view.clips.plane = plane;
if count > 0 {
let n = count.min(IMOD_CLIPSIZE as i32) as usize;
let norm_data = reader.read_f32s(n * 3)?;
let pt_data = reader.read_f32s(n * 3)?;
for i in 0..n {
view.clips.normal[i] = Ipoint {
x: norm_data[i * 3],
y: norm_data[i * 3 + 1],
z: norm_data[i * 3 + 2],
};
view.clips.point[i] = Ipoint {
x: pt_data[i * 3],
y: pt_data[i * 3 + 1],
z: pt_data[i * 3 + 2],
};
}
}
}
Ok(())
}
fn read_ref_image<R: ReadImod>(reader: &mut R) -> ImodResult<IrefImage> {
let _size = reader.read_i32()?;
let mut ref_img = IrefImage::default();
ref_img.cscale.x = reader.read_f32()?;
ref_img.cscale.y = reader.read_f32()?;
ref_img.cscale.z = reader.read_f32()?;
ref_img.ctrans.x = reader.read_f32()?;
ref_img.ctrans.y = reader.read_f32()?;
ref_img.ctrans.z = reader.read_f32()?;
ref_img.crot.x = reader.read_f32()?;
ref_img.crot.y = reader.read_f32()?;
ref_img.crot.z = reader.read_f32()?;
ref_img.otrans.x = reader.read_f32()?;
ref_img.otrans.y = reader.read_f32()?;
ref_img.otrans.z = reader.read_f32()?;
ref_img.orot.x = reader.read_f32()?;
ref_img.orot.y = reader.read_f32()?;
ref_img.orot.z = reader.read_f32()?;
Ok(ref_img)
}
fn read_store<R: ReadImod>(reader: &mut R) -> ImodResult<Istore> {
let _size = reader.read_u32()?;
let mut store = Istore::default();
let n_items_direct = reader.read_i32()?;
if n_items_direct > 0 {
for _ in 0..n_items_direct {
let flags = reader.read_u32()?;
let index = reader.read_i32()?;
let value_f = reader.read_f32()?;
let value_i = reader.read_i32()?;
store.items.push(IstoreItem {
flags,
index,
value_f,
value_i,
});
}
}
Ok(store)
}