// ---------------------------------------------------------------------------- // Simple sample to prove that Assimp is absolutely easy to use with OpenGL. // It takes a file name as command line parameter, loads it using standard // settings and displays it. // // If you intend to _use_ this code sample in your app, do yourself a favour // and replace immediate mode calls with VBOs ... // // The vc8 solution links against assimp-release-dll_win32 - be sure to // have this configuration built. // ---------------------------------------------------------------------------- #include "GL/glut.h" // assimp include files. These three are usually needed. #include "assimp.h" #include "aiPostProcess.h" #include "aiScene.h" // the global Assimp scene object const struct aiScene* scene = NULL; struct aiVector3D scene_min,scene_max; // current rotation angle static float angle = 0.f; #define aisgl_min(x,y) (xx?y:x) // ---------------------------------------------------------------------------- void reshape(int width, int height) { const double aspectRatio = (float) width / height, fieldOfView = 45.0; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fieldOfView, aspectRatio, 1.0, 1000.0); /* Znear and Zfar */ glViewport(0, 0, width, height); } // ---------------------------------------------------------------------------- void get_bounding_box_for_node (const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo ){ struct aiMatrix4x4 prev; unsigned int n = 0, t; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { struct aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); min->y = aisgl_min(min->y,tmp.y); min->z = aisgl_min(min->z,tmp.z); max->x = aisgl_max(max->x,tmp.x); max->y = aisgl_max(max->y,tmp.y); max->z = aisgl_max(max->z,tmp.z); } } prev = nd->mTransformation; for (n = 0; n < nd->mNumChildren; ++n) { get_bounding_box_for_node(nd->mChildren[n],min,max,trafo); } *trafo = prev; } // ---------------------------------------------------------------------------- void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) { struct aiMatrix4x4 trafo; aiIdentityMatrix4(&trafo); min->x = min->y = min->z = 1e10f; max->x = max->y = max->z = -1e10f; get_bounding_box_for_node(scene->mRootNode,min,max,&trafo); } // ---------------------------------------------------------------------------- void recursive_render (const struct aiNode* nd) { unsigned int n = 0, t; struct aiMatrix4x4 m = nd->mTransformation; // update transform aiTransposeMatrix4(&m); glMultMatrixf((float*)&m); // draw all meshes assigned to this node for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; glBegin(GL_TRIANGLES); for (t = 0; t < mesh->mNumFaces; ++t) { const struct aiFace* face = &mesh->mFaces[t]; glColor3f(1.f,0.f,0.f); glVertex3fv(&mesh->mVertices[face->mIndices[0]].x); glVertex3fv(&mesh->mVertices[face->mIndices[1]].x); glVertex3fv(&mesh->mVertices[face->mIndices[2]].x); } glEnd(); } // draw all children for (n = 0; n < nd->mNumChildren; ++n) { recursive_render(nd->mChildren[n]); } } // ---------------------------------------------------------------------------- void do_motion (void) { static GLint prev_time = 0; int time = glutGet(GLUT_ELAPSED_TIME); angle += (time-prev_time)*0.01; prev_time = time; glutPostRedisplay (); } // ---------------------------------------------------------------------------- void display(void) { float tmp; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f); // scale the whole asset to fit into our view frustum tmp = scene_max.x-scene_min.x; tmp = aisgl_max(scene_max.y-scene_min.y,tmp); tmp = aisgl_max(scene_max.z-scene_min.z,tmp); tmp = 1.f/(tmp); glScalef(tmp,tmp,tmp); // fixme: center around origin // rotate it around the y axis glRotatef(angle,0.f,1.f,0.f); // now begin at the root node of the imported data and traverse // the scenegraph by multipliying subsequent local transforms // together on GL's matrix stack. recursive_render(scene->mRootNode); glutSwapBuffers(); do_motion(); } // ---------------------------------------------------------------------------- int loadasset (const char* path) { // we are taking one of the postprocessing presets to avoid // writing 20 single postprocessing flags here. scene = aiImportFile(path,aiProcessPreset_TargetRealtime_Quality); if (scene) { get_bounding_box(&scene_min,&scene_max); return 0; } return 1; } // ---------------------------------------------------------------------------- int main(int argc, char **argv) { struct aiLogStream stream; glutInitWindowSize(900,600); glutInitWindowPosition(100,100); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInit(&argc, argv); glutCreateWindow("Assimp - Very simple OpenGL sample"); glutDisplayFunc(display); glutReshapeFunc(reshape); // get a handle to the predefined STDOUT log stream and attach // it to the logging system. It will be active for all further // calls to aiImportFile(Ex) and aiApplyPostProcessing. stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); aiAttachLogStream(&stream); // ... exactly the same, but this stream will now write the // log file to assimp_log.txt stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt"); aiAttachLogStream(&stream); if( 0 != loadasset( argc >= 2 ? argv[1] : "../../test/models/X/dwarf.x")) { if( argc != 1 || 0 != loadasset( "../../../../test/models/X/dwarf.x")) { return -1; } } glPolygonMode(GL_FRONT,GL_LINE); glPolygonMode(GL_BACK,GL_LINE); glClearColor(0.1f,0.1f,0.1f,1.f); glutGet(GLUT_ELAPSED_TIME); glutMainLoop(); // cleanup - calling 'aiReleaseImport' is important, as the library // keeps internal resources until the scene is freed again. Not // doing so can cause severe resource leaking. aiReleaseImport(scene); // We added a log stream to the library, it's our job to disable it // again. This will definitely release the last resources allocated // by Assimp. aiDetachAllLogStreams(); return 0; }