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>
20 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat);
21 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode);
22 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh);
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 info_log("Loading scene file: %s\n", fname);
56 const aiScene *aiscn = aiImportFile(fname, ppflags);
58 error_log("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();
74 for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
75 aiMesh *aimesh = aiscn->mMeshes[i];
78 switch(aimesh->mPrimitiveTypes) {
79 case aiPrimitiveType_TRIANGLE:
80 if((mesh = load_mesh(this, aiscn, flags, aimesh))) {
81 mesh_by_aimesh[aimesh] = mesh;
82 meshes.push_back(mesh);
87 error_log("unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
93 nodes = new SceneNode;
95 nodes->set_name("root");
96 nodes->set_position(root_pos);
97 nodes->set_rotation(root_rot);
98 nodes->set_scaling(root_scaling);
101 // load all the nodes recursively
102 for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
103 SceneNode *node = load_node(this, aiscn, flags, aiscn->mRootNode->mChildren[i]);
105 nodes->add_child(node);
109 node_by_name.clear();
110 mesh_by_aimesh.clear();
112 aiReleaseImport(aiscn);
113 info_log("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
118 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat)
122 float shin, shin_str;
124 if(aiGetMaterialString(aimat, AI_MATKEY_NAME, &name) == 0) {
125 mat->name = name.data;
127 mat->name = "unknown";
129 //info_log("load_material: %s\n", mat->name.c_str());
131 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
132 mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
134 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
135 mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
138 unsigned int count = 1;
139 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
142 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
143 // XXX can't remember how I came up with this...
144 mat->shininess = shin * shin_str * 0.0001 * 128.0;
149 const int num_tex_types = aiTextureType_UNKNOWN + 1;
150 for(int i=0; i<num_tex_types; i++) {
151 aiTextureType aitype = (aiTextureType)i;
152 int count = aiGetMaterialTextureCount(aimat, aitype);
154 for(int j=0; j<count; j++) {
156 if(aiGetMaterialTexture(aimat, aitype, j, &aipath) != 0) {
160 char *fname = (char*)alloca(strlen(aipath.data) + 1);
162 char *sptr = aipath.data;
164 *dptr++ = *sptr == '\\' ? '/' : *sptr;
167 int textype = assimp_textype(aitype);
168 info_log("loading %s texture: %s\n", assimp_textypestr(aitype), fname);
170 Texture *tex = scn->texset->get_texture(fname, TEX_2D);
172 mat->textures.push_back(tex);
174 if(textype != MTL_TEX_UNKNOWN && !mat->stdtex[textype]) {
175 mat->stdtex[textype] = tex;
183 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode)
185 SceneNode *node = new SceneNode;
186 node->set_name(ainode->mName.data);
189 Mat4 matrix = assimp_matrix(ainode->mTransformation);
190 Vec3 pos = matrix.get_translation();
191 Quat rot = matrix.get_rotation();
192 Vec3 scale = matrix.get_scaling();
194 node->set_position(pos);
195 node->set_rotation(rot);
196 node->set_scaling(scale);
197 node->dbg_xform = matrix;
200 for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
201 aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[i]];
203 Mesh *mesh = mesh_by_aimesh[aimesh];
205 ObjMesh *obj = new ObjMesh;
206 obj->set_name(mesh->get_name());
208 // also grab the material of this mesh
209 load_material(scn, &obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
211 node->add_object(obj);
212 scn->objects.push_back(obj);
216 /* recurse to all children */
217 for(unsigned int i=0; i<ainode->mNumChildren; i++) {
218 SceneNode *child = load_node(scn, aiscn, flags, ainode->mChildren[i]);
220 node->add_child(child);
224 node_by_name[node->get_name()] = node;
228 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh)
230 Mesh *mesh = new Mesh;
231 mesh->set_name(aimesh->mName.data);
233 int num_verts = aimesh->mNumVertices;
234 int num_faces = aimesh->mNumFaces;
236 mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
238 if(aimesh->mNormals) {
239 mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
241 if(aimesh->mTangents) {
242 mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
244 if(aimesh->mTextureCoords[0]) {
245 mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
247 if(aimesh->mTextureCoords[1]) {
248 mesh->set_attrib_data(MESH_ATTR_TEXCOORD2, 3, num_verts, (float*)aimesh->mTextureCoords[1]);
251 if(flags & SCNLOAD_FLIPYZ) {
252 Vec3 *vptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX);
253 for(int i=0; i<num_verts; i++) {
258 Vec3 *nptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_NORMAL);
259 for(int i=0; i<num_verts; i++) {
264 Vec3 *tptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_TANGENT);
265 for(int i=0; i<num_verts; i++) {
271 unsigned int *iptr = mesh->set_index_data(num_faces * 3);
272 for(int i=0; i<num_faces; i++) {
273 iptr[0] = aimesh->mFaces[i].mIndices[0];
274 iptr[1] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 2 : 1];
275 iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2];
281 static int assimp_textype(aiTextureType type)
284 case aiTextureType_DIFFUSE:
285 return MTL_TEX_DIFFUSE;
286 case aiTextureType_SPECULAR:
287 return MTL_TEX_SPECULAR;
288 case aiTextureType_NORMALS:
289 return MTL_TEX_NORMALMAP;
290 case aiTextureType_LIGHTMAP:
291 case aiTextureType_EMISSIVE:
292 return MTL_TEX_LIGHTMAP;
293 case aiTextureType_REFLECTION:
294 return MTL_TEX_ENVMAP;
298 return MTL_TEX_UNKNOWN;
301 static const char *assimp_textypestr(aiTextureType type)
304 case aiTextureType_DIFFUSE:
306 case aiTextureType_SPECULAR:
308 case aiTextureType_NORMALS:
310 case aiTextureType_LIGHTMAP:
311 case aiTextureType_EMISSIVE:
313 case aiTextureType_REFLECTION:
321 static Mat4 assimp_matrix(const aiMatrix4x4 &aim)
324 memcpy(m[0], &aim, 16 * sizeof(float));