4 #include <gmath/gmath.h>
5 #include <assimp/cimport.h>
6 #include <assimp/postprocess.h>
7 #include <assimp/scene.h>
8 #include <assimp/mesh.h>
9 #include <assimp/material.h>
10 #include <assimp/anim.h>
11 #include <assimp/vector3.h>
12 #include <assimp/matrix4x4.h>
13 #include <assimp/quaternion.h>
17 static bool load_material(Material *mat, const aiMaterial *aimat);
18 static SceneNode *load_node(const aiScene *aiscn, const aiNode *ainode);
19 static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh);
21 /*static Vec3 assimp_vector(const aiVector3D &v);
22 static Quat assimp_quat(const aiQuaternion &q);
23 static Mat4 assimp_matrix(const aiMatrix4x4 &aim);
24 static long assimp_time(const aiAnimation *anim, double aitime);
25 static void print_hierarchy(const aiNode *node);
28 static std::map<std::string, SceneNode*> node_by_name;
29 static std::map<aiMesh*, Mesh*> mesh_by_aimesh;
31 bool Scene::load(const char *fname)
33 unsigned int ppflags = aiProcess_CalcTangentSpace |
34 aiProcess_GenNormals |
35 aiProcess_JoinIdenticalVertices |
36 aiProcess_Triangulate |
37 aiProcess_SortByPType |
38 aiProcess_TransformUVCoords;
40 const aiScene *aiscn = aiImportFile(fname, ppflags);
42 fprintf(stderr, "failed to load scene file: %s\n", fname);
47 Vec3 root_pos, root_scaling(1.0, 1.0, 1.0);
50 if(aiscn->mRootNode) {
51 Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
52 root_pos = root_matrix.get_translation();
53 root_rot = root_matrix.get_rotation_quat();
54 root_scaling = root_matrix.get_scaling();
58 for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
59 aiMesh *aimesh = aiscn->mMeshes[i];
62 switch(aimesh->mPrimitiveTypes) {
63 case aiPrimitiveType_TRIANGLE:
64 if((mesh = load_mesh(aiscn, aimesh))) {
65 mesh_by_aimesh[aimesh] = mesh;
66 meshes.push_back(mesh);
71 fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
76 SceneNode *root = new SceneNode;
78 // load all the nodes recursively
79 for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
80 SceneNode *node = load_node(aiscn, aiscn->mRootNode->mChildren[i]);
82 root->add_child(node);
86 int nnodes = root->get_num_children();
89 } else if(nnodes == 1) {
90 nodes = root->get_child(0);
91 root->remove_child(nodes);
98 mesh_by_aimesh.clear();
100 aiReleaseImport(aiscn);
101 printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
105 static bool load_material(Material *mat, const aiMaterial *aimat)
108 float shin, shin_str;
110 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
111 mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
113 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
114 mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
117 unsigned int count = 1;
118 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
121 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
122 // XXX can't remember how I came up with this...
123 mat->shininess = shin * shin_str * 0.0001 * 128.0;
128 struct { int type; aiTextureType aitype; } textypes[] = {
129 {TEX_DIFFUSE, aiTextureType_DIFFUSE},
130 {TEX_NORMAL, aiTextureType_NORMALS},
131 {TEX_SPECULAR, aiTextureType_SPECULAR}
134 for(size_t i=0; i<sizeof textypes / sizeof *textypes; i++) {
137 if(aiGetMaterialTexture(aimat, textypes[i].aitype, 0, &aipath) == 0) {
138 char *tmp, *fname = aipath.data;
140 if((tmp = strrchr(fname, '/'))) {
143 if((tmp = strrchr(fname, '\\'))) {
148 mat->tex[textypes[i].type] = texset.get(fname);
157 static SceneNode *load_node(const aiScene *aiscn, const aiNode *ainode)
159 SceneNode *node = new SceneNode;
160 node->set_name(ainode->mName.data);
162 for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
163 aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]];
165 Mesh *mesh = mesh_by_aimesh[aimesh];
167 ObjMesh *obj = new ObjMesh;
169 // also grab the material of this mesh
170 load_material(&obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
172 node->add_object(obj);
176 /* recurse to all children */
177 for(unsigned int i=0; i<ainode->mNumChildren; i++) {
178 SceneNode *child = load_node(aiscn, ainode->mChildren[i]);
180 node->add_child(child);
184 node_by_name[node->get_name()] = node;
188 static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh)
190 Mesh *mesh = new Mesh;
192 int num_verts = aimesh->mNumVertices;
193 int num_faces = aimesh->mNumFaces;
195 mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
197 if(aimesh->mNormals) {
198 mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
200 if(aimesh->mTangents) {
201 mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
203 if(aimesh->mTextureCoords[0]) {
204 mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
207 unsigned int *iptr = mesh->set_index_data(num_faces * 3);
208 for(int i=0; i<num_faces; i++) {
209 for(int j=0; j<3; j++) {
210 *iptr++ = aimesh->mFaces[i].mIndices[j];
218 static Vec3 assimp_vector(const aiVector3D &v)
220 return Vec3(v[0], v[1], v[2]);
223 static Quat assimp_quat(const aiQuaternion &q)
225 return Quat(q.x, q.y, q.z, q.w);
228 static Mat4 assimp_matrix(const aiMatrix4x4 &aim)
231 memcpy(m[0], &aim, 16 * sizeof(float));
236 /* convert an assimp keyframe time (ticks) into milliseconds */
237 static long assimp_time(const aiAnimation *anim, double aitime)
240 if(anim->mTicksPerSecond < 1e-6) {
241 // assume time is in frames?
244 sec = aitime / anim->mTicksPerSecond;
246 return (long)(sec * 1000.0);
249 static void print_hierarchy(const aiNode *node)
252 static int lvlopen[256];
254 for(int i=0; i<lvl; i++) {
257 putchar(i >= lvl - 1 ? '+' : '|');
259 putchar(i >= lvl - 1 ? '+' : ' ');
262 printf("- \"%s\"\n", node->mName.data);
267 for(unsigned int i=0; i<node->mNumChildren; i++) {
268 if(i == node->mNumChildren - 1) {
269 lvlopen[lvl - 1] = 0;
271 print_hierarchy(node->mChildren[i]);