assimp
[laserbrain_demo] / src / sceneload.cc
diff --git a/src/sceneload.cc b/src/sceneload.cc
new file mode 100644 (file)
index 0000000..b2b00eb
--- /dev/null
@@ -0,0 +1,275 @@
+#include <stdio.h>
+#include <vector>
+#include <map>
+#include <gmath/gmath.h>
+#include <assimp/cimport.h>
+#include <assimp/postprocess.h>
+#include <assimp/scene.h>
+#include <assimp/mesh.h>
+#include <assimp/material.h>
+#include <assimp/anim.h>
+#include <assimp/vector3.h>
+#include <assimp/matrix4x4.h>
+#include <assimp/quaternion.h>
+#include "scene.h"
+#include "objmesh.h"
+
+static bool load_material(Material *mat, const aiMaterial *aimat);
+static SceneNode *load_node(const aiScene *aiscn, const aiNode *ainode);
+static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh);
+
+/*static Vec3 assimp_vector(const aiVector3D &v);
+static Quat assimp_quat(const aiQuaternion &q);
+static Mat4 assimp_matrix(const aiMatrix4x4 &aim);
+static long assimp_time(const aiAnimation *anim, double aitime);
+static void print_hierarchy(const aiNode *node);
+*/
+
+static std::map<std::string, SceneNode*> node_by_name;
+static std::map<aiMesh*, Mesh*> mesh_by_aimesh;
+
+bool Scene::load(const char *fname)
+{
+       unsigned int ppflags = aiProcess_CalcTangentSpace |
+               aiProcess_GenNormals |
+               aiProcess_JoinIdenticalVertices |
+               aiProcess_Triangulate |
+               aiProcess_SortByPType |
+               aiProcess_TransformUVCoords;
+
+       const aiScene *aiscn = aiImportFile(fname, ppflags);
+       if(!aiscn) {
+               fprintf(stderr, "failed to load scene file: %s\n", fname);
+               return false;
+       }
+
+       /*
+       Vec3 root_pos, root_scaling(1.0, 1.0, 1.0);
+       Quat root_rot;
+
+       if(aiscn->mRootNode) {
+               Mat4 root_matrix = assimp_matrix(aiscn->mRootNode->mTransformation);
+               root_pos = root_matrix.get_translation();
+               root_rot = root_matrix.get_rotation_quat();
+               root_scaling = root_matrix.get_scaling();
+       }*/
+
+       // load all meshes
+       for(unsigned int i=0; i<aiscn->mNumMeshes; i++) {
+               aiMesh *aimesh = aiscn->mMeshes[i];
+               Mesh *mesh;
+
+               switch(aimesh->mPrimitiveTypes) {
+               case aiPrimitiveType_TRIANGLE:
+                       if((mesh = load_mesh(aiscn, aimesh))) {
+                               mesh_by_aimesh[aimesh] = mesh;
+                               meshes.push_back(mesh);
+                       }
+                       break;
+
+               default:
+                       fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes);
+                       break;
+               }
+       }
+
+       SceneNode *root = new SceneNode;
+
+       // load all the nodes recursively
+       for(unsigned int i=0; i<aiscn->mRootNode->mNumChildren; i++) {
+               SceneNode *node = load_node(aiscn, aiscn->mRootNode->mChildren[i]);
+               if(node) {
+                       root->add_child(node);
+               }
+       }
+
+       int nnodes = root->get_num_children();
+       if(nnodes <= 0) {
+               delete root;
+       } else if(nnodes == 1) {
+               nodes = root->get_child(0);
+               root->remove_child(nodes);
+               delete root;
+       } else {
+               nodes = root;
+       }
+
+       node_by_name.clear();
+       mesh_by_aimesh.clear();
+
+       aiReleaseImport(aiscn);
+       printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size());
+       return true;
+}
+
+static bool load_material(Material *mat, const aiMaterial *aimat)
+{
+       aiColor4D aicol;
+       float shin, shin_str;
+
+       if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) {
+               mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]);
+       }
+       if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_SPECULAR, &aicol) == 0) {
+               mat->specular = Vec3(aicol[0], aicol[1], aicol[2]);
+       }
+
+       unsigned int count = 1;
+       if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS_STRENGTH, &shin_str, &count) != 0) {
+               shin_str = 1.0;
+       }
+       if(aiGetMaterialFloatArray(aimat, AI_MATKEY_SHININESS, &shin, &count) == 0) {
+               // XXX can't remember how I came up with this...
+               mat->shininess = shin * shin_str * 0.0001 * 128.0;
+       }
+
+       /*
+       // load textures
+       struct { int type; aiTextureType aitype; } textypes[] = {
+               {TEX_DIFFUSE, aiTextureType_DIFFUSE},
+               {TEX_NORMAL, aiTextureType_NORMALS},
+               {TEX_SPECULAR, aiTextureType_SPECULAR}
+       };
+
+       for(size_t i=0; i<sizeof textypes / sizeof *textypes; i++) {
+               aiString aipath;
+
+               if(aiGetMaterialTexture(aimat, textypes[i].aitype, 0, &aipath) == 0) {
+                       char *tmp, *fname = aipath.data;
+
+                       if((tmp = strrchr(fname, '/'))) {
+                               fname = tmp + 1;
+                       }
+                       if((tmp = strrchr(fname, '\\'))) {
+                               fname = tmp + 1;
+                       }
+
+                       if(*fname) {
+                               mat->tex[textypes[i].type] = texset.get(fname);
+                       }
+               }
+       }
+       */
+
+       return true;
+}
+
+static SceneNode *load_node(const aiScene *aiscn, const aiNode *ainode)
+{
+       SceneNode *node = new SceneNode;
+       node->set_name(ainode->mName.data);
+
+       for(unsigned int i=0; i<ainode->mNumMeshes; i++) {
+               aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]];
+
+               Mesh *mesh = mesh_by_aimesh[aimesh];
+               if(mesh) {
+                       ObjMesh *obj = new ObjMesh;
+                       obj->mesh = mesh;
+                       // also grab the material of this mesh
+                       load_material(&obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]);
+
+                       node->add_object(obj);
+               }
+       }
+
+       /* recurse to all children */
+       for(unsigned int i=0; i<ainode->mNumChildren; i++) {
+               SceneNode *child = load_node(aiscn, ainode->mChildren[i]);
+               if(child) {
+                       node->add_child(child);
+               }
+       }
+
+       node_by_name[node->get_name()] = node;
+       return node;
+}
+
+static Mesh *load_mesh(const aiScene *aiscn, const aiMesh *aimesh)
+{
+       Mesh *mesh = new Mesh;
+
+       int num_verts = aimesh->mNumVertices;
+       int num_faces = aimesh->mNumFaces;
+
+       mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)aimesh->mVertices);
+
+       if(aimesh->mNormals) {
+               mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)aimesh->mNormals);
+       }
+       if(aimesh->mTangents) {
+               mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, (float*)aimesh->mTangents);
+       }
+       if(aimesh->mTextureCoords[0]) {
+               mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]);
+       }
+
+       unsigned int *iptr = mesh->set_index_data(num_faces * 3);
+       for(int i=0; i<num_faces; i++) {
+               for(int j=0; j<3; j++) {
+                       *iptr++ = aimesh->mFaces[i].mIndices[j];
+               }
+       }
+
+       return mesh;
+}
+
+#if 0
+static Vec3 assimp_vector(const aiVector3D &v)
+{
+       return Vec3(v[0], v[1], v[2]);
+}
+
+static Quat assimp_quat(const aiQuaternion &q)
+{
+       return Quat(q.x, q.y, q.z, q.w);
+}
+
+static Mat4 assimp_matrix(const aiMatrix4x4 &aim)
+{
+       Mat4 m;
+       memcpy(m[0], &aim, 16 * sizeof(float));
+       m.transpose();
+       return m;
+}
+
+/* convert an assimp keyframe time (ticks) into milliseconds */
+static long assimp_time(const aiAnimation *anim, double aitime)
+{
+       double sec;
+       if(anim->mTicksPerSecond < 1e-6) {
+               // assume time is in frames?
+               sec = aitime / 30.0;
+       } else {
+               sec = aitime / anim->mTicksPerSecond;
+       }
+       return (long)(sec * 1000.0);
+}
+
+static void print_hierarchy(const aiNode *node)
+{
+       static int lvl;
+       static int lvlopen[256];
+
+       for(int i=0; i<lvl; i++) {
+               putchar(' ');
+               if(lvlopen[i]) {
+                       putchar(i >= lvl - 1 ? '+' : '|');
+               } else {
+                       putchar(i >= lvl - 1 ? '+' : ' ');
+               }
+       }
+       printf("- \"%s\"\n", node->mName.data);
+
+       lvlopen[lvl] = 1;
+
+       lvl++;
+       for(unsigned int i=0; i<node->mNumChildren; i++) {
+               if(i == node->mNumChildren - 1) {
+                       lvlopen[lvl - 1] = 0;
+               }
+               print_hierarchy(node->mChildren[i]);
+       }
+       lvl--;
+}
+#endif /* 0 */