gdritter repos utmyen / 7fceec0
Moved some code to the thermidor library Getty Ritter 7 years ago
4 changed file(s) with 7 addition(s) and 182 deletion(s). Collapse all Expand all
66 [dependencies]
77 image = "*"
88 glium = "*"
9 therm_util = { path = "../thermidor/therm_util" }
10 therm_model = { path = "../thermidor/therm_model" }
44 use glium::glutin::{Event,WindowBuilder};
55 use glium::texture::{RawImage2d,Texture2d};
66
7 use model::Model;
7 use therm_model::model::Model;
88
99 const VERTEX_SHADER: &'static str = include_str!("../data/shaders/vertex.glsl");
1010
22 #[macro_use]
33 extern crate glium;
44 extern crate image;
5 extern crate therm_model;
6 extern crate therm_util;
57
6 mod model;
78 mod graphics;
89
10
911 use glium::texture::{RawImage2d};
12 use therm_model::model;
1013
1114 fn sample() -> model::Model {
1215 let file = std::env::args().nth(1)
+0
-180
src/model.rs less more
1 extern crate glium;
2 extern crate image;
3
4 use glium::{VertexBuffer, IndexBuffer};
5 use glium::texture::Texture2d;
6 use std::vec;
7
8 #[derive(Debug, Copy, Clone)]
9 pub struct V3D {
10 pub pos: [f32; 3],
11 pub nrm: [f32; 3],
12 pub tex: [f32; 2],
13 }
14
15 implement_vertex!(V3D, pos, nrm, tex);
16
17 #[derive(Debug, Clone)]
18 pub struct Model {
19 pub points: Vec<V3D>,
20 pub tris: Vec<u16>,
21 pub texture: Option<Vec<u8>>,
22 }
23
24 impl Model {
25 pub fn load_from_file(path: &str) -> Result<Model, String> {
26 use std::fs::File;
27 use std::io::Read;
28 let mut f = match File::open(path) {
29 Ok(f) => f,
30 Err(_) => return Err("Unable to open file".to_string()),
31 };
32 let mut buf = Vec::new();
33 let _ = f.read_to_end(&mut buf);
34 (Reader { bytes: buf.into_iter() }).read_model()
35 }
36
37 pub fn get_vbuf(&self, display: &glium::Display) -> VertexBuffer<V3D> {
38 VertexBuffer::new(display, self.points.as_slice()).unwrap()
39 }
40
41 pub fn get_ibuf(&self, display: &glium::Display) -> IndexBuffer<u16> {
42 IndexBuffer::new(
43 display,
44 glium::index::PrimitiveType::TrianglesList,
45 &self.tris).unwrap()
46 }
47
48 pub fn get_tex(&self, display: &glium::Display) -> Option<Texture2d> {
49 use std::io::Cursor;
50 use glium::texture::RawImage2d;
51 if let Some(ref tex) = self.texture {
52 let img = image::load(Cursor::new(tex.clone()),
53 image::PNG).unwrap().to_rgba();
54 let dims = img.dimensions();
55 let img = RawImage2d::from_raw_rgba_reversed(img.into_raw(),
56 dims);
57 Some(Texture2d::new(display, img).unwrap())
58 } else {
59 None
60 }
61 }
62 }
63
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>,
68 }
69
70 #[test]
71 fn reader_tests() {
72 assert!(Reader::from_slice(&[0x00]).read_twip() == Ok(-32.0));
73 assert!(Reader::from_slice(&[0x00]).read_prefix_int() == Ok(0x00));
74 assert!(Reader::from_slice(&[0x7f]).read_prefix_int() == Ok(0x7f));
75 assert!(Reader::from_slice(&[0x80,0xff]).read_prefix_int() == Ok(0xff));
76 }
77
78 impl Reader {
79 fn from_slice(lst: &[u8]) -> Self {
80 Reader { bytes: lst.to_vec().into_iter() }
81 }
82 /// This gets the next byte, or fails if it's out of input.
83 fn next(&mut self) -> Result<u8, String> {
84 Ok(try!(self.bytes.next().ok_or("out of input")))
85 }
86
87 /// This reads a one-byte or two-byte float in the rough range of
88 /// (192 .. -128). We're going to treat all models as if they're
89 /// supposed to be centered in a 64x64x64 square, so this gives
90 /// us 128 units on either side of the central square, as well.
91 fn read_twip(&mut self) -> Result<f32, String> {
92 let b1 = try!(self.next());
93 if (b1 & 0x80) != 0 {
94 let b2 = try!(self.next());
95 let val = ((b1 as u16 & 0x7f) << 8) | b2 as u16;
96 Ok((val as f32 / 102.0) - 128.0)
97 } else {
98 Ok((b1 as f32) - 32.0)
99 }
100 }
101
102 /// This reads a single byte and treats it as a ratio.
103 fn read_ratio(&mut self) -> Result<f32, String> {
104 let b = try!(self.next());
105 Ok(b as f32 / 255.0)
106 }
107
108 /// This reads a 64-bit int with a packed PrefixInteger representation.
109 /// The shorter the int, the shorter the representation.
110 fn read_prefix_int(&mut self) -> Result<u64, String> {
111 fn match_bits(n: u8, mask: u8) -> bool {
112 n & mask == mask
113 }
114 let b = try!(self.next());
115 if match_bits(b, 0xff) { self.continue_prefix_int(8, 0) }
116 else if match_bits(b, 0xfe) { self.continue_prefix_int(7, 0) }
117 else if match_bits(b, 0xfc) { self.continue_prefix_int(6, b & 0x01) }
118 else if match_bits(b, 0xf8) { self.continue_prefix_int(5, b & 0x03) }
119 else if match_bits(b, 0xf0) { self.continue_prefix_int(4, b & 0x07) }
120 else if match_bits(b, 0xe0) { self.continue_prefix_int(3, b & 0x0f) }
121 else if match_bits(b, 0xc0) { self.continue_prefix_int(2, b & 0x1f) }
122 else if match_bits(b, 0x80) { self.continue_prefix_int(1, b & 0x3f) }
123 else { self.continue_prefix_int(0, b) }
124 }
125
126 /// This is a helper function for parsing prefix ints, too.
127 fn continue_prefix_int(&mut self, mut left: u8, upper: u8) -> Result<u64, String> {
128 let mut ret = upper as u64;
129 while left > 0 {
130 left -= 1;
131 ret = (ret << 8) | try!(self.next()) as u64;
132 }
133 Ok(ret)
134 }
135
136 /// This reads a single V3D: three twips for the x/y/z, three twips
137 /// for the normal, and two ratios for the uv coords.
138 fn read_v3d(&mut self) -> Result<V3D, String> {
139 Ok(V3D { pos: [ try!(self.read_twip()) * 0.1,
140 try!(self.read_twip()) * 0.1,
141 try!(self.read_twip()) * 0.1],
142 nrm: [ try!(self.read_twip()),
143 try!(self.read_twip()),
144 try!(self.read_twip()) ],
145 tex: [ try!(self.read_ratio()),
146 try!(self.read_ratio()) ],
147 })
148 }
149
150 /// This reads a PrefixInteger to find out how many other things to read,
151 /// and then reads that number of things.
152 fn read_several<F, R>(&mut self, reader: F) -> Result<Vec<R>, String>
153 where F: Fn(&mut Reader) -> Result<R, String>
154 {
155 let ct = try!(self.read_prefix_int());
156 let mut ret = Vec::with_capacity(ct as usize);
157 for _ in 0..ct {
158 ret.push(try!(reader(self)))
159 }
160 Ok(ret)
161 }
162
163 /// This reads a model: right now, a list of tris, followed by a list of
164 /// v3ds. This could be very small: a V3D could be as small as eight bytes,
165 /// an index as small as one, and each size tag can be one byte. A simple
166 /// model that contains only a triangle is going to be
167 /// (1 + 3*8) + (1 + 3) == 28 bytes
168 /// in contrast to the older UTM models, where an equivalent would be 50
169 /// bytes per V3D and a two-byte overhead per list, as well as miscellaneous
170 /// structure data, so
171 /// (2 + 3*50) + (2 + 3 * 3) + 13 == 176 bytes
172 /// That's a pretty good savings!
173 fn read_model(&mut self) -> Result<Model, String> {
174 Ok(Model {
175 tris: try!(self.read_several(|r| r.read_prefix_int().map(|x| x as u16))),
176 points: try!(self.read_several(|r| r.read_v3d())),
177 texture: None,
178 })
179 }
180 }