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