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, unsigned int flags, const aiNode *ainode);
19 static Mesh *load_mesh(const aiScene *aiscn, unsigned int flags, 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, unsigned int flags)
33 unsigned int ppflags = aiProcess_CalcTangentSpace |
34 aiProcess_GenNormals |
35 aiProcess_JoinIdenticalVertices |
36 aiProcess_Triangulate |
37 aiProcess_SortByPType |
38 aiProcess_TransformUVCoords | aiProcess_PreTransformVertices;
40 if(flags & SCNLOAD_FLIPTEX) {
41 ppflags |= aiProcess_FlipUVs;
44 const aiScene *aiscn = aiImportFile(fname, ppflags);
46 fprintf(stderr, "failed to load scene file: %s\n", fname);
51 Vec3 root_pos, root_scaling(1.0, 1.0, 1.0);
54 if(aiscn->mRootNode) {
55 Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
56 root_pos = root_matrix.get_translation();
57 root_rot = root_matrix.get_rotation_quat();
58 root_scaling = root_matrix.get_scaling();
62 for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
63 aiMesh *aimesh = aiscn->mMeshes[i];
66 switch(aimesh->mPrimitiveTypes) {
67 case aiPrimitiveType_TRIANGLE:
68 if((mesh = load_mesh(aiscn, flags, aimesh))) {
69 mesh_by_aimesh[aimesh] = mesh;
70 meshes.push_back(mesh);
75 fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
80 SceneNode *root = new SceneNode;
82 // load all the nodes recursively
83 for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
84 SceneNode *node = load_node(aiscn, flags, aiscn->mRootNode->mChildren[i]);
86 root->add_child(node);
90 int nnodes = root->get_num_children();
93 } else if(nnodes == 1) {
94 nodes = root->get_child(0);
95 root->remove_child(nodes);
101 node_by_name.clear();
102 mesh_by_aimesh.clear();
104 aiReleaseImport(aiscn);
105 printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
109 static bool load_material(Material *mat, const aiMaterial *aimat)
112 float shin, shin_str;
114 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
115 mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
117 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
118 mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
121 unsigned int count = 1;
122 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
125 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
126 // XXX can't remember how I came up with this...
127 mat->shininess = shin * shin_str * 0.0001 * 128.0;
132 struct { int type; aiTextureType aitype; } textypes[] = {
133 {TEX_DIFFUSE, aiTextureType_DIFFUSE},
134 {TEX_NORMAL, aiTextureType_NORMALS},
135 {TEX_SPECULAR, aiTextureType_SPECULAR}
138 for(size_t i=0; i<sizeof textypes / sizeof *textypes; i++) {
141 if(aiGetMaterialTexture(aimat, textypes[i].aitype, 0, &aipath) == 0) {
142 char *tmp, *fname = aipath.data;
144 if((tmp = strrchr(fname, '/'))) {
147 if((tmp = strrchr(fname, '\\'))) {
152 mat->tex[textypes[i].type] = texset.get(fname);
161 static SceneNode *load_node(const aiScene *aiscn, unsigned int flags, const aiNode *ainode)
163 SceneNode *node = new SceneNode;
164 node->set_name(ainode->mName.data);
166 for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
167 aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]];
169 Mesh *mesh = mesh_by_aimesh[aimesh];
171 ObjMesh *obj = new ObjMesh;
173 // also grab the material of this mesh
174 load_material(&obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
176 node->add_object(obj);
180 /* recurse to all children */
181 for(unsigned int i=0; i<ainode->mNumChildren; i++) {
182 SceneNode *child = load_node(aiscn, flags, ainode->mChildren[i]);
184 node->add_child(child);
188 node_by_name[node->get_name()] = node;
192 static Mesh *load_mesh(const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh)
194 Mesh *mesh = new Mesh;
196 int num_verts = aimesh->mNumVertices;
197 int num_faces = aimesh->mNumFaces;
199 mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
201 if(aimesh->mNormals) {
202 mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
204 if(aimesh->mTangents) {
205 mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
207 if(aimesh->mTextureCoords[0]) {
208 mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
211 if(flags & SCNLOAD_FLIPYZ) {
212 Vec3 *vptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX);
213 for(int i=0; i<num_verts; i++) {
218 Vec3 *nptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_NORMAL);
219 for(int i=0; i<num_verts; i++) {
224 Vec3 *tptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_TANGENT);
225 for(int i=0; i<num_verts; i++) {
231 unsigned int *iptr = mesh->set_index_data(num_faces * 3);
232 for(int i=0; i<num_faces; i++) {
233 iptr[0] = aimesh->mFaces[i].mIndices[0];
234 iptr[1] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 2 : 1];
235 iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2];
243 static Vec3 assimp_vector(const aiVector3D &v)
245 return Vec3(v[0], v[1], v[2]);
248 static Quat assimp_quat(const aiQuaternion &q)
250 return Quat(q.x, q.y, q.z, q.w);
253 static Mat4 assimp_matrix(const aiMatrix4x4 &aim)
256 memcpy(m[0], &aim, 16 * sizeof(float));
261 /* convert an assimp keyframe time (ticks) into milliseconds */
262 static long assimp_time(const aiAnimation *anim, double aitime)
265 if(anim->mTicksPerSecond < 1e-6) {
266 // assume time is in frames?
269 sec = aitime / anim->mTicksPerSecond;
271 return (long)(sec * 1000.0);
274 static void print_hierarchy(const aiNode *node)
277 static int lvlopen[256];
279 for(int i=0; i<lvl; i++) {
282 putchar(i >= lvl - 1 ? '+' : '|');
284 putchar(i >= lvl - 1 ? '+' : ' ');
287 printf("- \"%s\"\n", node->mName.data);
292 for(unsigned int i=0; i<node->mNumChildren; i++) {
293 if(i == node->mNumChildren - 1) {
294 lvlopen[lvl - 1] = 0;
296 print_hierarchy(node->mChildren[i]);