5 #include <gmath/gmath.h>
6 #include <assimp/cimport.h>
7 #include <assimp/postprocess.h>
8 #include <assimp/scene.h>
9 #include <assimp/mesh.h>
10 #include <assimp/material.h>
11 #include <assimp/anim.h>
12 #include <assimp/vector3.h>
13 #include <assimp/matrix4x4.h>
14 #include <assimp/quaternion.h>
19 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat);
20 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode);
21 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh);
22 static void print_nodes(SceneNode *node, int lvl = 0);
23 /*static const char *mprop_semantic(int x);
24 static int count_textures(const aiMaterial *aimat);*/
25 static int assimp_textype(aiTextureType type);
26 static const char *assimp_textypestr(aiTextureType type);
28 static Mat4 assimp_matrix(const aiMatrix4x4 &aim);
30 /*static Vec3 assimp_vector(const aiVector3D &v);
31 static Quat assimp_quat(const aiQuaternion &q);
32 static long assimp_time(const aiAnimation *anim, double aitime);
33 static void print_hierarchy(const aiNode *node);
36 static std::map<std::string, SceneNode*> node_by_name;
37 static std::map<aiMesh*, Mesh*> mesh_by_aimesh;
39 bool Scene::load(const char *fname, unsigned int flags)
41 unsigned int ppflags = aiProcess_CalcTangentSpace |
42 aiProcess_GenNormals |
43 aiProcess_JoinIdenticalVertices |
44 aiProcess_Triangulate |
45 aiProcess_SortByPType |
46 aiProcess_GenUVCoords |
47 //aiProcess_PreTransformVertices |
48 aiProcess_TransformUVCoords;
50 if(flags & SCNLOAD_FLIPTEX) {
51 ppflags |= aiProcess_FlipUVs;
54 printf("Loading scene file: %s\n", fname);
56 const aiScene *aiscn = aiImportFile(fname, ppflags);
58 fprintf(stderr, "failed to load scene file: %s\n", fname);
62 // assimp adds its own root node, which might have transformations
63 Vec3 root_pos, root_scaling(1.0, 1.0, 1.0);
66 if(aiscn->mRootNode) {
67 Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
68 root_pos = root_matrix.get_translation();
69 root_rot = root_matrix.get_rotation();
70 root_scaling = root_matrix.get_scaling();
72 printf("assimp root node: %s\n", aiscn->mRootNode->mName.data);
73 printf(" pos: %f %f %f\n", root_pos.x, root_pos.y, root_pos.z);
74 printf(" rot: %f %+f %+f %+f\n", root_rot.w, root_rot.x, root_rot.y, root_rot.z);
75 printf(" scaling: %f %f %f\n", root_scaling.x, root_scaling.y, root_scaling.z);
79 for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
80 aiMesh *aimesh = aiscn->mMeshes[i];
83 switch(aimesh->mPrimitiveTypes) {
84 case aiPrimitiveType_TRIANGLE:
85 if((mesh = load_mesh(this, aiscn, flags, aimesh))) {
86 mesh_by_aimesh[aimesh] = mesh;
87 meshes.push_back(mesh);
92 fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
98 nodes = new SceneNode;
99 nodes->set_name("root");
100 nodes->set_position(root_pos);
101 nodes->set_rotation(root_rot);
102 nodes->set_scaling(root_scaling);
105 // load all the nodes recursively
106 for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
107 SceneNode *node = load_node(this, aiscn, flags, aiscn->mRootNode->mChildren[i]);
109 nodes->add_child(node);
113 node_by_name.clear();
114 mesh_by_aimesh.clear();
116 aiReleaseImport(aiscn);
117 printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
123 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat)
127 float shin, shin_str;
129 if(aiGetMaterialString(aimat, AI_MATKEY_NAME, &name) == 0) {
130 mat->name = name.data;
132 mat->name = "unknown";
134 printf("load_material: %s\n", mat->name.c_str());
136 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
137 mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
139 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
140 mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
143 unsigned int count = 1;
144 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
147 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
148 // XXX can't remember how I came up with this...
149 mat->shininess = shin * shin_str * 0.0001 * 128.0;
154 const int num_tex_types = aiTextureType_UNKNOWN + 1;
155 for(int i=0; i<num_tex_types; i++) {
156 aiTextureType aitype = (aiTextureType)i;
157 int count = aiGetMaterialTextureCount(aimat, aitype);
159 for(int j=0; j<count; j++) {
161 if(aiGetMaterialTexture(aimat, aitype, j, &aipath) != 0) {
166 int nsize = datamap_path_size(aipath.data);
168 fname = new char[nsize];
169 datamap_lookup(aipath.data, fname, nsize);
171 fname = new char[strlen(aipath.data) + 1];
173 char *sptr = aipath.data;
175 *dptr++ = *sptr == '\\' ? '/' : *sptr;
179 int textype = assimp_textype(aitype);
180 printf("loading %s texture: %s\n", assimp_textypestr(aitype), fname);
182 Texture *tex = scn->texset->get_texture(fname, TEX_2D);
184 mat->textures.push_back(tex);
186 printf(" DBG(%p)\n", (void*)tex);
188 if(textype != MTL_TEX_UNKNOWN && !mat->stdtex[textype]) {
189 mat->stdtex[textype] = tex;
197 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode)
199 SceneNode *node = new SceneNode;
200 node->set_name(ainode->mName.data);
203 Mat4 matrix = assimp_matrix(ainode->mTransformation);
204 Vec3 pos = matrix.get_translation();
205 Quat rot = matrix.get_rotation();
206 Vec3 scale = matrix.get_scaling();
208 node->set_position(pos);
209 node->set_rotation(rot);
210 node->set_scaling(scale);
211 node->dbg_xform = matrix;
214 for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
215 aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[i]];
217 Mesh *mesh = mesh_by_aimesh[aimesh];
219 ObjMesh *obj = new ObjMesh;
221 // also grab the material of this mesh
222 load_material(scn, &obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
224 node->add_object(obj);
225 scn->objects.push_back(obj);
229 /* recurse to all children */
230 for(unsigned int i=0; i<ainode->mNumChildren; i++) {
231 SceneNode *child = load_node(scn, aiscn, flags, ainode->mChildren[i]);
233 node->add_child(child);
237 node_by_name[node->get_name()] = node;
241 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh)
243 Mesh *mesh = new Mesh;
245 int num_verts = aimesh->mNumVertices;
246 int num_faces = aimesh->mNumFaces;
248 mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
250 if(aimesh->mNormals) {
251 mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
253 if(aimesh->mTangents) {
254 mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
256 if(aimesh->mTextureCoords[0]) {
257 mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
259 if(aimesh->mTextureCoords[1]) {
260 mesh->set_attrib_data(MESH_ATTR_TEXCOORD2, 3, num_verts, (float*)aimesh->mTextureCoords[1]);
263 if(flags & SCNLOAD_FLIPYZ) {
264 Vec3 *vptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX);
265 for(int i=0; i<num_verts; i++) {
270 Vec3 *nptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_NORMAL);
271 for(int i=0; i<num_verts; i++) {
276 Vec3 *tptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_TANGENT);
277 for(int i=0; i<num_verts; i++) {
283 unsigned int *iptr = mesh->set_index_data(num_faces * 3);
284 for(int i=0; i<num_faces; i++) {
285 iptr[0] = aimesh->mFaces[i].mIndices[0];
286 iptr[1] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 2 : 1];
287 iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2];
291 AABox bbox = mesh->get_aabbox();
292 printf("mesh bounding box: %f %f %f -> %f %f %f\n", bbox.min.x, bbox.min.y, bbox.min.z,
293 bbox.max.x, bbox.max.y, bbox.max.z);
298 static void print_nodes(SceneNode *node, int lvl)
300 Vec3 pos = node->get_node_position();
301 Quat rot = node->get_node_rotation();
302 Vec3 scale = node->get_node_scaling();
304 const char *type = node->get_num_objects() > 0 ? "mesh node" : "null node";
306 for(int i=0; i<lvl; i++) {
309 printf("%s[%s] p(%g %g %g) rq(%g %+gi %+gj %+gk) s(%g %g %g)\n", type, node->get_name(),
310 pos.x, pos.y, pos.z, rot.w, rot.x, rot.y, rot.z, scale.x, scale.y, scale.z);
312 if(node->get_num_objects()) {
313 Mat4 xform = node->get_matrix();
317 int nchld = node->get_num_children();
318 for(int i=0; i<nchld; i++) {
319 print_nodes(node->get_child(i), lvl + 1);
323 static int assimp_textype(aiTextureType type)
326 case aiTextureType_DIFFUSE:
327 return MTL_TEX_DIFFUSE;
328 case aiTextureType_SPECULAR:
329 return MTL_TEX_SPECULAR;
330 case aiTextureType_NORMALS:
331 return MTL_TEX_NORMALMAP;
332 case aiTextureType_LIGHTMAP:
333 case aiTextureType_EMISSIVE:
334 return MTL_TEX_LIGHTMAP;
335 case aiTextureType_REFLECTION:
336 return MTL_TEX_ENVMAP;
340 return MTL_TEX_UNKNOWN;
343 static const char *assimp_textypestr(aiTextureType type)
346 case aiTextureType_DIFFUSE:
348 case aiTextureType_SPECULAR:
350 case aiTextureType_NORMALS:
352 case aiTextureType_LIGHTMAP:
353 case aiTextureType_EMISSIVE:
355 case aiTextureType_REFLECTION:
363 static Mat4 assimp_matrix(const aiMatrix4x4 &aim)
366 memcpy(m[0], &aim, 16 * sizeof(float));