📄 smooth.c
字号:
/* smooth.c Nate Robins, 1998 Model viewer program. Exercises the glm library. */#include <math.h>#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <stdarg.h>#include <GL/glut.h>#include "gltb.h"#include "glm.h"#include "dirent32.h"#define DATA_DIR "data/"char* model_file = NULL; /* name of the obect file */GLuint model_list = 0; /* display list for object */GLMmodel* model; /* glm model data structure */GLfloat scale; /* original scale factor */GLfloat smoothing_angle = 90.0; /* smoothing angle */GLfloat weld_distance = 0.00001; /* epsilon for welding vertices */GLboolean facet_normal = GL_FALSE; /* draw with facet normal? */GLboolean bounding_box = GL_FALSE; /* bounding box on? */GLboolean performance = GL_FALSE; /* performance counter on? */GLboolean stats = GL_FALSE; /* statistics on? */GLuint material_mode = 0; /* 0=none, 1=color, 2=material */GLint entries = 0; /* entries in model menu */GLdouble pan_x = 0.0;GLdouble pan_y = 0.0;GLdouble pan_z = 0.0;#if defined(_WIN32)#include <sys/timeb.h>#else#include <limits.h>#include <unistd.h>#include <sys/types.h>#include <sys/times.h>#endif#ifndef CLK_TCK
#define CLK_TCK 1000
#endif
floatelapsed(void){ static long begin = 0; static long finish, difference;#if defined(_WIN32) static struct timeb tb; ftime(&tb); finish = tb.time*1000+tb.millitm;#else static struct tms tb; finish = times(&tb);#endif difference = finish - begin; begin = finish; return (float)difference/(float)CLK_TCK;}voidshadowtext(int x, int y, char* s) { int lines; char* p; glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT), -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor3ub(0, 0, 0); glRasterPos2i(x+1, y-1); for(p = s, lines = 0; *p; p++) { if (*p == '\n') { lines++; glRasterPos2i(x+1, y-1-(lines*18)); } glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *p); } glColor3ub(0, 128, 255); glRasterPos2i(x, y); for(p = s, lines = 0; *p; p++) { if (*p == '\n') { lines++; glRasterPos2i(x, y-(lines*18)); } glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *p); } glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_DEPTH_TEST);}voidlists(void){ GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat specular[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat shininess = 65.0; glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); glMaterialf(GL_FRONT, GL_SHININESS, shininess); if (model_list) glDeleteLists(model_list, 1); /* generate a list */ if (material_mode == 0) { if (facet_normal) model_list = glmList(model, GLM_FLAT); else model_list = glmList(model, GLM_SMOOTH); } else if (material_mode == 1) { if (facet_normal) model_list = glmList(model, GLM_FLAT | GLM_COLOR); else model_list = glmList(model, GLM_SMOOTH | GLM_COLOR); } else if (material_mode == 2) { if (facet_normal) model_list = glmList(model, GLM_FLAT | GLM_MATERIAL); else model_list = glmList(model, GLM_SMOOTH | GLM_MATERIAL); }}voidinit(void){ gltbInit(GLUT_LEFT_BUTTON); /* read in the model */ model = glmReadOBJ(model_file); scale = glmUnitize(model); glmFacetNormals(model); glmVertexNormals(model, smoothing_angle); if (model->nummaterials > 0) material_mode = 2; /* create new display lists */ lists(); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE);}voidreshape(int width, int height){ gltbReshape(width, height); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat)height / (GLfloat)width, 1.0, 128.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -3.0);}#define NUM_FRAMES 5voiddisplay(void){ static char s[256], t[32]; static char* p; static int frames = 0; glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(pan_x, pan_y, 0.0); gltbMatrix();#if 0 /* glmDraw() performance test */ if (material_mode == 0) { if (facet_normal) glmDraw(model, GLM_FLAT); else glmDraw(model, GLM_SMOOTH); } else if (material_mode == 1) { if (facet_normal) glmDraw(model, GLM_FLAT | GLM_COLOR); else glmDraw(model, GLM_SMOOTH | GLM_COLOR); } else if (material_mode == 2) { if (facet_normal) glmDraw(model, GLM_FLAT | GLM_MATERIAL); else glmDraw(model, GLM_SMOOTH | GLM_MATERIAL); }#else glCallList(model_list);#endif glDisable(GL_LIGHTING); if (bounding_box) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_CULL_FACE); glColor4f(1.0, 0.0, 0.0, 0.25); glutSolidCube(2.0); glDisable(GL_BLEND); } glPopMatrix(); if (stats) { /* XXX - this could be done a _whole lot_ faster... */ int height = glutGet(GLUT_WINDOW_HEIGHT); glColor3ub(0, 0, 0); sprintf(s, "%s\n%d vertices\n%d triangles\n%d normals\n" "%d texcoords\n%d groups\n%d materials", model->pathname, model->numvertices, model->numtriangles, model->numnormals, model->numtexcoords, model->numgroups, model->nummaterials); shadowtext(5, height-(5+18*1), s); } /* spit out frame rate. */ frames++; if (frames > NUM_FRAMES) { sprintf(t, "%g fps", frames/elapsed()); frames = 0; } if (performance) { shadowtext(5, 5, t); } glutSwapBuffers(); glEnable(GL_LIGHTING);}voidkeyboard(unsigned char key, int x, int y){ GLint params[2]; switch (key) { case 'h': printf("help\n\n"); printf("w - Toggle wireframe/filled\n"); printf("c - Toggle culling\n"); printf("n - Toggle facet/smooth normal\n"); printf("b - Toggle bounding box\n"); printf("r - Reverse polygon winding\n"); printf("m - Toggle color/material/none mode\n"); printf("p - Toggle performance indicator\n"); printf("s/S - Scale model smaller/larger\n"); printf("t - Show model stats\n"); printf("o - Weld vertices in model\n"); printf("+/- - Increase/decrease smoothing angle\n"); printf("W - Write model to file (out.obj)\n"); printf("q/escape - Quit\n\n"); break; case 't': stats = !stats; break; case 'p': performance = !performance; break; case 'm': material_mode++; if (material_mode > 2) material_mode = 0; printf("material_mode = %d\n", material_mode); lists(); break; case 'd': glmDelete(model); init(); lists(); break; case 'w': glGetIntegerv(GL_POLYGON_MODE, params); if (params[0] == GL_FILL) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; case 'c': if (glIsEnabled(GL_CULL_FACE)) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); break; case 'b': bounding_box = !bounding_box; break; case 'n': facet_normal = !facet_normal; lists(); break; case 'r': glmReverseWinding(model); lists(); break; case 's': glmScale(model, 0.8); lists(); break; case 'S': glmScale(model, 1.25); lists(); break; case 'o': printf("Welded %d\n", glmWeld(model, weld_distance)); glmVertexNormals(model, smoothing_angle); lists(); break; case 'O': weld_distance += 0.01; printf("Weld distance: %.2f\n", weld_distance); glmWeld(model, weld_distance); glmFacetNormals(model); glmVertexNormals(model, smoothing_angle); lists(); break; case '-': smoothing_angle -= 1.0; printf("Smoothing angle: %.1f\n", smoothing_angle); glmVertexNormals(model, smoothing_angle); lists(); break; case '+': smoothing_angle += 1.0; printf("Smoothing angle: %.1f\n", smoothing_angle); glmVertexNormals(model, smoothing_angle); lists(); break; case 'W': glmScale(model, 1.0/scale); glmWriteOBJ(model, "out.obj", GLM_SMOOTH | GLM_MATERIAL); break; case 'R': { GLuint i; GLfloat swap; for (i = 1; i <= model->numvertices; i++) { swap = model->vertices[3 * i + 1]; model->vertices[3 * i + 1] = model->vertices[3 * i + 2]; model->vertices[3 * i + 2] = -swap; } glmFacetNormals(model); lists(); break; } case 27: exit(0); break; } glutPostRedisplay();}voidmenu(int item){ int i = 0; DIR* dirp; char* name; struct dirent* direntp; if (item > 0) { keyboard((unsigned char)item, 0, 0); } else { dirp = opendir(DATA_DIR); while ((direntp = readdir(dirp)) != NULL) { if (strstr(direntp->d_name, ".obj")) { i++; if (i == -item) break; } } if (!direntp) return; name = (char*)malloc(strlen(direntp->d_name) + strlen(DATA_DIR) + 1); strcpy(name, DATA_DIR); strcat(name, direntp->d_name); model = glmReadOBJ(name); scale = glmUnitize(model); glmFacetNormals(model); glmVertexNormals(model, smoothing_angle); if (model->nummaterials > 0) material_mode = 2; else material_mode = 0; lists(); free(name); glutPostRedisplay(); }}static GLint mouse_state;static GLint mouse_button;voidmouse(int button, int state, int x, int y){ GLdouble model[4*4]; GLdouble proj[4*4]; GLint view[4]; /* fix for two-button mice -- left mouse + shift = middle mouse */ if (button == GLUT_LEFT_BUTTON && glutGetModifiers() & GLUT_ACTIVE_SHIFT) button = GLUT_MIDDLE_BUTTON; gltbMouse(button, state, x, y); mouse_state = state; mouse_button = button; if (state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON) { glGetDoublev(GL_MODELVIEW_MATRIX, model); glGetDoublev(GL_PROJECTION_MATRIX, proj); glGetIntegerv(GL_VIEWPORT, view); gluProject((GLdouble)x, (GLdouble)y, 0.0, model, proj, view, &pan_x, &pan_y, &pan_z); gluUnProject((GLdouble)x, (GLdouble)y, pan_z, model, proj, view, &pan_x, &pan_y, &pan_z); pan_y = -pan_y; } glutPostRedisplay();}voidmotion(int x, int y){ GLdouble model[4*4]; GLdouble proj[4*4]; GLint view[4]; gltbMotion(x, y); if (mouse_state == GLUT_DOWN && mouse_button == GLUT_MIDDLE_BUTTON) { glGetDoublev(GL_MODELVIEW_MATRIX, model); glGetDoublev(GL_PROJECTION_MATRIX, proj); glGetIntegerv(GL_VIEWPORT, view); gluProject((GLdouble)x, (GLdouble)y, 0.0, model, proj, view, &pan_x, &pan_y, &pan_z); gluUnProject((GLdouble)x, (GLdouble)y, pan_z, model, proj, view, &pan_x, &pan_y, &pan_z); pan_y = -pan_y; } glutPostRedisplay();}intmain(int argc, char** argv){ int buffering = GLUT_DOUBLE; struct dirent* direntp; DIR* dirp; int models; glutInitWindowSize(512, 512); glutInit(&argc, argv); while (--argc) { if (strcmp(argv[argc], "-sb") == 0) buffering = GLUT_SINGLE; else model_file = argv[argc]; } if (!model_file) { model_file = "data/dolphins.obj"; } glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | buffering); glutCreateWindow("Smooth"); glutReshapeFunc(reshape); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); models = glutCreateMenu(menu); dirp = opendir(DATA_DIR); if (!dirp) { fprintf(stderr, "%s: can't open data directory.\n", argv[0]); } else { while ((direntp = readdir(dirp)) != NULL) { if (strstr(direntp->d_name, ".obj")) { entries++; glutAddMenuEntry(direntp->d_name, -entries); } } closedir(dirp); } glutCreateMenu(menu); glutAddMenuEntry("Smooth", 0); glutAddMenuEntry("", 0); glutAddSubMenu("Models", models); glutAddMenuEntry("", 0); glutAddMenuEntry("[w] Toggle wireframe/filled", 'w'); glutAddMenuEntry("[c] Toggle culling on/off", 'c'); glutAddMenuEntry("[n] Toggle face/smooth normals", 'n'); glutAddMenuEntry("[b] Toggle bounding box on/off", 'b'); glutAddMenuEntry("[p] Toggle frame rate on/off", 'p'); glutAddMenuEntry("[t] Toggle model statistics", 't'); glutAddMenuEntry("[m] Toggle color/material/none mode", 'm'); glutAddMenuEntry("[r] Reverse polygon winding", 'r'); glutAddMenuEntry("[s] Scale model smaller", 's'); glutAddMenuEntry("[S] Scale model larger", 'S'); glutAddMenuEntry("[o] Weld redundant vertices", 'o'); glutAddMenuEntry("[+] Increase smoothing angle", '+'); glutAddMenuEntry("[-] Decrease smoothing angle", '-'); glutAddMenuEntry("[W] Write model to file (out.obj)", 'W'); glutAddMenuEntry("", 0); glutAddMenuEntry("[Esc] Quit", 27); glutAttachMenu(GLUT_RIGHT_BUTTON); init(); glutMainLoop(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -