diff options
Diffstat (limited to 'progs/objviewer/objview.c')
| -rw-r--r-- | progs/objviewer/objview.c | 515 | 
1 files changed, 515 insertions, 0 deletions
| diff --git a/progs/objviewer/objview.c b/progs/objviewer/objview.c new file mode 100644 index 0000000000..ad25e751a7 --- /dev/null +++ b/progs/objviewer/objview.c @@ -0,0 +1,515 @@ +/*   + * .obj file viewer based on "smooth" by Nate Robins, 1997 + * + * Brian Paul + * 1 Oct 2009 + */ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdarg.h> +#include <GL/glew.h> +#include <GL/glut.h> +#include "glm.h" +#include "readtex.h" +#include "skybox.h" +#include "trackball.h" + + +static char *Model_file = NULL;		/* name of the obect file */ +static GLMmodel *Model; +static GLfloat Scale = 4.0;			/* scaling factor */ +static GLboolean Performance = GL_FALSE; +static GLboolean Stats = GL_FALSE; +static GLboolean Animate = GL_TRUE; +static GLuint SkyboxTex; +static GLboolean Skybox = GL_TRUE; +static GLboolean Cull = GL_TRUE; +static GLboolean WireFrame = GL_FALSE; +static GLenum FrontFace = GL_CCW; +static GLfloat Yrot = 0.0; +static GLint WinWidth = 1024, WinHeight = 768; +static GLuint NumInstances = 1; + + + +typedef struct +{ +   float CurQuat[4]; +   float Distance; +   /* When mouse is moving: */ +   GLboolean Rotating, Translating; +   GLint StartX, StartY; +   float StartDistance; +} ViewInfo; + +static ViewInfo View; + +static void +InitViewInfo(ViewInfo *view) +{ +   view->Rotating = GL_FALSE; +   view->Translating = GL_FALSE; +   view->StartX = view->StartY = 0; +   view->Distance = 12.0; +   view->StartDistance = 0.0; +   view->CurQuat[0] = 0.0; +   view->CurQuat[1] = 1.0; +   view->CurQuat[2] = 0.0; +   view->CurQuat[3] = 0.0; +} + + + +/* text: general purpose text routine.  draws a string according to + * format in a stroke font at x, y after scaling it by the scale + * specified (scale is in window-space (lower-left origin) pixels).   + * + * x      - position in x (in window-space) + * y      - position in y (in window-space) + * scale  - scale in pixels + * format - as in printf() + */ +static void  +text(GLuint x, GLuint y, GLfloat scale, char* format, ...) +{ +  va_list args; +  char buffer[255], *p; +  GLfloat font_scale = 119.05 + 33.33; + +  va_start(args, format); +  vsprintf(buffer, format, args); +  va_end(args); + +  glMatrixMode(GL_PROJECTION); +  glPushMatrix(); +  glLoadIdentity(); +  gluOrtho2D(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT)); + +  glMatrixMode(GL_MODELVIEW); +  glPushMatrix(); +  glLoadIdentity(); + +  glPushAttrib(GL_ENABLE_BIT); +  glDisable(GL_LIGHTING); +  glDisable(GL_TEXTURE_2D); +  glDisable(GL_DEPTH_TEST); +  glTranslatef(x, y, 0.0); + +  glScalef(scale/font_scale, scale/font_scale, scale/font_scale); + +  for(p = buffer; *p; p++) +    glutStrokeCharacter(GLUT_STROKE_ROMAN, *p); +   +  glPopAttrib(); + +  glPopMatrix(); +  glMatrixMode(GL_PROJECTION); +  glPopMatrix(); +  glMatrixMode(GL_MODELVIEW); +} + + +static float +ComputeFPS(void) +{ +   static double t0 = -1.0; +   static int frames = 0; +   double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; +   static float fps = 0; + +   frames++; + +   if (t0 < 0.0) { +      t0 = t; +      fps = 0.0; +   } +   else if (t - t0 >= 4.0) { +      fps = (frames / (t - t0) + 0.5); +      t0 = t; +      frames = 0; +      return fps; +   } + +   return 0.0; +} + + +static void +init_model(void) +{ +   float objScale; + +   /* read in the model */ +   Model = glmReadOBJ(Model_file); +   objScale = glmUnitize(Model); +   glmFacetNormals(Model); +   if (Model->numnormals == 0) { +      GLfloat smoothing_angle = 90.0; +      printf("Generating normals.\n"); +      glmVertexNormals(Model, smoothing_angle); +   } + +   glmLoadTextures(Model); +   glmReIndex(Model); +   glmMakeVBOs(Model); +   if (0) +      glmPrint(Model); +} + +static void +init_skybox(void) +{ +   SkyboxTex = LoadSkyBoxCubeTexture("alpine_east.rgb", +                                     "alpine_west.rgb", +                                     "alpine_up.rgb", +                                     "alpine_down.rgb", +                                     "alpine_south.rgb", +                                     "alpine_north.rgb"); +   glmSpecularTexture(Model, SkyboxTex); +} + + +static void +init_gfx(void) +{ +   glEnable(GL_DEPTH_TEST); +   glEnable(GL_CULL_FACE); +   glEnable(GL_NORMALIZE); +   glClearColor(0.3, 0.3, 0.9, 0.0); +} + + +static void +reshape(int width, int height) +{ +   float ar = 0.5 * (float) width / (float) height; + +   WinWidth = width; +   WinHeight = height; + +   glViewport(0, 0, width, height); + +   glMatrixMode(GL_PROJECTION); +   glLoadIdentity(); +   glFrustum(-ar, ar, -0.5, 0.5, 1.0, 300.0); +   glMatrixMode(GL_MODELVIEW); +   glLoadIdentity(); +   glTranslatef(0.0, 0.0, -3.0); +} + + +static void +Idle(void) +{ +   float q[4]; +   trackball(q, 100, 0, 99.99, 0); +   add_quats(q, View.CurQuat, View.CurQuat); + +   glutPostRedisplay(); +} + + +static void +display(void) +{ +   GLfloat rot[4][4]; +   float fps; + +   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + +   glPushMatrix(); +      glTranslatef(0.0, 0.0, -View.Distance); +      glRotatef(Yrot, 0, 1, 0); +      build_rotmatrix(rot, View.CurQuat); +      glMultMatrixf(&rot[0][0]); +      glScalef(Scale, Scale, Scale ); + +      glUseProgram(0); + +      if (Skybox) +         DrawSkyBoxCubeTexture(SkyboxTex); + +      if (WireFrame) +         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +      else +         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + +      if (Cull) +         glEnable(GL_CULL_FACE); +      else +         glDisable(GL_CULL_FACE); + +      if (NumInstances == 1) { +         glmDrawVBO(Model); +      } +      else { +         /* draw > 1 instance */ +         float dr = 360.0 / NumInstances; +         float r; +         for (r = 0.0; r < 360.0; r += dr) { +            glPushMatrix(); +            glRotatef(r, 0, 1, 0); +            glTranslatef(1.4, 0.0, 0.0); +            glmDrawVBO(Model); +            glPopMatrix(); +         } +      } + +      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +      glDisable(GL_CULL_FACE); + +   glPopMatrix(); + +   if (Stats) { +      glColor3f(1.0, 1.0, 1.0); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*1), 20, "%s",  +           Model->pathname); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*2), 20, "%d vertices",  +           Model->numvertices); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*3), 20, "%d triangles",  +           Model->numtriangles); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*4), 20, "%d normals",  +           Model->numnormals); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*5), 20, "%d texcoords",  +           Model->numtexcoords); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*6), 20, "%d groups",  +           Model->numgroups); +      text(5, glutGet(GLUT_WINDOW_HEIGHT) - (5+20*7), 20, "%d materials",  +           Model->nummaterials); +   } + +   glutSwapBuffers(); + +   fps = ComputeFPS(); +   if (fps) +      printf("%f FPS\n", fps); +} + + +static void +keyboard(unsigned char key, int x, int y) +{ +   switch (key) { +   case 'h': +      printf("help\n\n"); +      printf("a            -  Toggle animation\n"); +      printf("d/D          -  Decrease/Incrase number of models\n"); +      printf("w            -  Toggle wireframe/filled\n"); +      printf("c            -  Toggle culling\n"); +      printf("n            -  Toggle facet/smooth normal\n"); +      printf("r            -  Reverse polygon winding\n"); +      printf("p            -  Toggle performance indicator\n"); +      printf("s            -  Toggle skybox\n"); +      printf("z/Z          -  Scale model smaller/larger\n"); +      printf("i            -  Show model info/stats\n"); +      printf("q/escape     -  Quit\n\n"); +      break; +   case 'a': +      Animate = !Animate; +      if (Animate) +         glutIdleFunc(Idle); +      else +         glutIdleFunc(NULL); +      break; +   case 'd': +      if (NumInstances > 1) +         NumInstances--; +      break; +   case 'D': +      NumInstances++; +      break; +   case 'i': +      Stats = !Stats; +      break; +   case 'p': +      Performance = !Performance; +      break; +   case 'w': +      WireFrame = !WireFrame; +      break; +   case 'c': +      Cull = !Cull; +      printf("Polygon culling: %d\n", Cull); +      break; +   case 'r': +      if (FrontFace == GL_CCW) +         FrontFace = GL_CW; +      else +         FrontFace = GL_CCW; +      glFrontFace(FrontFace); +      printf("Front face:: %s\n", FrontFace == GL_CCW ? "CCW" : "CW"); +      break; +   case 's': +      Skybox = !Skybox; +      if (Skybox) +         glmSpecularTexture(Model, SkyboxTex); +      else +         glmSpecularTexture(Model, 0); +      break; +   case 'z': +      Scale *= 0.9; +      break; +   case 'Z': +      Scale *= 1.1; +      break; +   case 'q': +   case 27: +      exit(0); +      break; +   } + +   glutPostRedisplay(); +} + + +static void +menu(int item) +{ +    keyboard((unsigned char)item, 0, 0); +} + + +/** + * Handle mouse button. + */ +static void +Mouse(int button, int state, int x, int y) +{ +   if (button == GLUT_LEFT_BUTTON) { +      if (state == GLUT_DOWN) { +         View.StartX = x; +         View.StartY = y; +         View.Rotating = GL_TRUE; +      } +      else if (state == GLUT_UP) { +         View.Rotating = GL_FALSE; +      } +   } +   else if (button == GLUT_MIDDLE_BUTTON) { +      if (state == GLUT_DOWN) { +         View.StartX = x; +         View.StartY = y; +         View.StartDistance = View.Distance; +         View.Translating = GL_TRUE; +      } +      else if (state == GLUT_UP) { +         View.Translating = GL_FALSE; +      } +   } +} + + +/** + * Handle mouse motion + */ +static void +Motion(int x, int y) +{ +   int i; +   if (View.Rotating) { +      float x0 = (2.0 * View.StartX - WinWidth) / WinWidth; +      float y0 = (WinHeight - 2.0 * View.StartY) / WinHeight; +      float x1 = (2.0 * x - WinWidth) / WinWidth; +      float y1 = (WinHeight - 2.0 * y) / WinHeight; +      float q[4]; + +      trackball(q, x0, y0, x1, y1); +      View.StartX = x; +      View.StartY = y; +      for (i = 0; i < 1; i++) +         add_quats(q, View.CurQuat, View.CurQuat); + +      glutPostRedisplay(); +   } +   else if (View.Translating) { +      float dz = 0.02 * (y - View.StartY); +      View.Distance = View.StartDistance + dz; +      glutPostRedisplay(); +   } +} + + +static void +DoFeatureChecks(void) +{ +   char *version = (char *) glGetString(GL_VERSION); +   if (version[0] == '1') { +      /* check for individual extensions */ +      if (!glutExtensionSupported("GL_ARB_texture_cube_map")) { +         printf("Sorry, GL_ARB_texture_cube_map is required.\n"); +         exit(1); +      } +      if (!glutExtensionSupported("GL_ARB_vertex_shader")) { +         printf("Sorry, GL_ARB_vertex_shader is required.\n"); +         exit(1); +      } +      if (!glutExtensionSupported("GL_ARB_fragment_shader")) { +         printf("Sorry, GL_ARB_fragment_shader is required.\n"); +         exit(1); +      } +      if (!glutExtensionSupported("GL_ARB_vertex_buffer_object")) { +         printf("Sorry, GL_ARB_vertex_buffer_object is required.\n"); +         exit(1); +      } +   } +} + + +int +main(int argc, char** argv) +{ +   glutInitWindowSize(WinWidth, WinHeight); +   glutInit(&argc, argv); + +   if (argc > 1) { +      Model_file = argv[1]; +   } +   if (!Model_file) { +      fprintf(stderr, "usage: objview file.obj\n"); +      fprintf(stderr, "(using default bunny.obj)\n"); +      Model_file = "bunny.obj"; +   } + +   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); +   glutCreateWindow("objview"); + +   glewInit(); + +   DoFeatureChecks(); + +   glutReshapeFunc(reshape); +   glutDisplayFunc(display); +   glutKeyboardFunc(keyboard); +   glutMouseFunc(Mouse); +   glutMotionFunc(Motion); +   if (Animate) +      glutIdleFunc(Idle); + +   glutCreateMenu(menu); +   glutAddMenuEntry("[a] Toggle animate", 'a'); +   glutAddMenuEntry("[d] Fewer models", 'd'); +   glutAddMenuEntry("[D] More models", 'D'); +   glutAddMenuEntry("[w] Toggle wireframe/filled", 'w'); +   glutAddMenuEntry("[c] Toggle culling on/off", 'c'); +   glutAddMenuEntry("[r] Reverse polygon winding", 'r'); +   glutAddMenuEntry("[z] Scale model smaller", 'z'); +   glutAddMenuEntry("[Z] Scale model larger", 'Z'); +   glutAddMenuEntry("[p] Toggle performance indicator", 'p'); +   glutAddMenuEntry("[i] Show model stats", 'i'); +   glutAddMenuEntry("", 0); +   glutAddMenuEntry("[q] Quit", 27); +   glutAttachMenu(GLUT_RIGHT_BUTTON); + +   InitViewInfo(&View); + +   init_model(); +   init_skybox(); +   init_gfx(); + +   glutMainLoop(); + +   return 0; +} | 
