|
@@ -0,0 +1,229 @@
|
|
|
|
+
|
|
|
|
+// ----------------------------------------------------------------------------
|
|
|
|
+// 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 glVertex3D 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) (x<y?x:y)
|
|
|
|
+#define aisgl_max(x,y) (y>x?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;
|
|
|
|
+}
|