32550f7fcfb3361aff55ea7e2748c0c2c62531df
[chaz/yoink] / src / moof / mesh.cc
1
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
4 *
5 * Distributable under the terms and conditions of the 2-clause BSD license;
6 * see the file COPYING for a complete text of the license.
7 *
8 *****************************************************************************/
9
10 #include <cstring>
11 #include <fstream>
12 #include <sstream>
13 #include <stack>
14 #include <stdexcept>
15
16 #include <boost/algorithm/string/trim.hpp>
17 #include <zlib.h>
18
19 #include "debug.hh"
20 #include "log.hh"
21 #include "mesh.hh"
22 #include "opengl.hh"
23
24 // TODO: this file needs to be cleaned up
25
26 #define AC3D_FORMAT_VERSION 0x0b
27 #define ZLIB_BUF_SIZE 262114
28
29
30 namespace moof {
31
32
33 MOOF_REGISTER_RESOURCE(mesh, ac, models);
34
35 static std::string read_string(std::istream& stream)
36 {
37 std::string str;
38 char atom;
39
40 do stream.get(atom);
41 while (stream && std::isspace(atom));
42
43 if (atom == '"')
44 {
45 do {
46 stream.get(atom);
47 if (atom == '"') break;
48 str += atom;
49 }
50 while (stream);
51 }
52 else
53 {
54 do {
55 stream.get(atom);
56 if (std::isspace(atom)) break;
57 str += atom;
58 }
59 while (stream);
60 }
61
62 return str;
63 }
64
65 static int read_hex(std::istream& stream)
66 {
67 int hex;
68 std::ios::fmtflags flags = stream.flags();
69 stream.setf(std::ios::hex, std::ios::basefield);
70 stream >> hex;
71 stream.flags(flags);
72 return hex;
73 }
74
75 static vector2 read_pair(std::istream& stream)
76 {
77 vector2 triplet;
78 stream >> triplet[0] >> triplet[1];
79 return triplet;
80 }
81
82 static vector3 read_triplet(std::istream& stream)
83 {
84 vector3 triplet;
85 stream >> triplet[0] >> triplet[1] >> triplet[2];
86 return triplet;
87 }
88
89 static vector4 read_color(std::istream& stream)
90 {
91 vector4 color;
92 stream >> color[0] >> color[1] >> color[2];
93 color[3] = SCALAR(1.0);
94 return color;
95 }
96
97 void mesh::import(std::istream& stream)
98 {
99 std::string atom;
100 object_ptr obj;
101 std::stack<int> kids;
102
103 // read and verify the AC3D header
104 {
105 char magic[5];
106 unsigned version = 0;
107
108 stream.get(magic, sizeof(magic));
109 if (!stream || strncmp(magic, "AC3D", 4) != 0)
110 {
111 throw std::runtime_error("invalid mesh header");
112 }
113
114 version = read_hex(stream);
115 if (version > AC3D_FORMAT_VERSION)
116 {
117 throw std::runtime_error("wrong mesh file format version");
118 }
119 }
120
121 while (stream)
122 {
123 stream >> atom;
124 if (!stream) break;
125
126 if (atom == "MATERIAL")
127 {
128 materials_.push_back(material(read_string(stream)));
129
130 stream >> atom;
131 materials_.back().diffuse = read_color(stream);
132 stream >> atom;
133 materials_.back().ambient = read_color(stream);
134 stream >> atom;
135 materials_.back().emissive = read_color(stream);
136 stream >> atom;
137 materials_.back().specular = read_color(stream);
138
139 stream >> atom >> materials_.back().shininess;
140 stream >> atom >> materials_.back().diffuse[3];
141 materials_.back().diffuse[3] = SCALAR(1.0) -
142 materials_.back().diffuse[3];
143 }
144 else if (atom == "OBJECT")
145 {
146 stream >> atom;
147 if (atom != "world" && atom != "group" && atom != "poly")
148 {
149 throw std::runtime_error("unexpected object type " + atom);
150 }
151
152 object_ptr newObj = object::alloc(*this);
153
154 if (obj)
155 {
156 obj->kids.push_back(newObj);
157 newObj->parent = obj;
158 }
159 else
160 {
161 objects_.push_back(newObj);
162 }
163
164 obj = newObj;
165 }
166 else if (atom == "name")
167 {
168 if (obj)
169 {
170 obj->name = read_string(stream);
171 object_ptr parent = obj->parent.lock();
172 if (parent) parent->kids_byname.insert(std::make_pair(obj->name, obj));
173 }
174 else throw std::runtime_error("unexpected atom: " + atom);
175 }
176 else if (atom == "data")
177 {
178 std::getline(stream, atom);
179 std::getline(stream, obj ? obj->data : atom);
180 }
181 else if (atom == "texture")
182 {
183 if (obj) obj->texture = resource::load(read_string(stream));
184 }
185 else if (atom == "texrep")
186 {
187 if (obj) obj->texrep = read_pair(stream);
188 else throw std::runtime_error("unexpected atom: " + atom);
189 }
190 else if (atom == "rot")
191 {
192 // TODO
193 std::getline(stream, atom);
194 }
195 else if (atom == "loc")
196 {
197 // TODO
198 std::getline(stream, atom);
199 }
200 else if (atom == "url")
201 {
202 if (obj) std::getline(stream, obj->url);
203 else throw std::runtime_error("unexpected atom: " + atom);
204 }
205 else if (atom == "numvert")
206 {
207 if (!obj) throw std::runtime_error("unexpected atom: " + atom);
208
209 int numvert = 0;
210 stream >> numvert;
211
212 for (int i = 0; i < numvert; ++i)
213 {
214 obj->verts.push_back(read_triplet(stream));
215 }
216 }
217 else if (atom == "numsurf")
218 {
219 if (!obj) throw std::runtime_error("unexpected atom: " + atom);
220
221 int numsurf = 0;
222 stream >> numsurf;
223
224 for (int i = 0; i < numsurf; ++i)
225 {
226 stream >> atom;
227 if (atom != "SURF") throw std::runtime_error("uh oh");
228
229 read_hex(stream);
230
231 int material = 0;
232 stream >> atom;
233 if (atom == "mat") stream >> material >> atom;
234
235 if (atom != "refs")
236 {
237 throw std::runtime_error("blaaaaaaaahhh!!");
238 }
239
240 int numrefs = 0;
241 stream >> numrefs;
242 ASSERT(numrefs >= 3);
243
244 if ((int)obj->faces.size() <= material)
245 {
246 obj->faces.resize(material + 1);
247 }
248 material_group& face = obj->faces[material];
249
250 unsigned vert;
251 stream >> vert;
252 vector2 uv = read_pair(stream);
253 if (vert < face.triangles_uv.size())
254 {
255 if (uv != face.triangles_uv[vert])
256 {
257 obj->verts.push_back(obj->verts[vert]);
258 face.triangles_uv.resize(obj->verts.size());
259 vert = obj->verts.size() - 1;
260 }
261 }
262 else face.triangles_uv.resize(vert + 1);
263 face.triangles_uv[vert] = uv;
264 face.triangles.push_back(vert);
265
266 unsigned first = vert;
267
268 stream >> vert;
269 uv = read_pair(stream);
270 if (vert < face.triangles_uv.size())
271 {
272 if (uv != face.triangles_uv[vert])
273 {
274 obj->verts.push_back(obj->verts[vert]);
275 face.triangles_uv.resize(obj->verts.size());
276 vert = obj->verts.size() - 1;
277 }
278 }
279 else face.triangles_uv.resize(vert + 1);
280 face.triangles_uv[vert] = uv;
281 face.triangles.push_back(vert);
282
283 stream >> vert;
284 uv = read_pair(stream);
285 if (vert < face.triangles_uv.size())
286 {
287 if (uv != face.triangles_uv[vert])
288 {
289 obj->verts.push_back(obj->verts[vert]);
290 face.triangles_uv.resize(obj->verts.size());
291 vert = obj->verts.size() - 1;
292 }
293 }
294 else face.triangles_uv.resize(vert + 1);
295 face.triangles_uv[vert] = uv;
296 face.triangles.push_back(vert);
297
298 unsigned last = vert;
299
300 for (int j = 3; j < numrefs; ++j)
301 {
302 face.triangles.push_back(first);
303 face.triangles.push_back(last);
304
305 stream >> vert;
306 uv = read_pair(stream);
307 if (vert < face.triangles_uv.size())
308 {
309 if (uv != face.triangles_uv[vert])
310 {
311 obj->verts.push_back(obj->verts[vert]);
312 face.triangles_uv.resize(obj->verts.size());
313 vert = obj->verts.size() - 1;
314 }
315 }
316 else face.triangles_uv.resize(vert + 1);
317 face.triangles_uv[vert] = uv;
318 face.triangles.push_back(vert);
319
320 last = face.triangles.back();
321 }
322 }
323 }
324 else if (atom == "kids")
325 {
326 //while (0 < kids.size())
327 //{
328 //if (--kids.top() <= 0)
329 //{
330 //ASSERT(obj && "should be an object");
331 //obj = obj->parent;
332 //kids.pop();
333 //}
334 //else break;
335 //}
336
337 int numkids = 0;
338 stream >> numkids;
339 if (0 < numkids) kids.push(numkids);
340 else
341 {
342 if (0 < kids.size() && 0 < --kids.top()) kids.pop();
343 obj = obj->parent.lock();
344 }
345 }
346 }
347 while (stream);
348 }
349
350 //unsigned mesh::read_vertex_line(std::istream& stream)
351 //{
352 //unsigned vert;
353 //stream >> vert;
354 //vector2 uv = read_pair(stream);
355 //if (vert < face.triangles_uv.size())
356 //{
357 //if (uv != face.triangles_uv[vert])
358 //{
359 //obj->verts.push_back(obj->verts[vert]);
360 //face.triangles_uv.resize(obj->verts.size());
361 //vert = obj->verts.size() - 1;
362 //}
363 //}
364 //else face.triangles_uv.resize(vert + 1);
365 //face.triangles_uv[vert] = uv;
366 //face.triangles.push_back(vert);
367 //}
368
369 mesh::mesh(const std::string& path)
370 {
371 std::ifstream file(path.c_str(), std::ifstream::in |
372 std::ifstream::binary);
373 if (!file) throw std::runtime_error("cannot find mesh file");
374
375 // if we can read the header, the file isn't compressed
376 char magic[5];
377 file.get(magic, sizeof(magic));
378 if (strncmp(magic, "AC3D", 4) == 0)
379 {
380 log_info("text mesh detected");
381 file.seekg(std::ios::beg);
382 import(file);
383 }
384 else
385 {
386 log_info("compressed mesh detected");
387 file.seekg(std::ios::beg);
388
389 std::stringstream stream;
390 char in[ZLIB_BUF_SIZE];
391 char out[ZLIB_BUF_SIZE];
392
393 z_stream zstream;
394
395 zstream.zalloc = Z_NULL;
396 zstream.zfree = Z_NULL;
397 zstream.opaque = Z_NULL;
398 zstream.avail_in = 0;
399 zstream.next_in = Z_NULL;
400
401 int result = inflateInit2(&zstream, 32+MAX_WBITS);
402 if (result != Z_OK)
403 throw std::runtime_error("zlib init error");
404
405 do {
406 file.read(in, sizeof(in));
407 zstream.next_in = (Bytef*)in;
408 zstream.avail_in = file.gcount();
409
410 if (zstream.avail_in == 0) break;
411
412 do {
413 zstream.next_out = (Bytef*)out;
414 zstream.avail_out = sizeof(out);
415
416 result = inflate(&zstream, Z_NO_FLUSH);
417 switch (result)
418 {
419 case Z_NEED_DICT:
420 case Z_DATA_ERROR:
421 case Z_MEM_ERROR:
422 inflateEnd(&zstream);
423 throw std::runtime_error("zlib inflate error");
424 case Z_STREAM_ERROR:
425 throw std::runtime_error("zlib stream error");
426 }
427
428 int inflated = sizeof(out) - zstream.avail_out;
429 stream.write(out, inflated);
430 }
431 while (zstream.avail_out == 0);
432 }
433 while(result != Z_STREAM_END);
434
435 inflateEnd(&zstream);
436 import(stream);
437 }
438 }
439
440 void mesh::draw(scalar alpha) const
441 {
442 glEnableClientState(GL_VERTEX_ARRAY);
443
444 std::vector<object_ptr>::const_iterator it;
445 for (it = objects_.begin(); it != objects_.end(); ++it)
446 {
447 (*it)->draw(alpha);
448 }
449
450 // TODO: disable vertex array?
451 }
452
453 void mesh::set_material(int index) const
454 {
455 set_material(materials_[index]);
456 }
457
458 void mesh::set_material(const material& material) const
459 {
460 glColor(material.diffuse);
461 glMaterial(GL_FRONT, GL_DIFFUSE, material.diffuse);
462 glMaterial(GL_FRONT, GL_AMBIENT, material.ambient);
463 glMaterial(GL_FRONT, GL_SPECULAR, material.specular);
464 glMaterial(GL_FRONT, GL_EMISSION, material.emissive);
465 glMaterial(GL_FRONT, GL_SHININESS, material.shininess);
466 }
467
468 void mesh::object::draw(scalar alpha, bool recurse) const
469 {
470 glVertexPointer(verts);
471
472 if (texture)
473 {
474 texture->bind();
475 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
476 }
477 else
478 {
479 image::reset_binding();
480 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
481 }
482
483 for (size_t i = 0; i < faces.size(); ++i)
484 {
485 const material_group& face = faces[i];
486 if (face.triangles.size() == 0) continue;
487
488 mesh.set_material(i);
489
490 if (texture) glTexCoordPointer(face.triangles_uv);
491 glDrawElements(GL_TRIANGLES, face.triangles);
492 }
493
494 if (recurse)
495 {
496 std::vector<object_ptr>::const_iterator jt;
497 for (jt = kids.begin(); jt != kids.end(); ++jt)
498 (*jt)->draw(alpha);
499 }
500 }
501
502 //class mesh_resource_loader
503 //{
504 //public:
505
506 //mesh_resource_loader()
507 //{
508 //resource::register_type<mesh>("ac", "models");
509 //}
510
511 //~mesh_resource_loader()
512 //{
513 //resource::unregister_type("ac");
514 //}
515 //};
516
517 //static mesh_resource_loader loader;
518
519
520 } // namespace moof
521
This page took 0.053654 seconds and 3 git commands to generate.