2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
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.
10 **************************************************************************/
18 #include <boost/algorithm/string/trim.hpp>
21 #include <stlplus/strings/string_utilities.hpp>
29 #define AC3D_FORMAT_VERSION (0x0b)
30 #define ZLIB_BUF_SIZE (262114)
36 static std::string
read_string(std::istream
& stream
)
41 do // skip to the next non-space character
45 while (stream
&& std::isspace(atom
));
52 if (atom
== '"') break;
62 if (std::isspace(atom
)) break;
71 inline int read_hex(std::istream
& stream
)
74 std::ios::fmtflags flags
= stream
.flags();
75 stream
.setf(std::ios::hex
, std::ios::basefield
);
81 inline vector2
read_pair(std::istream
& stream
)
84 stream
>> triplet
[0] >> triplet
[1];
90 inline vector
< scalar
, fixed
<D
> > read_triplet(std::istream
& stream
)
92 vector
< scalar
, fixed
<D
> > triplet
;
93 stream
>> triplet
[0] >> triplet
[1] >> triplet
[2];
98 void mesh::import(std::istream
& stream
)
103 std::stack
<int> kids
;
105 // 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");
128 if (atom
== "MATERIAL")
130 materials_
.push_back(material(read_string(stream
)));
133 materials_
.back().diffuse
= read_triplet
<4>(stream
);
135 materials_
.back().ambient
= read_triplet
<3>(stream
);
137 materials_
.back().emissive
= read_triplet
<3>(stream
);
139 materials_
.back().specular
= read_triplet
<3>(stream
);
141 stream
>> atom
>> materials_
.back().shininess
;
142 stream
>> atom
>> materials_
.back().diffuse
[3]; // transparency
143 materials_
.back().diffuse
[3] = 1.0;
145 log_info("read material", materials_
.back().name
,
146 materials_
.back().diffuse
);
148 else if (atom
== "OBJECT")
151 if (atom
!= "world" && atom
!= "group" && atom
!= "poly")
153 throw std::runtime_error("unexpected object type " + atom
);
156 object_ptr newObj
= object::alloc();
160 obj
->kids
.push_back(newObj
);
161 newObj
->parent
= obj
;
165 objects_
.push_back(newObj
);
170 else if (atom
== "name")
172 if (obj
) obj
->name
= read_string(stream
);
173 else throw std::runtime_error("unexpected atom: " + atom
);
175 else if (atom
== "data")
177 std::getline(stream
, atom
);
178 std::getline(stream
, obj
? obj
->data
: atom
);
180 else if (atom
== "texture")
182 if (obj
) obj
->texture
= resource::load(read_string(stream
));
184 else if (atom
== "texrep")
186 if (obj
) obj
->texrep
= read_pair(stream
);
187 else throw std::runtime_error("unexpected atom: " + atom
);
189 else if (atom
== "rot")
192 std::getline(stream
, atom
);
194 else if (atom
== "loc")
197 std::getline(stream
, atom
);
199 else if (atom
== "url")
201 if (obj
) std::getline(stream
, obj
->url
);
202 else throw std::runtime_error("unexpected atom: " + atom
);
204 else if (atom
== "numvert")
206 if (!obj
) throw std::runtime_error("unexpected atom: " + atom
);
211 log_warning("adding verts", numvert
);
213 for (int i
= 0; i
< numvert
; ++i
)
215 obj
->verts
.push_back(read_triplet
<3>(stream
));
216 log_error("vert", obj
->verts
.back());
219 else if (atom
== "numsurf")
221 if (!obj
) throw std::runtime_error("unexpected atom: " + atom
);
226 for (int i
= 0; i
< numsurf
; ++i
)
229 if (atom
!= "SURF") throw std::runtime_error("uh oh");
231 int flags
= read_hex(stream
);
236 if (atom
== "mat") stream
>> material
>> atom
;
240 throw std::runtime_error("blaaaaaaaahhh!!");
245 ASSERT(numrefs
== 3 || numrefs
== 4);
247 if ((int)obj
->faces
.size() <= material
)
249 log_info("inserting face...");
250 //obj->faces.insert(obj->faces.begin() + material,
252 obj
->faces
.resize(material
+ 1);
253 log_info("inserted face", material
, obj
->faces
.size());
256 material_group
& face
= obj
->faces
[material
];
257 for (int j
= 0; j
< numrefs
; ++j
)
262 vector2 uv
= read_pair(stream
);
266 face
.triangles
.push_back(vert
);
267 face
.triangles_uv
.push_back(uv
);
271 face
.quads
.push_back(vert
);
272 face
.quads_uv
.push_back(uv
);
277 else if (atom
== "kids")
279 for (int i
= kids
.size(); i
> 0; --i
)
281 if (--kids
.top() <= 0)
283 ASSERT(obj
&& "should be an object");
292 if (numkids
> 0) kids
.push(numkids
);
296 log_info("KIDS", kids
.top(), "|", kids
.size());
301 log_warning("UNKNOWN ATOM:", atom
);
308 mesh::mesh(const std::string
& path
)
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");
314 // if we can read the header, the file isn't compressed
316 file
.get(magic
, sizeof(magic
));
317 if (strncmp(magic
, "AC3D", 4) == 0)
319 log_info("text mesh detected");
320 file
.seekg(std::ios::beg
);
326 log_info("compressed mesh detected");
327 file
.seekg(std::ios::beg
);
329 std::stringstream stream
;
330 char in
[ZLIB_BUF_SIZE
];
331 char out
[ZLIB_BUF_SIZE
];
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
;
341 int result
= inflateInit2(&zstream
, 32+MAX_WBITS
);
342 if (result
!= Z_OK
) throw std::runtime_error("zlib init error");
346 file
.read(in
, sizeof(in
));
347 zstream
.next_in
= (Bytef
*)in
;
348 zstream
.avail_in
= file
.gcount();
350 if (zstream
.avail_in
== 0) break;
354 zstream
.next_out
= (Bytef
*)out
;
355 zstream
.avail_out
= sizeof(out
);
357 result
= inflate(&zstream
, Z_NO_FLUSH
);
363 inflateEnd(&zstream
);
364 throw std::runtime_error("zlib inflate error");
366 throw std::runtime_error("zlib stream error");
369 int inflated
= sizeof(out
) - zstream
.avail_out
;
370 stream
.write(out
, inflated
);
372 while (zstream
.avail_out
== 0);
374 while(result
!= Z_STREAM_END
);
376 inflateEnd(&zstream
);
383 void mesh::draw(scalar alpha
) const
385 //glEnableClientState(GL_VERTEX_ARRAY);
386 //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
388 glColor4f(1.0f
, 1.0f
, 1.0f
, 1.0f
);
390 std::vector
<object_ptr
>::const_iterator it
;
391 for (it
= objects_
.begin(); it
!= objects_
.end(); ++it
)
393 (*it
)->draw(*this, alpha
);
398 void mesh::set_material(int index
) const
400 set_material(materials_
[index
]);
403 void mesh::set_material(const material
& material
) const
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
);
414 void mesh::object::draw(const mesh
& mesh
, scalar alpha
) const
416 //log_info("cool", verts.size());
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)
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();
433 for (int i
= 0; i
< faces
.size(); ++i
)
435 const material_group
& face
= faces
[i
];
436 mesh
.set_material(i
);
438 //std::vector<unsigned>::const_iterator jt;
439 int count
= face
.triangles
.size();
440 for (int j
= 0; j
< count
; j
+= 3)
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]]);
452 count
= face
.quads
.size();
453 for (int j
= 0; j
< count
; j
+= 4)
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]]);
468 std::vector
<object_ptr
>::const_iterator jt
;
469 for (jt
= kids
.begin(); jt
!= kids
.end(); ++jt
)
471 (*jt
)->draw(mesh
, alpha
);
475 void mesh::material_group::draw(scalar alpha
) const
477 // TODO: setup material
480 if (triangles.size() > 0)
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,
489 if (quads.size() > 0)
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]);
499 class mesh_resource_loader
503 mesh_resource_loader()
505 resource::register_type
<mesh
>("ac", "models");
508 ~mesh_resource_loader()
510 resource::unregister_type("ac");
514 static mesh_resource_loader loader
;