Sample_SimpleOpenGL.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /* ----------------------------------------------------------------------------
  2. // Simple sample to prove that Assimp is easy to use with OpenGL.
  3. // It takes a file name as command line parameter, loads it using standard
  4. // settings and displays it.
  5. //
  6. // If you intend to _use_ this code sample in your app, do yourself a favour
  7. // and replace immediate mode calls with VBOs ...
  8. //
  9. // The vc8 solution links against assimp-release-dll_win32 - be sure to
  10. // have this configuration built.
  11. // ----------------------------------------------------------------------------
  12. */
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #ifdef __APPLE__
  16. #include <glut.h>
  17. #else
  18. #include <GL/glut.h>
  19. #endif
  20. /* assimp include files. These three are usually needed. */
  21. #include <assimp/cimport.h>
  22. #include <assimp/scene.h>
  23. #include <assimp/postprocess.h>
  24. /* the global Assimp scene object */
  25. const struct aiScene* scene = NULL;
  26. GLuint scene_list = 0;
  27. struct aiVector3D scene_min, scene_max, scene_center;
  28. /* current rotation angle */
  29. static float angle = 0.f;
  30. #define aisgl_min(x,y) (x<y?x:y)
  31. #define aisgl_max(x,y) (y>x?y:x)
  32. /* ---------------------------------------------------------------------------- */
  33. void reshape(int width, int height)
  34. {
  35. const double aspectRatio = (float) width / height, fieldOfView = 45.0;
  36. glMatrixMode(GL_PROJECTION);
  37. glLoadIdentity();
  38. gluPerspective(fieldOfView, aspectRatio,
  39. 1.0, 1000.0); /* Znear and Zfar */
  40. glViewport(0, 0, width, height);
  41. }
  42. /* ---------------------------------------------------------------------------- */
  43. void get_bounding_box_for_node (const struct aiNode* nd,
  44. struct aiVector3D* min,
  45. struct aiVector3D* max,
  46. struct aiMatrix4x4* trafo
  47. ){
  48. struct aiMatrix4x4 prev;
  49. unsigned int n = 0, t;
  50. prev = *trafo;
  51. aiMultiplyMatrix4(trafo,&nd->mTransformation);
  52. for (; n < nd->mNumMeshes; ++n) {
  53. const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
  54. for (t = 0; t < mesh->mNumVertices; ++t) {
  55. struct aiVector3D tmp = mesh->mVertices[t];
  56. aiTransformVecByMatrix4(&tmp,trafo);
  57. min->x = aisgl_min(min->x,tmp.x);
  58. min->y = aisgl_min(min->y,tmp.y);
  59. min->z = aisgl_min(min->z,tmp.z);
  60. max->x = aisgl_max(max->x,tmp.x);
  61. max->y = aisgl_max(max->y,tmp.y);
  62. max->z = aisgl_max(max->z,tmp.z);
  63. }
  64. }
  65. for (n = 0; n < nd->mNumChildren; ++n) {
  66. get_bounding_box_for_node(nd->mChildren[n],min,max,trafo);
  67. }
  68. *trafo = prev;
  69. }
  70. /* ---------------------------------------------------------------------------- */
  71. void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max)
  72. {
  73. struct aiMatrix4x4 trafo;
  74. aiIdentityMatrix4(&trafo);
  75. min->x = min->y = min->z = 1e10f;
  76. max->x = max->y = max->z = -1e10f;
  77. get_bounding_box_for_node(scene->mRootNode,min,max,&trafo);
  78. }
  79. /* ---------------------------------------------------------------------------- */
  80. void color4_to_float4(const struct aiColor4D *c, float f[4])
  81. {
  82. f[0] = c->r;
  83. f[1] = c->g;
  84. f[2] = c->b;
  85. f[3] = c->a;
  86. }
  87. /* ---------------------------------------------------------------------------- */
  88. void set_float4(float f[4], float a, float b, float c, float d)
  89. {
  90. f[0] = a;
  91. f[1] = b;
  92. f[2] = c;
  93. f[3] = d;
  94. }
  95. /* ---------------------------------------------------------------------------- */
  96. void apply_material(const struct aiMaterial *mtl)
  97. {
  98. float c[4];
  99. GLenum fill_mode;
  100. int ret1, ret2;
  101. struct aiColor4D diffuse;
  102. struct aiColor4D specular;
  103. struct aiColor4D ambient;
  104. struct aiColor4D emission;
  105. ai_real shininess, strength;
  106. int two_sided;
  107. int wireframe;
  108. unsigned int max;
  109. set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f);
  110. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
  111. color4_to_float4(&diffuse, c);
  112. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c);
  113. set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
  114. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular))
  115. color4_to_float4(&specular, c);
  116. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
  117. set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f);
  118. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient))
  119. color4_to_float4(&ambient, c);
  120. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c);
  121. set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
  122. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission))
  123. color4_to_float4(&emission, c);
  124. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);
  125. max = 1;
  126. ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max);
  127. if(ret1 == AI_SUCCESS) {
  128. max = 1;
  129. ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
  130. if(ret2 == AI_SUCCESS)
  131. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);
  132. else
  133. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
  134. }
  135. else {
  136. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
  137. set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f);
  138. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
  139. }
  140. max = 1;
  141. if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
  142. fill_mode = wireframe ? GL_LINE : GL_FILL;
  143. else
  144. fill_mode = GL_FILL;
  145. glPolygonMode(GL_FRONT_AND_BACK, fill_mode);
  146. max = 1;
  147. if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
  148. glDisable(GL_CULL_FACE);
  149. else
  150. glEnable(GL_CULL_FACE);
  151. }
  152. /* ---------------------------------------------------------------------------- */
  153. void recursive_render (const struct aiScene *sc, const struct aiNode* nd)
  154. {
  155. unsigned int i;
  156. unsigned int n = 0, t;
  157. struct aiMatrix4x4 m = nd->mTransformation;
  158. /* update transform */
  159. aiTransposeMatrix4(&m);
  160. glPushMatrix();
  161. glMultMatrixf((float*)&m);
  162. /* draw all meshes assigned to this node */
  163. for (; n < nd->mNumMeshes; ++n) {
  164. const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
  165. apply_material(sc->mMaterials[mesh->mMaterialIndex]);
  166. if(mesh->mNormals == NULL) {
  167. glDisable(GL_LIGHTING);
  168. } else {
  169. glEnable(GL_LIGHTING);
  170. }
  171. for (t = 0; t < mesh->mNumFaces; ++t) {
  172. const struct aiFace* face = &mesh->mFaces[t];
  173. GLenum face_mode;
  174. switch(face->mNumIndices) {
  175. case 1: face_mode = GL_POINTS; break;
  176. case 2: face_mode = GL_LINES; break;
  177. case 3: face_mode = GL_TRIANGLES; break;
  178. default: face_mode = GL_POLYGON; break;
  179. }
  180. glBegin(face_mode);
  181. for(i = 0; i < face->mNumIndices; i++) {
  182. int index = face->mIndices[i];
  183. if(mesh->mColors[0] != NULL)
  184. glColor4fv((GLfloat*)&mesh->mColors[0][index]);
  185. if(mesh->mNormals != NULL)
  186. glNormal3fv(&mesh->mNormals[index].x);
  187. glVertex3fv(&mesh->mVertices[index].x);
  188. }
  189. glEnd();
  190. }
  191. }
  192. /* draw all children */
  193. for (n = 0; n < nd->mNumChildren; ++n) {
  194. recursive_render(sc, nd->mChildren[n]);
  195. }
  196. glPopMatrix();
  197. }
  198. /* ---------------------------------------------------------------------------- */
  199. void do_motion (void)
  200. {
  201. static GLint prev_time = 0;
  202. static GLint prev_fps_time = 0;
  203. static int frames = 0;
  204. int time = glutGet(GLUT_ELAPSED_TIME);
  205. angle += (time-prev_time)*0.01;
  206. prev_time = time;
  207. frames += 1;
  208. if ((time - prev_fps_time) > 1000) /* update every seconds */
  209. {
  210. int current_fps = frames * 1000 / (time - prev_fps_time);
  211. printf("%d fps\n", current_fps);
  212. frames = 0;
  213. prev_fps_time = time;
  214. }
  215. glutPostRedisplay ();
  216. }
  217. /* ---------------------------------------------------------------------------- */
  218. void display(void)
  219. {
  220. float tmp;
  221. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  222. glMatrixMode(GL_MODELVIEW);
  223. glLoadIdentity();
  224. gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f);
  225. /* rotate it around the y axis */
  226. glRotatef(angle,0.f,1.f,0.f);
  227. /* scale the whole asset to fit into our view frustum */
  228. tmp = scene_max.x-scene_min.x;
  229. tmp = aisgl_max(scene_max.y - scene_min.y,tmp);
  230. tmp = aisgl_max(scene_max.z - scene_min.z,tmp);
  231. tmp = 1.f / tmp;
  232. glScalef(tmp, tmp, tmp);
  233. /* center the model */
  234. glTranslatef( -scene_center.x, -scene_center.y, -scene_center.z );
  235. /* if the display list has not been made yet, create a new one and
  236. fill it with scene contents */
  237. if(scene_list == 0) {
  238. scene_list = glGenLists(1);
  239. glNewList(scene_list, GL_COMPILE);
  240. /* now begin at the root node of the imported data and traverse
  241. the scenegraph by multiplying subsequent local transforms
  242. together on GL's matrix stack. */
  243. recursive_render(scene, scene->mRootNode);
  244. glEndList();
  245. }
  246. glCallList(scene_list);
  247. glutSwapBuffers();
  248. do_motion();
  249. }
  250. /* ---------------------------------------------------------------------------- */
  251. int loadasset (const char* path)
  252. {
  253. /* we are taking one of the postprocessing presets to avoid
  254. spelling out 20+ single postprocessing flags here. */
  255. scene = aiImportFile(path,aiProcessPreset_TargetRealtime_MaxQuality);
  256. if (scene) {
  257. get_bounding_box(&scene_min,&scene_max);
  258. scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
  259. scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
  260. scene_center.z = (scene_min.z + scene_max.z) / 2.0f;
  261. return 0;
  262. }
  263. return 1;
  264. }
  265. /* ---------------------------------------------------------------------------- */
  266. int main(int argc, char **argv)
  267. {
  268. struct aiLogStream stream;
  269. glutInitWindowSize(900,600);
  270. glutInitWindowPosition(100,100);
  271. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  272. glutInit(&argc, argv);
  273. glutCreateWindow("Assimp - Very simple OpenGL sample");
  274. glutDisplayFunc(display);
  275. glutReshapeFunc(reshape);
  276. /* get a handle to the predefined STDOUT log stream and attach
  277. it to the logging system. It remains active for all further
  278. calls to aiImportFile(Ex) and aiApplyPostProcessing. */
  279. stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
  280. aiAttachLogStream(&stream);
  281. /* ... same procedure, but this stream now writes the
  282. log messages to assimp_log.txt */
  283. stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt");
  284. aiAttachLogStream(&stream);
  285. /* the model name can be specified on the command line. If none
  286. is specified, we try to locate one of the more expressive test
  287. models from the repository (/models-nonbsd may be missing in
  288. some distributions so we need a fallback from /models!). */
  289. if( 0 != loadasset( argc >= 2 ? argv[1] : "../../test/models-nonbsd/X/dwarf.x")) {
  290. if( argc != 1 || (0 != loadasset( "../../../../test/models-nonbsd/X/dwarf.x") && 0 != loadasset( "../../test/models/X/Testwuson.X"))) {
  291. return -1;
  292. }
  293. }
  294. glClearColor(0.1f,0.1f,0.1f,1.f);
  295. glEnable(GL_LIGHTING);
  296. glEnable(GL_LIGHT0); /* Uses default lighting parameters */
  297. glEnable(GL_DEPTH_TEST);
  298. glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  299. glEnable(GL_NORMALIZE);
  300. /* XXX docs say all polygons are emitted CCW, but tests show that some aren't. */
  301. if(getenv("MODEL_IS_BROKEN"))
  302. glFrontFace(GL_CW);
  303. glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  304. glutGet(GLUT_ELAPSED_TIME);
  305. glutMainLoop();
  306. /* cleanup - calling 'aiReleaseImport' is important, as the library
  307. keeps internal resources until the scene is freed again. Not
  308. doing so can cause severe resource leaking. */
  309. aiReleaseImport(scene);
  310. /* We added a log stream to the library, it's our job to disable it
  311. again. This will definitely release the last resources allocated
  312. by Assimp.*/
  313. aiDetachAllLogStreams();
  314. return 0;
  315. }