]>
Dogcows Code - chaz/yoink/blob - src/moof/mesh.cc
2 /*] Copyright (c) 2009-2011, Charles McGarvey [*****************************
3 **] All rights reserved.
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.
8 *****************************************************************************/
16 #include <boost/algorithm/string/trim.hpp>
19 #include "compression.hh"
25 #define AC3D_FORMAT_VERSION 0x0b
31 MOOF_REGISTER_RESOURCE(mesh
, ac
, models
);
32 MOOF_REGISTER_RESOURCE(mesh
, acz
, models
);
35 static std::string
read_string(std::istream
& stream
)
41 while (stream
&& std::isspace(atom
));
47 if (atom
== '"') break;
56 if (std::isspace(atom
)) break;
65 static int read_hex(std::istream
& stream
)
68 std::ios::fmtflags flags
= stream
.flags();
69 stream
.setf(std::ios::hex
, std::ios::basefield
);
75 static vector2
read_pair(std::istream
& stream
)
78 stream
>> pair
[0] >> pair
[1];
82 static vector3
read_triplet(std::istream
& stream
)
85 stream
>> triplet
[0] >> triplet
[1] >> triplet
[2];
89 static vector4
read_color(std::istream
& stream
)
92 stream
>> color
[0] >> color
[1] >> color
[2];
93 color
[3] = SCALAR(1.0);
98 static inline void throw_invalid_atom(const std::string
& atom
)
100 throw std::runtime_error("unexpected atom: " + atom
);
104 void mesh::load(std::istream
& stream
)
106 // read and verify the AC3D header
108 unsigned version
= 0;
110 stream
.get(magic
, sizeof(magic
));
111 if (!stream
|| strncmp(magic
, "AC3D", 4) != 0)
113 throw std::runtime_error("invalid mesh header");
116 version
= read_hex(stream
);
117 if (version
> AC3D_FORMAT_VERSION
)
119 throw std::runtime_error("wrong mesh file format version");
124 std::stack
<int> kids
;
131 if (atom
== "OBJECT")
133 obj
= load_object(stream
, obj
);
135 else if (atom
== "MATERIAL")
137 load_material(stream
);
139 else if (atom
== "name")
143 obj
->name
= read_string(stream
);
144 object_ptr parent
= obj
->parent
.lock();
145 if (parent
) parent
->kids_byname
.insert(std::make_pair(obj
->name
, obj
));
149 throw_invalid_atom(atom
);
152 else if (atom
== "data")
154 std::getline(stream
, atom
);
155 std::getline(stream
, obj
? obj
->data
: atom
);
157 else if (atom
== "texture")
159 if (obj
) obj
->texture
= resource::load(read_string(stream
));
161 else if (atom
== "texrep")
163 if (obj
) obj
->texrep
= read_pair(stream
);
164 else throw_invalid_atom(atom
);
166 else if (atom
== "rot")
169 std::getline(stream
, atom
);
171 else if (atom
== "loc")
174 std::getline(stream
, atom
);
176 else if (atom
== "url")
178 if (obj
) std::getline(stream
, obj
->url
);
179 else throw_invalid_atom(atom
);
181 else if (atom
== "numvert")
183 if (!obj
) throw_invalid_atom(atom
);
188 for (int i
= 0; i
< numvert
; ++i
)
190 obj
->verts
.push_back(read_triplet(stream
));
193 else if (atom
== "numsurf")
195 if (!obj
) throw_invalid_atom(atom
);
200 for (int i
= 0; i
< numsurf
; ++i
)
203 if (atom
!= "SURF") throw_invalid_atom(atom
);
204 load_surface(stream
, obj
);
208 else if (atom
== "kids")
218 if (0 < kids
.size() && 0 < --kids
.top()) kids
.pop();
219 obj
= obj
->parent
.lock();
227 void mesh::load_material(std::istream
& stream
)
229 materials_
.push_back(material(read_string(stream
)));
233 materials_
.back().diffuse
= read_color(stream
);
235 materials_
.back().ambient
= read_color(stream
);
237 materials_
.back().emissive
= read_color(stream
);
239 materials_
.back().specular
= read_color(stream
);
241 stream
>> atom
>> materials_
.back().shininess
;
242 stream
>> atom
>> materials_
.back().diffuse
[3];
243 materials_
.back().diffuse
[3] = SCALAR(1.0) - materials_
.back().diffuse
[3];
246 mesh::object_ptr
mesh::load_object(std::istream
& stream
, object_ptr parent
)
250 if (atom
!= "world" && atom
!= "group" && atom
!= "poly")
252 throw_invalid_atom(atom
);
255 object_ptr obj
= object::alloc(*this);
259 parent
->kids
.push_back(obj
);
260 obj
->parent
= parent
;
264 objects_
.push_back(obj
);
270 void mesh::load_surface(std::istream
& stream
, object_ptr obj
)
277 if (atom
== "mat") stream
>> material
>> atom
;
278 if (atom
!= "refs") throw_invalid_atom(atom
);
282 ASSERT(numrefs
>= 3);
284 if ((int)obj
->faces
.size() <= material
) obj
->faces
.resize(material
+ 1);
285 material_group
& face
= obj
->faces
[material
];
287 std::vector
<unsigned> verts(numrefs
);
288 std::vector
<vector2
> uv(numrefs
);
290 for (int i
= 0; i
< numrefs
; ++i
)
293 uv
[i
] = read_pair(stream
);
296 // translate texture coordinates
297 if (obj
->texture
) obj
->texture
->fix_uv(uv
);
298 // TODO why isn't texture always defined at this point?
300 for (int i
= 0; i
< numrefs
; ++i
)
302 scalar vert
= verts
[i
];
303 vector2 texcoord
= uv
[i
];
304 if (vert
< face
.triangles_uv
.size())
306 if (texcoord
!= face
.triangles_uv
[vert
])
308 obj
->verts
.push_back(obj
->verts
[vert
]);
309 face
.triangles_uv
.resize(obj
->verts
.size());
310 vert
= obj
->verts
.size() - 1;
313 else face
.triangles_uv
.resize(vert
+ 1);
314 face
.triangles_uv
[vert
] = texcoord
;
318 face
.triangles
.push_back(verts
[0]);
319 face
.triangles
.push_back(verts
[1]);
320 face
.triangles
.push_back(verts
[2]);
321 for (int i
= 3; i
< numrefs
; ++i
)
323 face
.triangles
.push_back(verts
[0]);
324 face
.triangles
.push_back(verts
[i
-1]);
325 face
.triangles
.push_back(verts
[i
]);
331 vector2 uv
= read_pair(stream
);
332 if (vert
< face
.triangles_uv
.size())
334 if (uv
!= face
.triangles_uv
[vert
])
336 obj
->verts
.push_back(obj
->verts
[vert
]);
337 face
.triangles_uv
.resize(obj
->verts
.size());
338 vert
= obj
->verts
.size() - 1;
341 else face
.triangles_uv
.resize(vert
+ 1);
342 face
.triangles_uv
[vert
] = uv
;
343 face
.triangles
.push_back(vert
);
345 unsigned first
= vert
;
348 uv
= read_pair(stream
);
349 if (vert
< face
.triangles_uv
.size())
351 if (uv
!= face
.triangles_uv
[vert
])
353 obj
->verts
.push_back(obj
->verts
[vert
]);
354 face
.triangles_uv
.resize(obj
->verts
.size());
355 vert
= obj
->verts
.size() - 1;
358 else face
.triangles_uv
.resize(vert
+ 1);
359 face
.triangles_uv
[vert
] = uv
;
360 face
.triangles
.push_back(vert
);
363 uv
= read_pair(stream
);
364 if (vert
< face
.triangles_uv
.size())
366 if (uv
!= face
.triangles_uv
[vert
])
368 obj
->verts
.push_back(obj
->verts
[vert
]);
369 face
.triangles_uv
.resize(obj
->verts
.size());
370 vert
= obj
->verts
.size() - 1;
373 else face
.triangles_uv
.resize(vert
+ 1);
374 face
.triangles_uv
[vert
] = uv
;
375 face
.triangles
.push_back(vert
);
377 unsigned last
= vert
;
379 for (int j
= 3; j
< numrefs
; ++j
)
381 face
.triangles
.push_back(first
);
382 face
.triangles
.push_back(last
);
385 uv
= read_pair(stream
);
386 if (vert
< face
.triangles_uv
.size())
388 if (uv
!= face
.triangles_uv
[vert
])
390 obj
->verts
.push_back(obj
->verts
[vert
]);
391 face
.triangles_uv
.resize(obj
->verts
.size());
392 vert
= obj
->verts
.size() - 1;
395 else face
.triangles_uv
.resize(vert
+ 1);
396 face
.triangles_uv
[vert
] = uv
;
397 face
.triangles
.push_back(vert
);
399 last
= face
.triangles
.back();
405 mesh::mesh(const std::string
& path
)
407 std::ifstream
file(path
.c_str(), std::ios::binary
);
408 if (!file
) throw std::runtime_error("cannot find mesh file");
410 // if we can read the header, the file isn't compressed
412 file
.get(magic
, sizeof(magic
));
413 if (strncmp(magic
, "AC3D", 4) == 0)
415 log_info("text mesh detected");
416 file
.seekg(std::ios::beg
);
421 log_info("decompressing mesh...");
422 file
.seekg(std::ios::beg
);
423 std::stringstream stream
;
424 inflate(file
, stream
);
429 void mesh::draw(scalar alpha
) const
431 glEnableClientState(GL_VERTEX_ARRAY
);
433 std::vector
<object_ptr
>::const_iterator it
;
434 for (it
= objects_
.begin(); it
!= objects_
.end(); ++it
)
439 // TODO: disable vertex array?
442 void mesh::set_material(int index
) const
444 set_material(materials_
[index
]);
447 void mesh::set_material(const material
& material
) const
449 glColor(material
.diffuse
);
450 glMaterial(GL_FRONT
, GL_DIFFUSE
, material
.diffuse
);
451 glMaterial(GL_FRONT
, GL_AMBIENT
, material
.ambient
);
452 glMaterial(GL_FRONT
, GL_SPECULAR
, material
.specular
);
453 glMaterial(GL_FRONT
, GL_EMISSION
, material
.emissive
);
454 glMaterial(GL_FRONT
, GL_SHININESS
, material
.shininess
);
458 void mesh::object::draw(scalar alpha
, bool recurse
) const
460 glVertexPointer(verts
);
465 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
469 image::reset_binding();
470 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
473 for (size_t i
= 0; i
< faces
.size(); ++i
)
475 const material_group
& face
= faces
[i
];
476 if (face
.triangles
.size() == 0) continue;
478 mesh
.set_material(i
);
480 if (texture
) glTexCoordPointer(face
.triangles_uv
);
481 glDrawElements(GL_TRIANGLES
, face
.triangles
);
486 std::vector
<object_ptr
>::const_iterator jt
;
487 for (jt
= kids
.begin(); jt
!= kids
.end(); ++jt
)
This page took 0.054875 seconds and 4 git commands to generate.