X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=blobdiff_plain;f=src%2Fsceneload.cc;h=a48838563a93de30add938b509ef64afbcd97d2f;hp=5179e4ac616b646af291ae37fe551aadb5159a45;hb=2a5c3d461a983818c82424eef9eeb14761f8b07e;hpb=ab9fd0ac34f8107ff8067607fad229d08b1c3935 diff --git a/src/sceneload.cc b/src/sceneload.cc index 5179e4a..a488385 100644 --- a/src/sceneload.cc +++ b/src/sceneload.cc @@ -1,8 +1,11 @@ #include +#include +#include #include #include #include #include +#include #include #include #include @@ -11,106 +14,174 @@ #include #include #include +#include "assfile.h" +#include "app.h" #include "scene.h" #include "objmesh.h" +#include "datamap.h" +#include "logger.h" +#include "metascene.h" + +static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat); +static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode); +static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh); +/*static const char *mprop_semantic(int x); +static int count_textures(const aiMaterial *aimat);*/ +static int assimp_textype(aiTextureType type); +//static const char *assimp_textypestr(aiTextureType type); -static bool load_material(Material *mat, const aiMaterial *aimat); -static SceneNode *load_node(const aiScene *aiscn, unsigned int flags, const aiNode *ainode); -static Mesh *load_mesh(const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh); +static Mat4 assimp_matrix(const aiMatrix4x4 &aim); /*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 node_by_name; -static std::map mesh_by_aimesh; +static aiFile *io_open(aiFileIO *io, const char *fname, const char *mode); +static void io_close(aiFileIO *io, aiFile *aifp); +static size_t io_read(aiFile *aifp, char *buf, size_t size, size_t count); +static size_t io_tell(aiFile *aifp); +static size_t io_filesize(aiFile *aifp); +static aiReturn io_seek(aiFile *aifp, size_t offs, aiOrigin whence); + +struct LoaderData { + const aiScene *aiscn; + std::string fname; + std::map node_by_name; + std::map mesh_by_aimesh; +}; + +#define LD_STAGE_MASK 0xf000 bool Scene::load(const char *fname, unsigned int flags) { - unsigned int ppflags = aiProcess_CalcTangentSpace | - aiProcess_GenNormals | - aiProcess_JoinIdenticalVertices | - aiProcess_Triangulate | - aiProcess_SortByPType | - aiProcess_TransformUVCoords | aiProcess_PreTransformVertices; - - if(flags & SCNLOAD_FLIPTEX) { - ppflags |= aiProcess_FlipUVs; + if((flags & LD_STAGE_MASK) == 0) { + // not passing either of the stage specifiers, means do the whole job + flags |= LD_STAGE_MASK; } - const aiScene *aiscn = aiImportFile(fname, ppflags); - if(!aiscn) { - fprintf(stderr, "failed to load scene file: %s\n", fname); - return false; - } + // first perform I/O and all operations not requiring access to an OpenGL context + if(flags & SCNLOAD_STAGE_IO) { + unsigned int ppflags = aiProcess_CalcTangentSpace | + aiProcess_GenNormals | + aiProcess_JoinIdenticalVertices | + aiProcess_Triangulate | + aiProcess_SortByPType | + aiProcess_GenUVCoords | + //aiProcess_PreTransformVertices | + aiProcess_TransformUVCoords; + + if(flags & SCNLOAD_FLIPTEX) { + ppflags |= aiProcess_FlipUVs; + } - /* - 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; imNumMeshes; i++) { - aiMesh *aimesh = aiscn->mMeshes[i]; - Mesh *mesh; - - switch(aimesh->mPrimitiveTypes) { - case aiPrimitiveType_TRIANGLE: - if((mesh = load_mesh(aiscn, flags, aimesh))) { - mesh_by_aimesh[aimesh] = mesh; - meshes.push_back(mesh); - } - break; + info_log("Loading scene file: %s\n", fname); + if(this->name.empty()) { + this->name = std::string(fname); + } - default: - fprintf(stderr, "unsupported primitive type: %u\n", aimesh->mPrimitiveTypes); - break; + aiFileIO io; + io.OpenProc = io_open; + io.CloseProc = io_close; + + const aiScene *aiscn = aiImportFileEx(fname, ppflags, &io); + if(!aiscn) { + error_log("failed to load scene file: %s\n", fname); + return false; } + + LoaderData *ldata = new LoaderData; + ldata->aiscn = aiscn; + ldata->fname = std::string(fname); + loader_data = (void*)ldata; } - SceneNode *root = new SceneNode; + /* then, assuming we have successfully loaded everything, proceed to construct + * all the engine objects, which require access to the OpenGL context + */ + if(flags & SCNLOAD_STAGE_GL) { + if(!loader_data) { + error_log("second stage scene loader failed to find valid I/O data\n"); + return false; + } + + LoaderData *ldata = (LoaderData*)loader_data; + const aiScene *aiscn = ldata->aiscn; + fname = ldata->fname.c_str(); + + clear(); // clear any previous data (TODO: add flag for not clearing) - // load all the nodes recursively - for(unsigned int i=0; imRootNode->mNumChildren; i++) { - SceneNode *node = load_node(aiscn, flags, aiscn->mRootNode->mChildren[i]); - if(node) { - root->add_child(node); + // assimp adds its own root node, which might have transformations + 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(); + root_scaling = root_matrix.get_scaling(); } - } - 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; - } + if(!nodes) { + nodes = new SceneNode; + nodes->scene = this; + nodes->set_name("root"); + nodes->set_position(root_pos); + nodes->set_rotation(root_rot); + nodes->set_scaling(root_scaling); + } + + // load all meshes + for(unsigned int i=0; imNumMeshes; i++) { + aiMesh *aimesh = aiscn->mMeshes[i]; + Mesh *mesh; + + switch(aimesh->mPrimitiveTypes) { + case aiPrimitiveType_TRIANGLE: + if((mesh = load_mesh(this, aiscn, flags, aimesh))) { + ldata->mesh_by_aimesh[aimesh] = mesh; + meshes.push_back(mesh); + } + break; + + default: + error_log("unsupported primitive type: %u\n", aimesh->mPrimitiveTypes); + break; + } + } + + // load all the nodes recursively + for(unsigned int i=0; imRootNode->mNumChildren; i++) { + SceneNode *node = load_node(this, aiscn, flags, aiscn->mRootNode->mChildren[i]); + if(node) { + nodes->add_child(node); + } + } - node_by_name.clear(); - mesh_by_aimesh.clear(); + info_log("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size()); - aiReleaseImport(aiscn); - printf("loaded scene file: %s, %d meshes\n", fname, (int)meshes.size()); + aiReleaseImport(aiscn); + delete ldata; + loader_data = 0; + nodes->update(0); + } return true; } -static bool load_material(Material *mat, const aiMaterial *aimat) +static bool load_material(Scene *scn, Material *mat, const aiMaterial *aimat) { + aiString name; aiColor4D aicol; float shin, shin_str; + if(aiGetMaterialString(aimat, AI_MATKEY_NAME, &name) == 0) { + mat->name = name.data; + } else { + mat->name = "unknown"; + } + //info_log("load_material: %s\n", mat->name.c_str()); + if(aiGetMaterialColor(aimat, AI_MATKEY_COLOR_DIFFUSE, &aicol) == 0) { mat->diffuse = Vec3(aicol[0], aicol[1], aicol[2]); } @@ -127,71 +198,94 @@ static bool load_material(Material *mat, const aiMaterial *aimat) 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; itex[textypes[i].type] = texset.get(fname); + char *fname = (char*)alloca(strlen(aipath.data) + 1); + char *dptr = fname; + char *sptr = aipath.data; + do { + *dptr++ = *sptr == '\\' ? '/' : *sptr; + } while(*sptr++); + + if(!fname || !*fname) continue; + + int textype = assimp_textype(aitype); + + Texture *tex = texman.get_texture(fname, TEX_2D, &scn->datamap); + assert(tex); + mat->textures.push_back(tex); + + if(textype != MTL_TEX_UNKNOWN && !mat->stdtex[textype]) { + mat->stdtex[textype] = tex; } } } - */ return true; } -static SceneNode *load_node(const aiScene *aiscn, unsigned int flags, const aiNode *ainode) +static SceneNode *load_node(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiNode *ainode) { + LoaderData *ldata = (LoaderData*)scn->loader_data; + SceneNode *node = new SceneNode; node->set_name(ainode->mName.data); + // transformation + Mat4 matrix = assimp_matrix(ainode->mTransformation); + Vec3 pos = matrix.get_translation(); + Quat rot = matrix.get_rotation(); + Vec3 scale = matrix.get_scaling(); + + node->set_position(pos); + node->set_rotation(rot); + node->set_scaling(scale); + node->dbg_xform = matrix; + + // meshes for(unsigned int i=0; imNumMeshes; i++) { - aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[0]]; + aiMesh *aimesh = aiscn->mMeshes[ainode->mMeshes[i]]; - Mesh *mesh = mesh_by_aimesh[aimesh]; + Mesh *mesh = ldata->mesh_by_aimesh[aimesh]; if(mesh) { ObjMesh *obj = new ObjMesh; + obj->set_name(mesh->get_name()); obj->mesh = mesh; // also grab the material of this mesh - load_material(&obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]); + load_material(scn, &obj->mtl, aiscn->mMaterials[aimesh->mMaterialIndex]); node->add_object(obj); + scn->objects.push_back(obj); } } /* recurse to all children */ for(unsigned int i=0; imNumChildren; i++) { - SceneNode *child = load_node(aiscn, flags, ainode->mChildren[i]); + SceneNode *child = load_node(scn, aiscn, flags, ainode->mChildren[i]); if(child) { node->add_child(child); } } - node_by_name[node->get_name()] = node; + ldata->node_by_name[node->get_name()] = node; return node; } -static Mesh *load_mesh(const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh) +static Mesh *load_mesh(Scene *scn, const aiScene *aiscn, unsigned int flags, const aiMesh *aimesh) { Mesh *mesh = new Mesh; + mesh->set_name(aimesh->mName.data); int num_verts = aimesh->mNumVertices; int num_faces = aimesh->mNumFaces; @@ -207,6 +301,9 @@ static Mesh *load_mesh(const aiScene *aiscn, unsigned int flags, const aiMesh *a if(aimesh->mTextureCoords[0]) { mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 3, num_verts, (float*)aimesh->mTextureCoords[0]); } + if(aimesh->mTextureCoords[1]) { + mesh->set_attrib_data(MESH_ATTR_TEXCOORD2, 3, num_verts, (float*)aimesh->mTextureCoords[1]); + } if(flags & SCNLOAD_FLIPYZ) { Vec3 *vptr = (Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX); @@ -235,66 +332,140 @@ static Mesh *load_mesh(const aiScene *aiscn, unsigned int flags, const aiMesh *a iptr[2] = aimesh->mFaces[i].mIndices[flags & SCNLOAD_FLIPYZ ? 1 : 2]; iptr += 3; } - return mesh; } -#if 0 -static Vec3 assimp_vector(const aiVector3D &v) +static int assimp_textype(aiTextureType type) { - return Vec3(v[0], v[1], v[2]); + switch(type) { + case aiTextureType_DIFFUSE: + return MTL_TEX_DIFFUSE; + case aiTextureType_SPECULAR: + return MTL_TEX_SPECULAR; + case aiTextureType_NORMALS: + return MTL_TEX_NORMALMAP; + case aiTextureType_LIGHTMAP: + case aiTextureType_EMISSIVE: + return MTL_TEX_LIGHTMAP; + case aiTextureType_REFLECTION: + return MTL_TEX_REFLECT; + default: + break; + } + return MTL_TEX_UNKNOWN; } -static Quat assimp_quat(const aiQuaternion &q) +/*static const char *assimp_textypestr(aiTextureType type) { - return Quat(q.x, q.y, q.z, q.w); -} + switch(type) { + case aiTextureType_DIFFUSE: + return "diffuse"; + case aiTextureType_SPECULAR: + return "specular"; + case aiTextureType_NORMALS: + return "normalmap"; + case aiTextureType_LIGHTMAP: + case aiTextureType_EMISSIVE: + return "lightmap"; + case aiTextureType_REFLECTION: + return "envmap"; + default: + break; + } + return "unknown"; +}*/ static Mat4 assimp_matrix(const aiMatrix4x4 &aim) { Mat4 m; memcpy(m[0], &aim, 16 * sizeof(float)); - m.transpose(); - return m; + return transpose(m); +} + + +// --- SceneSet --- + +SceneSet::SceneSet() + : DataSet(create_scene, load_scene, done_scene, free_scene) +{ } -/* convert an assimp keyframe time (ticks) into milliseconds */ -static long assimp_time(const aiAnimation *anim, double aitime) +Scene *SceneSet::create_scene() { - double sec; - if(anim->mTicksPerSecond < 1e-6) { - // assume time is in frames? - sec = aitime / 30.0; - } else { - sec = aitime / anim->mTicksPerSecond; + return new Scene; +} + +bool SceneSet::load_scene(Scene *scn, const char *fname) +{ + return scn->load(fname, SCNLOAD_FLIPTEX | SCNLOAD_STAGE_IO); +} + +bool SceneSet::done_scene(Scene *scn) +{ + bool res = scn->load(0, SCNLOAD_STAGE_GL); + if(scn->metascn) { + scn->metascn->scene_loaded(scn); } - return (long)(sec * 1000.0); + return res; } -static void print_hierarchy(const aiNode *node) +void SceneSet::free_scene(Scene *scn) { - static int lvl; - static int lvlopen[256]; - - for(int i=0; i= lvl - 1 ? '+' : '|'); - } else { - putchar(i >= lvl - 1 ? '+' : ' '); - } + delete scn; +} + + +// ------ custom file I/O for assimp ------- + +static aiFile *io_open(aiFileIO *io, const char *fname, const char *mode) +{ + ass_file *fp; + if(!(fp = ass_fopen(fname, mode))) { + error_log("failed to open scene file: %s: %s\n", fname, strerror(ass_errno)); + return 0; } - printf("- \"%s\"\n", node->mName.data); - lvlopen[lvl] = 1; + aiFile *aifp = new aiFile; + aifp->ReadProc = io_read; + aifp->WriteProc = 0; + aifp->TellProc = io_tell; + aifp->FileSizeProc = io_filesize; + aifp->SeekProc = io_seek; + aifp->FlushProc = 0; + aifp->UserData = (aiUserData)fp; + return aifp; +} - lvl++; - for(unsigned int i=0; imNumChildren; i++) { - if(i == node->mNumChildren - 1) { - lvlopen[lvl - 1] = 0; - } - print_hierarchy(node->mChildren[i]); +static void io_close(aiFileIO *io, aiFile *aifp) +{ + ass_fclose(aifp->UserData); + delete aifp; +} + +static size_t io_read(aiFile *aifp, char *buf, size_t size, size_t count) +{ + return ass_fread(buf, size, count, aifp->UserData); +} + +static size_t io_tell(aiFile *aifp) +{ + return ass_ftell(aifp->UserData); +} + +static size_t io_filesize(aiFile *aifp) +{ + ass_file *fp = aifp->UserData; + long cur = ass_ftell(fp); + ass_fseek(fp, 0, SEEK_END); + long off = ass_ftell(fp); + ass_fseek(fp, cur, SEEK_SET); + return off; +} + +static aiReturn io_seek(aiFile *aifp, size_t offs, aiOrigin whence) +{ + if(ass_fseek(aifp->UserData, offs, (int)whence) == -1) { + return aiReturn_FAILURE; } - lvl--; + return aiReturn_SUCCESS; } -#endif /* 0 */