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>
18 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat);
19 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode);
20 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh);
21 /*static const char *mprop_semantic(int x);
22 static int count_textures(const aiMaterial *aimat);*/
23 static int assimp_textype(aiTextureType type);
25 /*static Vec3 assimp_vector(const aiVector3D &v);
26 static Quat assimp_quat(const aiQuaternion &q);
27 static Mat4 assimp_matrix(const aiMatrix4x4 &aim);
28 static long assimp_time(const aiAnimation *anim, double aitime);
29 static void print_hierarchy(const aiNode *node);
32 static std::map<std::string, SceneNode*> node_by_name;
33 static std::map<aiMesh*, Mesh*> mesh_by_aimesh;
35 bool Scene::load(const char *fname, unsigned int flags)
37 unsigned int ppflags = aiProcess_CalcTangentSpace |
38 aiProcess_GenNormals |
39 aiProcess_JoinIdenticalVertices |
40 aiProcess_Triangulate |
41 aiProcess_SortByPType |
42 aiProcess_TransformUVCoords | aiProcess_PreTransformVertices;
44 if(flags & SCNLOAD_FLIPTEX) {
45 ppflags |= aiProcess_FlipUVs;
48 const aiScene *aiscn = aiImportFile(fname, ppflags);
50 fprintf(stderr, "failed to load scene file: %s\n", fname);
55 Vec3 root_pos, root_scaling(1.0, 1.0, 1.0);
58 if(aiscn->mRootNode) {
59 Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
60 root_pos = root_matrix.get_translation();
61 root_rot = root_matrix.get_rotation_quat();
62 root_scaling = root_matrix.get_scaling();
66 for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
67 aiMesh *aimesh = aiscn->mMeshes[i];
70 switch(aimesh->mPrimitiveTypes) {
71 case aiPrimitiveType_TRIANGLE:
72 if((mesh = load_mesh(this, aiscn, flags, aimesh))) {
73 mesh_by_aimesh[aimesh] = mesh;
74 meshes.push_back(mesh);
79 fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
84 SceneNode *root = new SceneNode;
86 // load all the nodes recursively
87 for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
88 SceneNode *node = load_node(this, aiscn, flags, aiscn->mRootNode->mChildren[i]);
90 root->add_child(node);
94 int nnodes = root->get_num_children();
97 } else if(nnodes == 1) {
98 nodes = root->get_child(0);
99 root->remove_child(nodes);
105 node_by_name.clear();
106 mesh_by_aimesh.clear();
108 aiReleaseImport(aiscn);
109 printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
113 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat)
117 float shin, shin_str;
119 if(aiGetMaterialString(aimat, AI_MATKEY_NAME, &name) == 0) {
120 mat->name = name.data;
122 mat->name = "unknown";
124 printf("load_material: %s\n", mat->name.c_str());
126 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
127 mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
129 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
130 mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
133 unsigned int count = 1;
134 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
137 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
138 // XXX can't remember how I came up with this...
139 mat->shininess = shin * shin_str * 0.0001 * 128.0;
144 const int num_tex_types = aiTextureType_UNKNOWN + 1;
145 for(int i=0; i<num_tex_types; i++) {
146 aiTextureType aitype = (aiTextureType)i;
147 int count = aiGetMaterialTextureCount(aimat, aitype);
149 for(int j=0; j<count; j++) {
151 if(aiGetMaterialTexture(aimat, aitype, j, &aipath) != 0) {
156 int nsize = datamap_path_size(aipath.data);
158 fname = new char[nsize];
159 datamap_lookup(aipath.data, fname, nsize);
161 fname = new char[strlen(aipath.data) + 1];
163 char *sptr = aipath.data;
165 *dptr++ = *sptr == '\\' ? '/' : *sptr;
169 Texture *tex = scn->texset->get(fname);
171 fprintf(stderr, "failed to load texture: %s\n", fname);
177 mat->textures.push_back(tex);
179 int textype = assimp_textype(aitype);
180 if(textype != MTL_TEX_UNKNOWN && !mat->stdtex[textype]) {
181 mat->stdtex[textype] = tex;
187 for(size_t i=0; i<sizeof textypes / sizeof *textypes; i++) {
190 if(aiGetMaterialTexture(aimat, textypes[i].aitype, 0, &aipath) == 0) {
191 char *tmp, *fname = aipath.data;
193 if((tmp = strrchr(fname, '/'))) {
196 if((tmp = strrchr(fname, '\\'))) {
201 mat->tex[textypes[i].type] = texset.get(fname);
210 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode)
212 SceneNode *node = new SceneNode;
213 node->set_name(ainode->mName.data);
215 for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
216 aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]];
218 Mesh *mesh = mesh_by_aimesh[aimesh];
220 ObjMesh *obj = new ObjMesh;
222 // also grab the material of this mesh
223 load_material(scn, &obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
225 node->add_object(obj);
226 scn->objects.push_back(obj);
230 /* recurse to all children */
231 for(unsigned int i=0; i<ainode->mNumChildren; i++) {
232 SceneNode *child = load_node(scn, aiscn, flags, ainode->mChildren[i]);
234 node->add_child(child);
238 node_by_name[node->get_name()] = node;
242 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh)
244 Mesh *mesh = new Mesh;
246 int num_verts = aimesh->mNumVertices;
247 int num_faces = aimesh->mNumFaces;
249 mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
251 if(aimesh->mNormals) {
252 mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
254 if(aimesh->mTangents) {
255 mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
257 if(aimesh->mTextureCoords[0]) {
258 mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
260 if(aimesh->mTextureCoords[1]) {
261 mesh->set_attrib_data(MESH_ATTR_TEXCOORD2, 3, num_verts, (float*)aimesh->mTextureCoords[1]);
264 if(flags & SCNLOAD_FLIPYZ) {
265 Vec3 *vptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX);
266 for(int i=0; i<num_verts; i++) {
271 Vec3 *nptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_NORMAL);
272 for(int i=0; i<num_verts; i++) {
277 Vec3 *tptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_TANGENT);
278 for(int i=0; i<num_verts; i++) {
284 unsigned int *iptr = mesh->set_index_data(num_faces * 3);
285 for(int i=0; i<num_faces; i++) {
286 iptr[0] = aimesh->mFaces[i].mIndices[0];
287 iptr[1] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 2 : 1];
288 iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2];
295 static int assimp_textype(aiTextureType type)
298 case aiTextureType_DIFFUSE:
299 return MTL_TEX_DIFFUSE;
300 case aiTextureType_SPECULAR:
301 return MTL_TEX_SPECULAR;
302 case aiTextureType_NORMALS:
303 return MTL_TEX_NORMALMAP;
304 case aiTextureType_LIGHTMAP:
305 return MTL_TEX_LIGHTMAP;
306 case aiTextureType_REFLECTION:
307 return MTL_TEX_ENVMAP;
311 return MTL_TEX_UNKNOWN;