/* * graphics example: playing with a grid */ #include #include #include #ifdef __APPLE__ #include #else #include #endif #include #include GLubyte *gridData = NULL; int gridWidth; int gridHeight; int nx = 80, ny = 80; /* number of grid cells to draw */ int timer_active = 1; double gridZScale = 0.0; int gridLines = 1; int timerfuncmode = 0; /* ********************************************************************** */ void timerfunc(); /* change the coordinates from (-1,1) to (1,0) to place the imagemap properly. * use the scale to tile many images. */ float tex_coord(float n) { return 1 - (n+1)/2 ; } void readPPM(char *file, GLubyte **map, int *width, int *height) { FILE *fp; char buf[BUFSIZ]; int i,j,k; int n; GLubyte *grid; int is_pgm = 0; printf("reading %s...\n", file); fp = fopen(file, "r"); if(!fp) { perror(file); exit(1); } fgets(buf, BUFSIZ, fp); /* skip header (P2) */ if(strncmp(buf, "P2", 2) == 0) { is_pgm = 1; } else if(strncmp(buf, "P3", 2) == 0) { is_pgm = 0; } else { fprintf(stderr, "%s: parse error\n", file); exit(1); } fgets(buf, BUFSIZ, fp); /* skip comment(s) */ while(buf[0] == '#') { fgets(buf, BUFSIZ, fp); } { int w, h; sscanf(buf, "%d%d", &w, &h); *width = w; *height = h; printf("width=%d, height=%d\n", w, h); if(w==0 || h==0) { fprintf(stderr, "%s: bad file size\n", file); exit(1); } } fgets(buf, BUFSIZ, fp); *map = (GLubyte *)calloc(*height * *width * 4, sizeof(GLubyte)); assert(*map); /* read in data */ grid = *map; for(i=0; i< *height; i++) { for(j=0; j< *width; j++) { if(is_pgm) { int items = fscanf(fp, "%d", &n); if(items != 1) { fprintf(stderr, "%s: file read error\n", file); exit(1); } *grid++ = (GLubyte)n; *grid++ = (GLubyte)n; *grid++ = (GLubyte)n; } else for(k=0;k<3;k++) { int items = fscanf(fp, "%d", &n); if(items != 1) { fprintf(stderr, "%s: file read error\n", file); exit(1); } *grid++ = (GLubyte)n; } *grid++ = (GLubyte)255; //(*map)[(i* *width+j)*4+3]= (GLubyte)255; } } fclose(fp); } void readGrid(char *file) { readPPM(file, &gridData, &gridWidth, &gridHeight); } void init_light() { GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } void init(char *file){ readGrid(file); glClearColor(0, 0, 0, 0); /* Background color = Black*/ glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glLineStipple(1, 0xCCCC); //init_light(); } /* return the color vector to use for these grid values */ GLfloat * color(GLubyte *values, GLfloat *c) { double v; int i; int is_black = 1; for(i=0; i<4; i++) { v = (double)values[i] / 255.0; c[i] = v; if(v > 0.1 && i < 3) { is_black = 0; } } /* make sure we can see all the lines XXX */ if(is_black) { c[2] = 0.5; } //printf("color: %d -> %f\n", value, v); return c; } /* return a pointer into the grid at (approx) x,y */ GLubyte * GRID(double xd, double yd) { GLubyte *ptr; int x, y; static GLubyte zeroptr[4] = {0,0,0,0}; x = (int)xd; y = (int)yd; if(x < 0 || x >= gridWidth || y < 0 || y >= gridHeight) { ptr = zeroptr; } else { ptr = &gridData[(4 * (gridWidth * gridHeight - y * gridWidth + x) )]; } return ptr; } /* return a single value representing the grid at x,y, scaled 0...1 */ GLfloat VALUE(double x, double y) { GLubyte *ptr; double v = 0; ptr = GRID(x,y); v = ptr[0] + ptr[1] + ptr[2]; v /= (255 * 3.0); return v * gridZScale; } /* ********************************************************************** */ /* drawing functions */ void draw_grid(void) { GLfloat x, y; /* index into display */ GLfloat dx, dy; GLfloat c[4]; /* color */ double gx, gy; /* index into grid */ double gdx, gdy; GLfloat pt[3][3]; int k; dx = 2.0 / nx; dy = 2.0 / ny; glLineWidth(1); //glPolygonMode(GL_FRONT, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, (gridLines?GL_LINE:GL_FILL)); /* * walk through display and draw matching grid values */ gdx = (double)gridWidth / nx; gdy = (double)gridHeight / ny; for(y=-2; y<=2; y+=dy, gy += gdy) { if(y < -1) { gy = -gdy; } /* draw a row at a time */ glBegin(GL_TRIANGLE_STRIP); /* glColor3f(0,0,0); /\* border *\/ */ /* glVertex3f(-1, y+dy, 0); */ /* glVertex3f(-1, y, 0); */ k = 0; for(x=-2; x<=2; x+=dx, gx += gdx) { if(x < -1) { gx = -gdx; } pt[k][0] = x; pt[k][1] = y + dy; pt[k][2] = VALUE(gx, gy+gdy); glColor3fv(color(GRID(gx, gy+gdy), c)); glVertex3fv(pt[k]); k++; if(k==3) k = 0; pt[k][0] = x; pt[k][1] = y; pt[k][2] = VALUE(gx,gy); glColor3fv(color(GRID(gx, gy), c)); glVertex3fv(pt[k]); k++; if(k==3) k = 0; } /* glColor3f(0,0,0); /\* border *\/ */ /* glVertex3f(1, y+dy, 0); */ /* glVertex3f(1, y, 0); */ glEnd(); } #if 0 /* this draws a plane at z */ glBegin(GL_LINES); { GLfloat z = 1; glEdgeFlag(GL_TRUE); glColor3f(1, .5, .5); for(y=-1; y<=1; y+=dy) { glVertex3f(-1, y, z); glVertex3f(1, y, z); } for(x=-1; x<=1; x+=dx) { glVertex3f(x, -1, z); glVertex3f(x, 1, z); } } glEnd(); #endif glFlush(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_grid(); glFlush(); } void init_view() { glLoadIdentity(); gluLookAt(0, -2, 2,/* eye */ 0, 0, 0,/* center */ 0, 0, 1);/* up */ glMatrixMode (GL_PROJECTION); glLoadIdentity(); gluPerspective(60, 1 /* aspect */, 1, 10.0); glMatrixMode (GL_MODELVIEW); /* glRotatef(180, 1, 0, 0); */ /* glRotatef(60, 1, 0, 0); */ } void keypress(unsigned char key, int x, int y) { switch(key) { case '[':/* reduce number of segments drawn */ nx /= 2; ny /= 2; glutPostRedisplay(); break; case ']': nx *= 2; ny *= 2; glutPostRedisplay(); break; case 'i':/* reset to start view */ init_view(); glutPostRedisplay(); break; case 'I':/* look at back */ glLoadIdentity(); glRotatef(180, 1, 0, 0); glutPostRedisplay(); break; /* various rotations: */ case 'x': glRotatef(5.0, 1, 0, 0); glutPostRedisplay(); break; case 'y': glRotatef(5.0, 0, 1, 0); glutPostRedisplay(); break; case 'z': glRotatef(5.0, 0, 0, 1); glutPostRedisplay(); break; case 'X': glRotatef(-5.0, 1, 0, 0); glutPostRedisplay(); break; case 'Y': glRotatef(-5.0, 0, 1, 0); glutPostRedisplay(); break; case 'Z': glRotatef(-5.0, 0, 0, 1); glutPostRedisplay(); break; /* animate */ case 'a': timer_active = 1; //glutTimerFunc(100 /*ms*/, timerfunc, 2); timerfuncmode |= 2; glutIdleFunc(timerfunc); break; case 'r': timer_active = 1; //glutTimerFunc(100 /*ms*/, timerfunc, 1); timerfuncmode |= 1; glutIdleFunc(timerfunc); break; case 's': timer_active = 0; timerfuncmode = 0; glutIdleFunc(NULL); break; case 'g': gridLines ^= 1; glutPostRedisplay(); break; case 'q': /* quit */ exit(0); break; } } void timerfunc() { static double theta = 0.0; static int up = 1; int done = 0; int now, elapsed_ms; static int lastFrameTime; double step_modifier = 1.0; if(!timer_active) return; now = glutGet(GLUT_ELAPSED_TIME); elapsed_ms = now - lastFrameTime; lastFrameTime = now; step_modifier = elapsed_ms / 10; if(timerfuncmode & 1) { //theta += 0.1; /* wrap XXX */ /* should be rate limited */ glRotatef(step_modifier * .3, 0, 0, 1); /* XXX */ } if(timerfuncmode & 2) { gridLines = 1; if(up) { gridZScale += step_modifier * 0.004; } else { gridZScale -= step_modifier * 0.004; } if((gridZScale >= 1.0 && up) || (gridZScale <= 0.0 && !up)) { done = 1; if(up) gridLines = 0; up ^= 1; timerfuncmode &= ~2; } } if(!timerfuncmode) { //glutTimerFunc(100 /*ms*/, timerfunc, value); glutIdleFunc(NULL); } glutPostRedisplay(); } /* ********************************************************************** */ /* main */ int main(int argc, char **argv) { glutInit(&argc, argv); if(argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); fprintf(stderr, " must be an ascii pgm\n"); exit(1); } glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100,100); glutCreateWindow(argv[1]); init(argv[1]); glutDisplayFunc(display); glutKeyboardFunc(keypress); timer_active = 1; //glutTimerFunc(100 /*ms*/, timerfunc, 2); timerfuncmode = 2; glutIdleFunc(timerfunc); /* initial 'view' XXX */ init_view(); glutMainLoop(); return 0; }