Sample_SimpleOpenGL.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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 <freeglut.h>
  17. #else
  18. #include <GL/freeglut.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. #define COMMAND_USAGE "--usage"
  25. /* ---------------------------------------------------------------------------- */
  26. inline static void print_run_command(const char* command_name) {
  27. printf("Run '%s %s' for more information.\n",
  28. PROJECT_NAME, command_name);
  29. }
  30. /* ---------------------------------------------------------------------------- */
  31. inline static void print_error(const char* msg) {
  32. printf("ERROR: %s\n", msg);
  33. }
  34. #define NEW_LINE "\n"
  35. #define DOUBLE_NEW_LINE NEW_LINE NEW_LINE
  36. /* ---------------------------------------------------------------------------- */
  37. inline static void print_usage() {
  38. static const char* usage_format =
  39. "Usage: "
  40. PROJECT_NAME
  41. " <file>" DOUBLE_NEW_LINE
  42. "where:" DOUBLE_NEW_LINE
  43. " %-10s %s" DOUBLE_NEW_LINE
  44. "options:" DOUBLE_NEW_LINE
  45. " %-10s %s" DOUBLE_NEW_LINE;
  46. printf(usage_format,
  47. // where
  48. "file", "The input model file to load.",
  49. // options
  50. COMMAND_USAGE, "Display usage.");
  51. }
  52. /* the global Assimp scene object */
  53. const C_STRUCT aiScene* scene = NULL;
  54. GLuint scene_list = 0;
  55. C_STRUCT aiVector3D scene_min, scene_max, scene_center;
  56. /* current rotation angle */
  57. static float angle = 0.f;
  58. #define aisgl_min(x,y) (x<y?x:y)
  59. #define aisgl_max(x,y) (y>x?y:x)
  60. /* ---------------------------------------------------------------------------- */
  61. void reshape(int width, int height)
  62. {
  63. const double aspectRatio = (float) width / height, fieldOfView = 45.0;
  64. glMatrixMode(GL_PROJECTION);
  65. glLoadIdentity();
  66. gluPerspective(fieldOfView, aspectRatio,
  67. 1.0, 1000.0); /* Znear and Zfar */
  68. glViewport(0, 0, width, height);
  69. }
  70. /* ---------------------------------------------------------------------------- */
  71. void get_bounding_box_for_node (const C_STRUCT aiNode* nd,
  72. C_STRUCT aiVector3D* min,
  73. C_STRUCT aiVector3D* max,
  74. C_STRUCT aiMatrix4x4* trafo
  75. ){
  76. C_STRUCT aiMatrix4x4 prev;
  77. unsigned int n = 0, t;
  78. prev = *trafo;
  79. aiMultiplyMatrix4(trafo,&nd->mTransformation);
  80. for (; n < nd->mNumMeshes; ++n) {
  81. const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
  82. for (t = 0; t < mesh->mNumVertices; ++t) {
  83. C_STRUCT aiVector3D tmp = mesh->mVertices[t];
  84. aiTransformVecByMatrix4(&tmp,trafo);
  85. min->x = aisgl_min(min->x,tmp.x);
  86. min->y = aisgl_min(min->y,tmp.y);
  87. min->z = aisgl_min(min->z,tmp.z);
  88. max->x = aisgl_max(max->x,tmp.x);
  89. max->y = aisgl_max(max->y,tmp.y);
  90. max->z = aisgl_max(max->z,tmp.z);
  91. }
  92. }
  93. for (n = 0; n < nd->mNumChildren; ++n) {
  94. get_bounding_box_for_node(nd->mChildren[n],min,max,trafo);
  95. }
  96. *trafo = prev;
  97. }
  98. /* ---------------------------------------------------------------------------- */
  99. void get_bounding_box(C_STRUCT aiVector3D* min, C_STRUCT aiVector3D* max)
  100. {
  101. C_STRUCT aiMatrix4x4 trafo;
  102. aiIdentityMatrix4(&trafo);
  103. min->x = min->y = min->z = 1e10f;
  104. max->x = max->y = max->z = -1e10f;
  105. get_bounding_box_for_node(scene->mRootNode,min,max,&trafo);
  106. }
  107. /* ---------------------------------------------------------------------------- */
  108. void color4_to_float4(const C_STRUCT aiColor4D *c, float f[4])
  109. {
  110. f[0] = c->r;
  111. f[1] = c->g;
  112. f[2] = c->b;
  113. f[3] = c->a;
  114. }
  115. /* ---------------------------------------------------------------------------- */
  116. void set_float4(float f[4], float a, float b, float c, float d)
  117. {
  118. f[0] = a;
  119. f[1] = b;
  120. f[2] = c;
  121. f[3] = d;
  122. }
  123. /* ---------------------------------------------------------------------------- */
  124. void apply_material(const C_STRUCT aiMaterial *mtl)
  125. {
  126. float c[4];
  127. GLenum fill_mode;
  128. int ret1, ret2;
  129. C_STRUCT aiColor4D diffuse;
  130. C_STRUCT aiColor4D specular;
  131. C_STRUCT aiColor4D ambient;
  132. C_STRUCT aiColor4D emission;
  133. ai_real shininess, strength;
  134. int two_sided;
  135. int wireframe;
  136. unsigned int max;
  137. set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f);
  138. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
  139. color4_to_float4(&diffuse, c);
  140. glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c);
  141. set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
  142. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular))
  143. color4_to_float4(&specular, c);
  144. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
  145. set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f);
  146. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient))
  147. color4_to_float4(&ambient, c);
  148. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c);
  149. set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
  150. if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission))
  151. color4_to_float4(&emission, c);
  152. glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);
  153. max = 1;
  154. ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max);
  155. if(ret1 == AI_SUCCESS) {
  156. max = 1;
  157. ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
  158. if(ret2 == AI_SUCCESS)
  159. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);
  160. else
  161. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
  162. }
  163. else {
  164. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
  165. set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f);
  166. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
  167. }
  168. max = 1;
  169. if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
  170. fill_mode = wireframe ? GL_LINE : GL_FILL;
  171. else
  172. fill_mode = GL_FILL;
  173. glPolygonMode(GL_FRONT_AND_BACK, fill_mode);
  174. max = 1;
  175. if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
  176. glDisable(GL_CULL_FACE);
  177. else
  178. glEnable(GL_CULL_FACE);
  179. }
  180. /* ---------------------------------------------------------------------------- */
  181. void recursive_render (const C_STRUCT aiScene *sc, const C_STRUCT aiNode* nd)
  182. {
  183. unsigned int i;
  184. unsigned int n = 0, t;
  185. C_STRUCT aiMatrix4x4 m = nd->mTransformation;
  186. /* update transform */
  187. aiTransposeMatrix4(&m);
  188. glPushMatrix();
  189. glMultMatrixf((float*)&m);
  190. /* draw all meshes assigned to this node */
  191. for (; n < nd->mNumMeshes; ++n) {
  192. const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
  193. apply_material(sc->mMaterials[mesh->mMaterialIndex]);
  194. if(mesh->mNormals == NULL) {
  195. glDisable(GL_LIGHTING);
  196. } else {
  197. glEnable(GL_LIGHTING);
  198. }
  199. for (t = 0; t < mesh->mNumFaces; ++t) {
  200. const C_STRUCT aiFace* face = &mesh->mFaces[t];
  201. GLenum face_mode;
  202. switch(face->mNumIndices) {
  203. case 1: face_mode = GL_POINTS; break;
  204. case 2: face_mode = GL_LINES; break;
  205. case 3: face_mode = GL_TRIANGLES; break;
  206. default: face_mode = GL_POLYGON; break;
  207. }
  208. glBegin(face_mode);
  209. for(i = 0; i < face->mNumIndices; i++) {
  210. int index = face->mIndices[i];
  211. if(mesh->mColors[0] != NULL)
  212. glColor4fv((GLfloat*)&mesh->mColors[0][index]);
  213. if(mesh->mNormals != NULL)
  214. glNormal3fv(&mesh->mNormals[index].x);
  215. glVertex3fv(&mesh->mVertices[index].x);
  216. }
  217. glEnd();
  218. }
  219. }
  220. /* draw all children */
  221. for (n = 0; n < nd->mNumChildren; ++n) {
  222. recursive_render(sc, nd->mChildren[n]);
  223. }
  224. glPopMatrix();
  225. }
  226. /* ---------------------------------------------------------------------------- */
  227. void do_motion (void)
  228. {
  229. static GLint prev_time = 0;
  230. static GLint prev_fps_time = 0;
  231. static int frames = 0;
  232. int time = glutGet(GLUT_ELAPSED_TIME);
  233. angle += (float)((time-prev_time)*0.01);
  234. prev_time = time;
  235. frames += 1;
  236. if ((time - prev_fps_time) > 1000) /* update every seconds */
  237. {
  238. int current_fps = frames * 1000 / (time - prev_fps_time);
  239. printf("%d fps\n", current_fps);
  240. frames = 0;
  241. prev_fps_time = time;
  242. }
  243. glutPostRedisplay ();
  244. }
  245. /* ---------------------------------------------------------------------------- */
  246. void display(void)
  247. {
  248. float tmp;
  249. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  250. glMatrixMode(GL_MODELVIEW);
  251. glLoadIdentity();
  252. gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f);
  253. /* rotate it around the y axis */
  254. glRotatef(angle,0.f,1.f,0.f);
  255. /* scale the whole asset to fit into our view frustum */
  256. tmp = scene_max.x-scene_min.x;
  257. tmp = aisgl_max(scene_max.y - scene_min.y,tmp);
  258. tmp = aisgl_max(scene_max.z - scene_min.z,tmp);
  259. tmp = 1.f / tmp;
  260. glScalef(tmp, tmp, tmp);
  261. /* center the model */
  262. glTranslatef( -scene_center.x, -scene_center.y, -scene_center.z );
  263. /* if the display list has not been made yet, create a new one and
  264. fill it with scene contents */
  265. if(scene_list == 0) {
  266. scene_list = glGenLists(1);
  267. glNewList(scene_list, GL_COMPILE);
  268. /* now begin at the root node of the imported data and traverse
  269. the scenegraph by multiplying subsequent local transforms
  270. together on GL's matrix stack. */
  271. recursive_render(scene, scene->mRootNode);
  272. glEndList();
  273. }
  274. glCallList(scene_list);
  275. glutSwapBuffers();
  276. do_motion();
  277. }
  278. /* ---------------------------------------------------------------------------- */
  279. int loadasset (const char* path)
  280. {
  281. /* we are taking one of the postprocessing presets to avoid
  282. spelling out 20+ single postprocessing flags here. */
  283. scene = aiImportFile(path,aiProcessPreset_TargetRealtime_MaxQuality);
  284. if (scene) {
  285. get_bounding_box(&scene_min,&scene_max);
  286. scene_center.x = (scene_min.x + scene_max.x) / 2.0f;
  287. scene_center.y = (scene_min.y + scene_max.y) / 2.0f;
  288. scene_center.z = (scene_min.z + scene_max.z) / 2.0f;
  289. return 0;
  290. }
  291. return 1;
  292. }
  293. /* ---------------------------------------------------------------------------- */
  294. int main(int argc, char **argv)
  295. {
  296. const char* model_file = NULL;
  297. C_STRUCT aiLogStream stream;
  298. if (argc < 2) {
  299. print_error("No input model file specified.");
  300. print_run_command(COMMAND_USAGE);
  301. return EXIT_FAILURE;
  302. }
  303. // Find and execute available commands entered by the user.
  304. for (int i = 1; i < argc; ++i) {
  305. if (!strncmp(argv[i], COMMAND_USAGE, strlen(COMMAND_USAGE))) {
  306. print_usage();
  307. return EXIT_SUCCESS;
  308. }
  309. }
  310. // Check and validate the specified model file extension.
  311. model_file = argv[1];
  312. const char* extension = strrchr(model_file, '.');
  313. if (!extension) {
  314. print_error("Please provide a file with a valid extension.");
  315. return EXIT_FAILURE;
  316. }
  317. if (AI_FALSE == aiIsExtensionSupported(extension)) {
  318. print_error("The specified model file extension is currently "
  319. "unsupported in Assimp " ASSIMP_VERSION ".");
  320. return EXIT_FAILURE;
  321. }
  322. glutInitWindowSize(900,600);
  323. glutInitWindowPosition(100,100);
  324. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  325. glutInit(&argc, argv);
  326. glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
  327. glutCreateWindow("Assimp - Very simple OpenGL sample");
  328. glutDisplayFunc(display);
  329. glutReshapeFunc(reshape);
  330. /* get a handle to the predefined STDOUT log stream and attach
  331. it to the logging system. It remains active for all further
  332. calls to aiImportFile(Ex) and aiApplyPostProcessing. */
  333. stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL);
  334. aiAttachLogStream(&stream);
  335. /* ... same procedure, but this stream now writes the
  336. log messages to assimp_log.txt */
  337. stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt");
  338. aiAttachLogStream(&stream);
  339. // Load the model file.
  340. if(0 != loadasset(model_file)) {
  341. print_error("Failed to load model. Please ensure that the specified file exists.");
  342. aiDetachAllLogStreams();
  343. return EXIT_FAILURE;
  344. }
  345. glClearColor(0.1f,0.1f,0.1f,1.f);
  346. glEnable(GL_LIGHTING);
  347. glEnable(GL_LIGHT0); /* Uses default lighting parameters */
  348. glEnable(GL_DEPTH_TEST);
  349. glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  350. glEnable(GL_NORMALIZE);
  351. /* XXX docs say all polygons are emitted CCW, but tests show that some aren't. */
  352. if(getenv("MODEL_IS_BROKEN"))
  353. glFrontFace(GL_CW);
  354. glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  355. glutGet(GLUT_ELAPSED_TIME);
  356. glutMainLoop();
  357. /* cleanup - calling 'aiReleaseImport' is important, as the library
  358. keeps internal resources until the scene is freed again. Not
  359. doing so can cause severe resource leaking. */
  360. aiReleaseImport(scene);
  361. /* We added a log stream to the library, it's our job to disable it
  362. again. This will definitely release the last resources allocated
  363. by Assimp.*/
  364. aiDetachAllLogStreams();
  365. return EXIT_SUCCESS;
  366. }