+++ /dev/null
-/*
- * .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;
-}