]> Dogcows Code - chaz/yoink/blob - src/moof/mesh.cc
testing improved runloop scheduling
[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 }
360 while (stream);
361 }
362
363 //unsigned mesh::read_vertex_line(std::istream& stream)
364 //{
365 //unsigned vert;
366 //stream >> vert;
367 //vector2 uv = read_pair(stream);
368 //if (vert < face.triangles_uv.size())
369 //{
370 //if (uv != face.triangles_uv[vert])
371 //{
372 //obj->verts.push_back(obj->verts[vert]);
373 //face.triangles_uv.resize(obj->verts.size());
374 //vert = obj->verts.size() - 1;
375 //}
376 //}
377 //else face.triangles_uv.resize(vert + 1);
378 //face.triangles_uv[vert] = uv;
379 //face.triangles.push_back(vert);
380 //}
381
382
383
384 mesh::mesh(const std::string& path)
385 {
386 std::ifstream file(path.c_str(), std::ifstream::in |
387 std::ifstream::binary);
388 if (!file) throw std::runtime_error("cannot find mesh file");
389
390 // if we can read the header, the file isn't compressed
391 char magic[5];
392 file.get(magic, sizeof(magic));
393 if (strncmp(magic, "AC3D", 4) == 0)
394 {
395 log_info("text mesh detected");
396 file.seekg(std::ios::beg);
397
398 import(file);
399 }
400 else
401 {
402 log_info("compressed mesh detected");
403 file.seekg(std::ios::beg);
404
405 std::stringstream stream;
406 char in[ZLIB_BUF_SIZE];
407 char out[ZLIB_BUF_SIZE];
408
409 z_stream zstream;
410
411 zstream.zalloc = Z_NULL;
412 zstream.zfree = Z_NULL;
413 zstream.opaque = Z_NULL;
414 zstream.avail_in = 0;
415 zstream.next_in = Z_NULL;
416
417 int result = inflateInit2(&zstream, 32+MAX_WBITS);
418 if (result != Z_OK) throw std::runtime_error("zlib init error");
419
420 do
421 {
422 file.read(in, sizeof(in));
423 zstream.next_in = (Bytef*)in;
424 zstream.avail_in = file.gcount();
425
426 if (zstream.avail_in == 0) break;
427
428 do
429 {
430 zstream.next_out = (Bytef*)out;
431 zstream.avail_out = sizeof(out);
432
433 result = inflate(&zstream, Z_NO_FLUSH);
434 switch (result)
435 {
436 case Z_NEED_DICT:
437 case Z_DATA_ERROR:
438 case Z_MEM_ERROR:
439 inflateEnd(&zstream);
440 throw std::runtime_error("zlib inflate error");
441 case Z_STREAM_ERROR:
442 throw std::runtime_error("zlib stream error");
443 }
444
445 int inflated = sizeof(out) - zstream.avail_out;
446 stream.write(out, inflated);
447 }
448 while (zstream.avail_out == 0);
449 }
450 while(result != Z_STREAM_END);
451
452 inflateEnd(&zstream);
453
454 import(stream);
455 }
456 }
457
458
459 void mesh::draw(scalar alpha) const
460 {
461 glEnableClientState(GL_VERTEX_ARRAY);
462
463 std::vector<object_ptr>::const_iterator it;
464 for (it = objects_.begin(); it != objects_.end(); ++it)
465 {
466 (*it)->draw(alpha);
467 }
468
469 // TODO: disable vertex array?
470 }
471
472
473 void mesh::set_material(int index) const
474 {
475 set_material(materials_[index]);
476 }
477
478 void mesh::set_material(const material& material) const
479 {
480 glColor(material.diffuse);
481 glMaterial(GL_FRONT, GL_DIFFUSE, material.diffuse);
482 glMaterial(GL_FRONT, GL_AMBIENT, material.ambient);
483 glMaterial(GL_FRONT, GL_SPECULAR, material.specular);
484 glMaterial(GL_FRONT, GL_EMISSION, material.emissive);
485 glMaterial(GL_FRONT, GL_SHININESS, material.shininess);
486 }
487
488
489 void mesh::object::draw(scalar alpha, bool recurse) const
490 {
491 glVertexPointer(verts);
492
493 if (texture)
494 {
495 texture->bind();
496 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
497 }
498 else
499 {
500 image::reset_binding();
501 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
502 }
503
504 for (size_t i = 0; i < faces.size(); ++i)
505 {
506 const material_group& face = faces[i];
507 if (face.triangles.size() == 0) continue;
508
509 mesh.set_material(i);
510
511 if (texture) glTexCoordPointer(face.triangles_uv);
512 glDrawElements(GL_TRIANGLES, face.triangles);
513 }
514
515 if (recurse)
516 {
517 std::vector<object_ptr>::const_iterator jt;
518 for (jt = kids.begin(); jt != kids.end(); ++jt)
519 {
520 (*jt)->draw(alpha);
521 }
522 }
523 }
524
525
526 //class mesh_resource_loader
527 //{
528 //public:
529
530 //mesh_resource_loader()
531 //{
532 //resource::register_type<mesh>("ac", "models");
533 //}
534
535 //~mesh_resource_loader()
536 //{
537 //resource::unregister_type("ac");
538 //}
539 //};
540
541 //static mesh_resource_loader loader;
542
543
544 } // namespace moof
545
This page took 0.053341 seconds and 4 git commands to generate.