#include #include #include #include #include "GL/glut.h" #ifndef PI #define PI 3.14159265358979323846 #endif #define GETCOORD(frame, x, y) (&(theMesh.coords[frame*theMesh.numCoords+(x)+(y)*(theMesh.widthX+1)])) #define GETFACET(frame, x, y) (&(theMesh.facets[frame*theMesh.numFacets+(x)+(y)*theMesh.widthX])) GLenum rgb, doubleBuffer, directRender; GLint colorIndexes1[3]; GLint colorIndexes2[3]; GLenum clearMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; GLenum smooth = GL_FALSE; GLenum lighting = GL_TRUE; GLenum depth = GL_TRUE; GLenum stepMode = GL_FALSE; GLenum spinMode = GL_FALSE; GLint contouring = 0; GLint widthX, widthY; GLint checkerSize; float height; GLint frames, curFrame = 0, nextFrame = 0; struct facet { float color[3]; float normal[3]; }; struct coord { float vertex[3]; float normal[3]; }; struct mesh { GLint widthX, widthY; GLint numFacets; GLint numCoords; GLint frames; struct coord *coords; struct facet *facets; } theMesh; GLubyte contourTexture1[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 127, 127, 127, }; GLubyte contourTexture2[] = { 255, 255, 255, 255, 255, 127, 127, 127, 255, 127, 127, 127, 255, 127, 127, 127, }; static void display(void) { struct coord *coord; struct facet *facet; float *lastColor; float *thisColor; GLint i, j; glClear(clearMask); if (nextFrame || !stepMode) { curFrame++; } if (curFrame >= theMesh.frames) { curFrame = 0; } if ((nextFrame || !stepMode) && spinMode) { glRotatef(5.0, 0.0, 0.0, 1.0); } nextFrame = 0; for (i = 0; i < theMesh.widthX; i++) { glBegin(GL_QUAD_STRIP); lastColor = NULL; for (j = 0; j < theMesh.widthY; j++) { facet = GETFACET(curFrame, i, j); if (!smooth && lighting) { glNormal3fv(facet->normal); } if (lighting) { thisColor = facet->color; glColor3fv(facet->color); } else { thisColor = facet->color; glColor3fv(facet->color); } if (!lastColor || (thisColor[0] != lastColor[0] && smooth)) { if (lastColor) { glEnd(); glBegin(GL_QUAD_STRIP); } coord = GETCOORD(curFrame, i, j); if (smooth && lighting) { glNormal3fv(coord->normal); } glVertex3fv(coord->vertex); coord = GETCOORD(curFrame, i+1, j); if (smooth && lighting) { glNormal3fv(coord->normal); } glVertex3fv(coord->vertex); } coord = GETCOORD(curFrame, i, j+1); if (smooth && lighting) { glNormal3fv(coord->normal); } glVertex3fv(coord->vertex); coord = GETCOORD(curFrame, i+1, j+1); if (smooth && lighting) { glNormal3fv(coord->normal); } glVertex3fv(coord->vertex); lastColor = thisColor; } glEnd(); } glFlush(); if (doubleBuffer) { glutSwapBuffers(); } } static void InitMesh(void) { struct coord *coord; struct facet *facet; float dp1[3], dp2[3]; float *pt1, *pt2, *pt3; float angle, d, x, y; GLint numFacets, numCoords, frameNum, i, j; theMesh.widthX = widthX; theMesh.widthY = widthY; theMesh.frames = frames; numFacets = widthX * widthY; numCoords = (widthX + 1) * (widthY + 1); theMesh.numCoords = numCoords; theMesh.numFacets = numFacets; theMesh.coords = (struct coord *)malloc(frames*numCoords* sizeof(struct coord)); theMesh.facets = (struct facet *)malloc(frames*numFacets* sizeof(struct facet)); if (theMesh.coords == NULL || theMesh.facets == NULL) { printf("Out of memory.\n"); exit(0); } for (frameNum = 0; frameNum < frames; frameNum++) { for (i = 0; i <= widthX; i++) { x = i / (float)widthX; for (j = 0; j <= widthY; j++) { y = j / (float)widthY; d = sqrt(x*x+y*y); if (d == 0.0) { d = 0.0001; } angle = 2 * PI * d + (2 * PI / frames * frameNum); coord = GETCOORD(frameNum, i, j); coord->vertex[0] = x - 0.5; coord->vertex[1] = y - 0.5; coord->vertex[2] = (height - height * d) * cos(angle); coord->normal[0] = -(height / d) * x * ((1 - d) * 2 * PI * sin(angle) + cos(angle)); coord->normal[1] = -(height / d) * y * ((1 - d) * 2 * PI * sin(angle) + cos(angle)); coord->normal[2] = -1; d = 1.0 / sqrt(coord->normal[0]*coord->normal[0]+ coord->normal[1]*coord->normal[1]+1); coord->normal[0] *= d; coord->normal[1] *= d; coord->normal[2] *= d; } } for (i = 0; i < widthX; i++) { for (j = 0; j < widthY; j++) { facet = GETFACET(frameNum, i, j); if (((i/checkerSize)%2)^(j/checkerSize)%2) { facet->color[0] = 1.0; facet->color[1] = 0.2; facet->color[2] = 0.2; } else { facet->color[0] = 0.2; facet->color[1] = 1.0; facet->color[2] = 0.2; } pt1 = GETCOORD(frameNum, i, j)->vertex; pt2 = GETCOORD(frameNum, i, j+1)->vertex; pt3 = GETCOORD(frameNum, i+1, j+1)->vertex; dp1[0] = pt2[0] - pt1[0]; dp1[1] = pt2[1] - pt1[1]; dp1[2] = pt2[2] - pt1[2]; dp2[0] = pt3[0] - pt2[0]; dp2[1] = pt3[1] - pt2[1]; dp2[2] = pt3[2] - pt2[2]; facet->normal[0] = dp1[1] * dp2[2] - dp1[2] * dp2[1]; facet->normal[1] = dp1[2] * dp2[0] - dp1[0] * dp2[2]; facet->normal[2] = dp1[0] * dp2[1] - dp1[1] * dp2[0]; d = 1.0 / sqrt(facet->normal[0]*facet->normal[0]+ facet->normal[1]*facet->normal[1]+ facet->normal[2]*facet->normal[2]); facet->normal[0] *= d; facet->normal[1] *= d; facet->normal[2] *= d; } } } } static void InitMaterials(void) { static float ambient[] = {0.1, 0.1, 0.1, 1.0}; static float diffuse[] = {0.5, 1.0, 1.0, 1.0}; static float position[] = {90.0, 90.0, 150.0, 0.0}; static float front_mat_shininess[] = {60.0}; static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0}; static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0}; static float back_mat_shininess[] = {60.0}; static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0}; static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0}; static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0}; static float lmodel_twoside[] = {GL_TRUE}; glMatrixMode(GL_PROJECTION); gluPerspective(450, 1.0, 0.5, 10.0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_POSITION, position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glMaterialfv(GL_FRONT, GL_SHININESS, front_mat_shininess); glMaterialfv(GL_FRONT, GL_SPECULAR, front_mat_specular); glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse); glMaterialfv(GL_BACK, GL_SHININESS, back_mat_shininess); glMaterialfv(GL_BACK, GL_SPECULAR, back_mat_specular); glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); } static void InitTexture(void) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } void Idle(void) { glutPostRedisplay(); } static void Init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); glFrontFace(GL_CW); glEnable(GL_DEPTH_TEST); InitMaterials(); InitTexture(); InitMesh(); glMatrixMode(GL_MODELVIEW); glTranslatef(0.0, 0.4, -1.8); glScalef(2.0, 2.0, 2.0); glRotatef(-35.0, 1.0, 0.0, 0.0); glRotatef(35.0, 0.0, 0.0, 1.0); } static void Reshape(int width, int height) { glViewport(0, 0, (GLint)width, (GLint)height); } void Key(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; case 'c': contouring++; if (contouring == 1) { static GLfloat map[4] = {0, 0, 20, 0}; glTexImage2D(GL_TEXTURE_2D, 0, 3, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (GLvoid *)contourTexture1); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv(GL_S, GL_OBJECT_PLANE, map); glTexGenfv(GL_T, GL_OBJECT_PLANE, map); glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } else if (contouring == 2) { static GLfloat map[4] = {0, 0, 20, 0}; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glPushMatrix(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTexGenfv(GL_S, GL_EYE_PLANE, map); glTexGenfv(GL_T, GL_EYE_PLANE, map); glPopMatrix(); } else { contouring = 0; glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_2D); } break; case 's': smooth = !smooth; if (smooth) { glShadeModel(GL_SMOOTH); } else { glShadeModel(GL_FLAT); } break; case 'l': lighting = !lighting; if (lighting) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); } else { glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glDisable(GL_COLOR_MATERIAL); } break; case 'd': depth = !depth; if (depth) { glEnable(GL_DEPTH_TEST); clearMask |= GL_DEPTH_BUFFER_BIT; } else { glDisable(GL_DEPTH_TEST); clearMask &= ~GL_DEPTH_BUFFER_BIT; } break; case ' ': stepMode = !stepMode; if (stepMode) { glutIdleFunc(0); } else { glutIdleFunc(Idle); } break; case 'n': if (stepMode) { nextFrame = 1; } break; case 'a': spinMode = !spinMode; break; default: return ; } return ; } static GLenum Args(int argc, char **argv) { GLint i; doubleBuffer = GL_TRUE; directRender = GL_TRUE; rgb = GL_TRUE; frames = 10; widthX = 10; widthY = 10; checkerSize = 2; height = 0.2; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-sb") == 0) { doubleBuffer = GL_FALSE; } else if (strcmp(argv[i], "-db") == 0) { doubleBuffer = GL_TRUE; } else if (strcmp(argv[i], "-dr") == 0) { directRender = GL_TRUE; } else if (strcmp(argv[i], "-ir") == 0) { directRender = GL_FALSE; } else if (strcmp(argv[i], "-grid") == 0) { if (i+2 >= argc || argv[i+1][0] == '-' || argv[i+2][0] == '-') { printf("-grid (No numbers).\n"); return GL_FALSE; } else { widthX = atoi(argv[++i]); widthY = atoi(argv[++i]); } } else if (strcmp(argv[i], "-size") == 0) { if (i+1 >= argc || argv[i+1][0] == '-') { printf("-checker (No number).\n"); return GL_FALSE; } else { checkerSize = atoi(argv[++i]); } } else if (strcmp(argv[i], "-wave") == 0) { if (i+1 >= argc || argv[i+1][0] == '-') { printf("-wave (No number).\n"); return GL_FALSE; } else { height = atof(argv[++i]); } } else if (strcmp(argv[i], "-frames") == 0) { if (i+1 >= argc || argv[i+1][0] == '-') { printf("-frames (No number).\n"); return GL_FALSE; } else { frames = atoi(argv[++i]); } } else { printf("%s (Bad option).\n", argv[i]); return GL_FALSE; } } return GL_TRUE; } int main(int argc, char **argv) { GLenum type; glutInitWindowSize(300, 300); glutInit(&argc, argv); if (Args(argc, argv) == GL_FALSE) { exit(1); } type = (rgb) ? GLUT_RGB : GLUT_INDEX; type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE; glutInitDisplayMode(type); glutCreateWindow("wave"); Init(); glutReshapeFunc(Reshape); glutKeyboardFunc(Key); glutIdleFunc(Idle); glutDisplayFunc(display); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }