6 #include <gmath/gmath.h>
7 #include <assimp/cimport.h>
8 #include <assimp/postprocess.h>
9 #include <assimp/scene.h>
10 #include <assimp/mesh.h>
11 #include <assimp/material.h>
12 #include <assimp/anim.h>
13 #include <assimp/vector3.h>
14 #include <assimp/matrix4x4.h>
15 #include <assimp/quaternion.h>
21 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat);
22 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode);
23 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh);
24 /*static const char *mprop_semantic(int x);
25 static int count_textures(const aiMaterial *aimat);*/
26 static int assimp_textype(aiTextureType type);
27 static const char *assimp_textypestr(aiTextureType type);
29 static Mat4 assimp_matrix(const aiMatrix4x4 &aim);
31 /*static Vec3 assimp_vector(const aiVector3D &v);
32 static Quat assimp_quat(const aiQuaternion &q);
33 static long assimp_time(const aiAnimation *anim, double aitime);
34 static void print_hierarchy(const aiNode *node);
40 std::map<std::string, SceneNode*> node_by_name;
41 std::map<aiMesh*, Mesh*> mesh_by_aimesh;
44 #define LD_STAGE_MASK 0xf000
46 bool Scene::load(const char *fname, unsigned int flags)
48 if((flags & LD_STAGE_MASK) == 0) {
49 // not passing either of the stage specifiers, means do the whole job
50 flags |= LD_STAGE_MASK;
53 // first perform I/O and all operations not requiring access to an OpenGL context
54 if(flags & SCNLOAD_STAGE_IO) {
55 unsigned int ppflags = aiProcess_CalcTangentSpace |
56 aiProcess_GenNormals |
57 aiProcess_JoinIdenticalVertices |
58 aiProcess_Triangulate |
59 aiProcess_SortByPType |
60 aiProcess_GenUVCoords |
61 //aiProcess_PreTransformVertices |
62 aiProcess_TransformUVCoords;
64 if(flags & SCNLOAD_FLIPTEX) {
65 ppflags |= aiProcess_FlipUVs;
68 info_log("Loading scene file: %s\n", fname);
70 const aiScene *aiscn = aiImportFile(fname, ppflags);
72 error_log("failed to load scene file: %s\n", fname);
76 // assimp adds its own root node, which might have transformations
77 Vec3 root_pos, root_scaling(1.0, 1.0, 1.0);
80 if(aiscn->mRootNode) {
81 Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
82 root_pos = root_matrix.get_translation();
83 root_rot = root_matrix.get_rotation();
84 root_scaling = root_matrix.get_scaling();
88 nodes = new SceneNode;
90 nodes->set_name("root");
91 nodes->set_position(root_pos);
92 nodes->set_rotation(root_rot);
93 nodes->set_scaling(root_scaling);
96 LoaderData *ldata = new LoaderData;
98 ldata->fname = std::string(fname);
99 loader_data = (void*)ldata;
102 /* then, assuming we have successfully loaded everything, proceed to construct
103 * all the engine objects, which require access to the OpenGL context
105 if(flags & SCNLOAD_STAGE_GL) {
107 error_log("second stage scene loader failed to find valid I/O data\n");
111 LoaderData *ldata = (LoaderData*)loader_data;
112 const aiScene *aiscn = ldata->aiscn;
113 fname = ldata->fname.c_str();
116 for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
117 aiMesh *aimesh = aiscn->mMeshes[i];
120 switch(aimesh->mPrimitiveTypes) {
121 case aiPrimitiveType_TRIANGLE:
122 if((mesh = load_mesh(this, aiscn, flags, aimesh))) {
123 ldata->mesh_by_aimesh[aimesh] = mesh;
124 meshes.push_back(mesh);
129 error_log("unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
134 // load all the nodes recursively
135 for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
136 SceneNode *node = load_node(this, aiscn, flags, aiscn->mRootNode->mChildren[i]);
138 nodes->add_child(node);
142 info_log("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
144 aiReleaseImport(aiscn);
152 static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat)
156 float shin, shin_str;
158 if(aiGetMaterialString(aimat, AI_MATKEY_NAME, &name) == 0) {
159 mat->name = name.data;
161 mat->name = "unknown";
163 //info_log("load_material: %s\n", mat->name.c_str());
165 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
166 mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
168 if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
169 mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
172 unsigned int count = 1;
173 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
176 if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
177 // XXX can't remember how I came up with this...
178 mat->shininess = shin * shin_str * 0.0001 * 128.0;
183 const int num_tex_types = aiTextureType_UNKNOWN + 1;
184 for(int i=0; i<num_tex_types; i++) {
185 aiTextureType aitype = (aiTextureType)i;
186 int count = aiGetMaterialTextureCount(aimat, aitype);
188 for(int j=0; j<count; j++) {
190 if(aiGetMaterialTexture(aimat, aitype, j, &aipath) != 0) {
194 char *fname = (char*)alloca(strlen(aipath.data) + 1);
196 char *sptr = aipath.data;
198 *dptr++ = *sptr == '\\' ? '/' : *sptr;
201 int textype = assimp_textype(aitype);
202 info_log("loading %s texture: %s\n", assimp_textypestr(aitype), fname);
204 Texture *tex = scn->texset->get_texture(fname, TEX_2D);
206 mat->textures.push_back(tex);
208 if(textype != MTL_TEX_UNKNOWN && !mat->stdtex[textype]) {
209 mat->stdtex[textype] = tex;
217 static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode)
219 LoaderData *ldata = (LoaderData*)scn->loader_data;
221 SceneNode *node = new SceneNode;
222 node->set_name(ainode->mName.data);
225 Mat4 matrix = assimp_matrix(ainode->mTransformation);
226 Vec3 pos = matrix.get_translation();
227 Quat rot = matrix.get_rotation();
228 Vec3 scale = matrix.get_scaling();
230 node->set_position(pos);
231 node->set_rotation(rot);
232 node->set_scaling(scale);
233 node->dbg_xform = matrix;
236 for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
237 aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[i]];
239 Mesh *mesh = ldata->mesh_by_aimesh[aimesh];
241 ObjMesh *obj = new ObjMesh;
242 obj->set_name(mesh->get_name());
244 // also grab the material of this mesh
245 load_material(scn, &obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
247 node->add_object(obj);
248 scn->objects.push_back(obj);
252 /* recurse to all children */
253 for(unsigned int i=0; i<ainode->mNumChildren; i++) {
254 SceneNode *child = load_node(scn, aiscn, flags, ainode->mChildren[i]);
256 node->add_child(child);
260 ldata->node_by_name[node->get_name()] = node;
264 static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh)
266 Mesh *mesh = new Mesh;
267 mesh->set_name(aimesh->mName.data);
269 int num_verts = aimesh->mNumVertices;
270 int num_faces = aimesh->mNumFaces;
272 mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
274 if(aimesh->mNormals) {
275 mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
277 if(aimesh->mTangents) {
278 mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
280 if(aimesh->mTextureCoords[0]) {
281 mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
283 if(aimesh->mTextureCoords[1]) {
284 mesh->set_attrib_data(MESH_ATTR_TEXCOORD2, 3, num_verts, (float*)aimesh->mTextureCoords[1]);
287 if(flags & SCNLOAD_FLIPYZ) {
288 Vec3 *vptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX);
289 for(int i=0; i<num_verts; i++) {
294 Vec3 *nptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_NORMAL);
295 for(int i=0; i<num_verts; i++) {
300 Vec3 *tptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_TANGENT);
301 for(int i=0; i<num_verts; i++) {
307 unsigned int *iptr = mesh->set_index_data(num_faces * 3);
308 for(int i=0; i<num_faces; i++) {
309 iptr[0] = aimesh->mFaces[i].mIndices[0];
310 iptr[1] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 2 : 1];
311 iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2];
317 static int assimp_textype(aiTextureType type)
320 case aiTextureType_DIFFUSE:
321 return MTL_TEX_DIFFUSE;
322 case aiTextureType_SPECULAR:
323 return MTL_TEX_SPECULAR;
324 case aiTextureType_NORMALS:
325 return MTL_TEX_NORMALMAP;
326 case aiTextureType_LIGHTMAP:
327 case aiTextureType_EMISSIVE:
328 return MTL_TEX_LIGHTMAP;
329 case aiTextureType_REFLECTION:
330 return MTL_TEX_ENVMAP;
334 return MTL_TEX_UNKNOWN;
337 static const char *assimp_textypestr(aiTextureType type)
340 case aiTextureType_DIFFUSE:
342 case aiTextureType_SPECULAR:
344 case aiTextureType_NORMALS:
346 case aiTextureType_LIGHTMAP:
347 case aiTextureType_EMISSIVE:
349 case aiTextureType_REFLECTION:
357 static Mat4 assimp_matrix(const aiMatrix4x4 &aim)
360 memcpy(m[0], &aim, 16 * sizeof(float));
368 : DataSet<Scene*>(create_scene, load_scene, done_scene, free_scene)
372 Scene *SceneSet::create_scene()
377 bool SceneSet::load_scene(Scene *scn, const char *fname)
379 return scn->load(fname, SCNLOAD_FLIPTEX | SCNLOAD_STAGE_IO);
382 bool SceneSet::done_scene(Scene *scn)
384 return scn->load(0, SCNLOAD_STAGE_GL);
387 void SceneSet::free_scene(Scene *scn)