gdritter repos utmyen / e780058
Working on newer, better model format Getty Ritter 7 years ago
1 changed file(s) with 107 addition(s) and 29 deletion(s). Collapse all Expand all
11 extern crate glium;
22 extern crate image;
33
4 use bencode::Bencode;
54 use glium::{VertexBuffer, IndexBuffer};
65 use glium::texture::Texture2d;
6 use std::vec;
77
88 #[derive(Debug, Copy, Clone)]
99 pub struct V3D {
3131 };
3232 let mut buf = Vec::new();
3333 let _ = f.read_to_end(&mut buf);
34 Model::load(&buf)
35 }
36
37 pub fn load(is: &[u8]) -> Result<Model, String> {
38 let bs = try!(Bencode::parse(is));
39 let tex = match bs.get_field("tex") {
40 Ok(t) => Some(try!(t.as_bytes())),
41 Err(_) => None,
42 };
43 Ok(Model {
44 points: try!(try!(bs.get_field("pts")).map(load_v3d)),
45 tris: try!(try!(bs.get_field("tris")).map(|v| v.as_u16())),
46 texture: tex,
47 })
34 (Reader { bytes: buf.into_iter() }).read_model()
4835 }
4936
5037 pub fn get_vbuf(&self, display: &glium::Display) -> VertexBuffer<V3D> {
7461 }
7562 }
7663
77 fn load_v3d(bs: &Bencode) -> Result<V3D, String> {
78 Ok(V3D {
79 pos: [ try!(try!(bs.get_idx(0)).as_float()) * 0.5,
80 try!(try!(bs.get_idx(1)).as_float()) * 0.5,
81 try!(try!(bs.get_idx(2)).as_float()) * 0.5,
82 ],
83 nrm: [ try!(try!(bs.get_idx(5)).as_float()),
84 try!(try!(bs.get_idx(6)).as_float()),
85 try!(try!(bs.get_idx(7)).as_float()),
86 ],
87 tex: [ try!(try!(bs.get_idx(3)).as_float()),
88 try!(try!(bs.get_idx(4)).as_float()),
89 ]
90 })
64 /// A `Reader` is just a tiny wrapper over a mutable byte iterator, so we
65 /// can parse things more easily.
66 struct Reader {
67 pub bytes: vec::IntoIter<u8>,
9168 }
69
70 impl Reader {
71 /// This gets the next byte, or fails if it's out of input.
72 fn next(&mut self) -> Result<u8, String> {
73 Ok(try!(self.bytes.next().ok_or("out of input")))
74 }
75
76 /// This reads a one-byte or two-byte float in the rough range of
77 /// (192 .. -128). We're going to treat all models as if they're
78 /// supposed to be centered in a 64x64x64 square, so this gives
79 /// us 128 units on either side of the central square, as well.
80 fn read_twip(&mut self) -> Result<f32, String> {
81 let b1 = try!(self.next());
82 if (b1 & 0x80) != 0 {
83 let b2 = try!(self.next());
84 let val = ((b2 as u16 & 0x7f) << 8) | b2 as u16;
85 Ok((val as f32 / 102.0) - 128.0)
86 } else {
87 Ok((b1 as f32) - 32.0)
88 }
89 }
90
91 /// This reads a single byte and treats it as a ratio.
92 fn read_ratio(&mut self) -> Result<f32, String> {
93 let b = try!(self.next());
94 Ok(b as f32 / 255.0)
95 }
96
97 /// This reads a 64-bit int with a packed PrefixInteger representation.
98 /// The shorter the int, the shorter the representation.
99 fn read_prefix_int(&mut self) -> Result<u64, String> {
100 fn match_bits(n: u8, mask: u8) -> bool {
101 n & mask == mask
102 }
103 let b = try!(self.next());
104 if match_bits(b, 0xff) { self.continue_prefix_int(8, 0) }
105 else if match_bits(b, 0xfe) { self.continue_prefix_int(7, 0) }
106 else if match_bits(b, 0xfc) { self.continue_prefix_int(6, b & 0x01) }
107 else if match_bits(b, 0xf8) { self.continue_prefix_int(5, b & 0x03) }
108 else if match_bits(b, 0xf0) { self.continue_prefix_int(4, b & 0x07) }
109 else if match_bits(b, 0xe0) { self.continue_prefix_int(3, b & 0x0f) }
110 else if match_bits(b, 0xc0) { self.continue_prefix_int(2, b & 0x1f) }
111 else if match_bits(b, 0x80) { self.continue_prefix_int(1, b & 0x3f) }
112 else { self.continue_prefix_int(0, b) }
113 }
114
115 /// This is a helper function for parsing prefix ints, too.
116 fn continue_prefix_int(&mut self, mut left: u8, upper: u8) -> Result<u64, String> {
117 let mut ret = upper as u64;
118 while left > 0 {
119 left -= 0;
120 ret = (ret << 8) | try!(self.next()) as u64;
121 }
122 Ok(ret)
123 }
124
125 /// This reads a single V3D: three twips for the x/y/z, three twips
126 /// for the normal, and two ratios for the uv coords.
127 fn read_v3d(&mut self) -> Result<V3D, String> {
128 Ok(V3D { pos: [ try!(self.read_twip()),
129 try!(self.read_twip()),
130 try!(self.read_twip()) ],
131 nrm: [ try!(self.read_twip()),
132 try!(self.read_twip()),
133 try!(self.read_twip()) ],
134 tex: [ try!(self.read_ratio()),
135 try!(self.read_ratio()) ],
136 })
137 }
138
139 /// This reads a PrefixInteger to find out how many other things to read,
140 /// and then reads that number of things.
141 fn read_several<F, R>(&mut self, reader: F) -> Result<Vec<R>, String>
142 where F: Fn(&mut Reader) -> Result<R, String>
143 {
144 let ct = try!(self.read_prefix_int());
145 let mut ret = Vec::with_capacity(ct as usize);
146 for i in 0..ct {
147 ret[i as usize] = try!(reader(self))
148 }
149 Ok(ret)
150 }
151
152 /// This reads a model: right now, a list of tris, followed by a list of
153 /// v3ds. This could be very small: a V3D could be as small as eight bytes,
154 /// an index as small as one, and each size tag can be one byte. A simple
155 /// model that contains only a triangle is going to be
156 /// (1 + 3*8) + (1 + 3) == 28 bytes
157 /// in contrast to the older UTM models, where an equivalent would be 50
158 /// bytes per V3D and a two-byte overhead per list, as well as miscellaneous
159 /// structure data, so
160 /// (2 + 3*50) + (2 + 3 * 3) + 13 == 176 bytes
161 /// That's a pretty good savings!
162 fn read_model(&mut self) -> Result<Model, String> {
163 Ok(Model {
164 tris: try!(self.read_several(|r| r.read_prefix_int().map(|x| x as u16))),
165 points: try!(self.read_several(|r| r.read_v3d())),
166 texture: None,
167 })
168 }
169 }