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