/* Greydon Foil 2.26.04 */ /* gfoilhw5.c */ #include "gfoilhw5.h" #include #include #include #include #ifdef __APPLE__ #include #else #include #endif Grid* mainGrid; int fillToggle; int colorScheme; int resolution; int heightLevel; float pos[3] = {0, 0, 0}; float rot[3] = {0, 0, 0}; float eye[3] = {0, 0, 0}; float pitch; float yaw; /* Opens a file for reading and then parses it correctly, filling in the values of the grid structure accordingly */ Grid* readGrid(char* filename){ Grid* inGrid = (Grid*)malloc(sizeof(Grid)); if (inGrid == NULL) { printf("Memory allocation problems"); exit(1); } /* attemps to open the file and returns an error if there are problems */ FILE* fp; fp = fopen(filename, "r"); if (fp == NULL) { printf("Invalid file name\n"); exit(1); } inGrid->name = filename; char name[10]; float numF = 0; int numI = 0; /* ncols */ if (fscanf(fp, "%s", name) == EOF || fscanf(fp, "%d",&numI) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->numCols = numI; /* nrows */ if (fscanf(fp, "%s", name) == EOF || fscanf(fp, "%d", &numI) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->numRows = numI; /* x11corner */ if (fscanf(fp, "%s", name) == EOF || fscanf(fp, "%f", &numF) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->xllcorner = numF; /* y11corner */ if (fscanf(fp, "%s", name) == EOF || fscanf(fp, "%f", &numF) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->yllcorner = numF; /* cellsize */ if (fscanf(fp, "%s", name) == EOF || fscanf(fp, "%f", &numF) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->cellsize = numF; /* NODATA value */ if (fscanf(fp, "%s", name) == EOF || fscanf(fp, "%f", &numF) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->nodataVal = numF; inGrid->values = (float**)malloc(sizeof(float*)*(inGrid->numCols)); if (inGrid->values == NULL){ printf("Memory allocation problems.\n"); exit(1); } int i; for (i = 0;i < inGrid->numCols; i++) { inGrid->values[i] = (float*)malloc(sizeof(float)*(inGrid->numRows)); if (inGrid->values[i] == NULL) { printf("Memory allocation problems. \n"); exit(1); } } inGrid->smallestHeight = 999.0; inGrid->largestHeight = -999.0; int currentRow = 0; int currentCol = 0; while(fscanf(fp, "%d", &numI) != EOF) { inGrid->values[currentCol][currentRow] = numI; if (inGrid->values[currentCol][currentRow] > inGrid->largestHeight) inGrid->largestHeight = inGrid->values[currentCol][currentRow]; else if (inGrid->values[currentCol][currentRow] < inGrid->smallestHeight && inGrid->values[currentCol][currentRow] - inGrid->nodataVal) inGrid->smallestHeight = inGrid->values[currentCol][currentRow]; currentCol++; if (currentCol == inGrid->numCols) { currentCol = 0; currentRow++; } } printf("largest %f smallest %f\n", inGrid->largestHeight, inGrid->smallestHeight); fclose(fp); return inGrid; } /* readFile */ /* This just prints out information about the grid. */ void printInfo(Grid* inGrid) { printf("\nThe name of the file is: %s\n", inGrid->name); printf("The number of columns in the file is: %d\n", inGrid->numCols); printf("The number of rows in the file is: %d\n", inGrid->numRows); printf("The xll corner is: %f\n", inGrid->xllcorner); printf("The yll corner is: %f\n", inGrid->yllcorner); printf("The cell size is: %f\n", inGrid->cellsize); printf("The NODATA value is: %d\n\n", inGrid->nodataVal); } /* This method determines the orientation of the drawing to be done on the screen and then loops through the grid and draws triangles using heights in the grid as vertices and coloring those vertices according to heights. It also checks to see if any of the vertices are points with no height data and does not draw them if they do. */ void display(void) { if (fillToggle == 1) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } float ratio; float startingPointX, startingPointY; if (mainGrid->numCols > mainGrid->numRows) { ratio = 2/((float)mainGrid->numCols); startingPointX = -1; startingPointY = 1 - ((mainGrid->numCols - mainGrid->numRows)/2)* ratio; } else { ratio = 2/((float)mainGrid->numRows); startingPointX = -1 + ((mainGrid->numRows - mainGrid->numCols)/2)* ratio; startingPointY = 1; } int modX = mainGrid->numCols % resolution; int modY = mainGrid->numRows % resolution; /* This determines the relative height to the rest of the grid. Using they keys you can change the relief of the map */ float heightRatio = mainGrid->largestHeight - mainGrid->smallestHeight; heightRatio = heightRatio * heightLevel; int i, j; for (j = 0; j < mainGrid->numRows - resolution; j += resolution) { for (i = 0; i < mainGrid->numCols - resolution; i += resolution) { if (mainGrid->values[i][j] != mainGrid->nodataVal && mainGrid-> values[i+resolution][j] != mainGrid->nodataVal && mainGrid-> values[i][j+resolution] != mainGrid->nodataVal && mainGrid-> values[i+resolution][j+resolution] != mainGrid->nodataVal) { glBegin(GL_POLYGON); colorFunction(mainGrid->values[i][j]); glVertex3f(startingPointX + i*ratio, startingPointY - j*ratio, mainGrid->values[i][j]/heightRatio); colorFunction(mainGrid->values[i+resolution][j]); glVertex3f(startingPointX + (i + resolution) * ratio, startingPointY - j*ratio, mainGrid->values[i+resolution][j]/heightRatio); colorFunction(mainGrid->values[i][j+resolution]); glVertex3f(startingPointX + i*ratio, startingPointY - (j+resolution) * ratio, mainGrid->values[i][j+resolution]/heightRatio); glEnd(); glBegin(GL_POLYGON); colorFunction(mainGrid->values[i][j+resolution]); glVertex3f(startingPointX + i*ratio, startingPointY - (j+resolution)*ratio, mainGrid->values[i][j+resolution]/heightRatio); colorFunction(mainGrid->values[i+resolution][j]); glVertex3f(startingPointX + (i+resolution)* ratio, startingPointY - j*ratio, mainGrid->values[i+resolution][j]/heightRatio); colorFunction(mainGrid->values[i + resolution][j+resolution]); glVertex3f(startingPointX + (i+resolution)*ratio, startingPointY - (j+resolution)*ratio, mainGrid->values[i + resolution] [j + resolution]/heightRatio); glEnd(); if ((j + resolution * 2 > mainGrid->numRows) && (i + resolution * 2 > mainGrid->numCols)) { /* bottom corner */ if (mainGrid->values[mainGrid->numCols - 1][j+resolution] != mainGrid->nodataVal && mainGrid->values[mainGrid->numCols-1] [mainGrid->numRows-1] != mainGrid->nodataVal && mainGrid-> values[i+resolution][mainGrid->numRows-1] != mainGrid-> nodataVal && mainGrid->values[i][mainGrid->numRows-1] != mainGrid->nodataVal && mainGrid->values[mainGrid->numCols-1] [j] != mainGrid->nodataVal) { glBegin(GL_POLYGON); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution)* ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1] [j + resolution]); glVertex3f(startingPointX + (mainGrid->numCols - 1) * ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[mainGrid->numCols-1] [j+resolution]/heightRatio); colorFunction(mainGrid->values[i + resolution] [mainGrid->numRows - 1]); glVertex3f(startingPointX + (i + resolution) * ratio, startingPointY - (mainGrid->numRows - 1) * ratio, mainGrid->values[i+resolution] [mainGrid->numRows-1]/heightRatio); glEnd(); glBegin(GL_POLYGON); colorFunction(mainGrid->values[i + resolution] [mainGrid->numRows - 1]); glVertex3f(startingPointX + (i + resolution)*ratio, startingPointY - (mainGrid->numRows - 1)*ratio, mainGrid->values[i+resolution] [mainGrid->numRows-1]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1] [j + resolution]); glVertex3f(startingPointX + (mainGrid->numCols - 1)* ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[mainGrid->numCols-1] [j+resolution]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1] [mainGrid->numRows - 1]); glVertex3f(startingPointX + (mainGrid->numCols - 1)*ratio, startingPointY - (mainGrid->numRows - 1)*ratio, mainGrid->values[mainGrid->numCols-1] [mainGrid->numRows-1]/heightRatio); glEnd(); glBegin(GL_POLYGON); /* right bottom square */ colorFunction(mainGrid->values[i][j + resolution]); glVertex3f(startingPointX + (i)* ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i][j+resolution]/heightRatio); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution) * ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[i][mainGrid->numRows - 1]); glVertex3f(startingPointX + (i) * ratio, startingPointY - (mainGrid->numRows - 1) * ratio, mainGrid->values[i][mainGrid->numRows-1]/heightRatio); glEnd(); glBegin(GL_POLYGON); colorFunction(mainGrid->values[i][mainGrid->numRows - 1]); glVertex3f(startingPointX + (i)*ratio, startingPointY - (mainGrid->numRows - 1)*ratio, mainGrid->values[i][mainGrid->numRows-1]/heightRatio); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution)* ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[i + resolution] [mainGrid->numRows - 1]); glVertex3f(startingPointX + (i + resolution)*ratio, startingPointY - (mainGrid->numRows - 1)*ratio, mainGrid->values[i+resolution] [mainGrid->numRows-1]/heightRatio); glEnd(); glBegin(GL_POLYGON); /* bottom right square */ colorFunction(mainGrid->values[i + resolution][j]); glVertex3f(startingPointX + (i + resolution)* ratio, startingPointY - (j)*ratio, mainGrid->values[i+resolution][j]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1][j]); glVertex3f(startingPointX + (mainGrid->numCols - 1) * ratio, startingPointY - (j)*ratio, mainGrid->values[mainGrid->numCols-1][j]/heightRatio); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution) * ratio, startingPointY - (j + resolution) * ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); glEnd(); glBegin(GL_POLYGON); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution)*ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1][j]); glVertex3f(startingPointX + (mainGrid->numCols - 1)* ratio, startingPointY - (j)*ratio, mainGrid->values[mainGrid->numCols-1][j]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1] [j + resolution]); glVertex3f(startingPointX + (mainGrid->numCols - 1)*ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[mainGrid->numCols-1] [j+resolution]/heightRatio); glEnd(); } } else if (j + resolution * 2 > mainGrid->numRows && i + resolution < mainGrid->numCols) { /* bottom */ if (mainGrid->values[i][j+resolution] != mainGrid->nodataVal && mainGrid->values[i+resolution][j+resolution] != mainGrid-> nodataVal && mainGrid->values[i][mainGrid->numRows-1] != mainGrid->nodataVal && mainGrid->values[i+resolution] [mainGrid->numRows-1] != mainGrid->nodataVal) { glBegin(GL_POLYGON); colorFunction(mainGrid->values[i][j + resolution]); glVertex3f(startingPointX + (i)* ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i][j+resolution]/heightRatio); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution) * ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[i][mainGrid->numRows - 1]); glVertex3f(startingPointX + (i) * ratio, startingPointY - (mainGrid->numRows - 1) * ratio, mainGrid->values[i][mainGrid->numRows-1]/heightRatio); glEnd(); glBegin(GL_POLYGON); colorFunction(mainGrid->values[i][mainGrid->numRows - 1]); glVertex3f(startingPointX + (i)*ratio, startingPointY - (mainGrid->numRows - 1)*ratio, mainGrid->values[i][mainGrid->numRows-1]/heightRatio); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution)* ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[i + resolution] [mainGrid->numRows - 1]); glVertex3f(startingPointX + (i + resolution)*ratio, startingPointY - (mainGrid->numRows - 1)*ratio, mainGrid->values[i+resolution] [mainGrid->numRows-1]/heightRatio); glEnd(); } } else if ((j + resolution < mainGrid->numRows) && (i + resolution * 2 > mainGrid->numCols)) { /* right */ if(mainGrid->values[i+resolution][j] != mainGrid->nodataVal && mainGrid->values[i+resolution][j+resolution] != mainGrid->nodataVal && mainGrid->values[mainGrid->numCols-1] [j] != mainGrid->nodataVal && mainGrid->values [mainGrid->numCols-1][j+resolution] != mainGrid->nodataVal) { glBegin(GL_POLYGON); colorFunction(mainGrid->values[i + resolution][j]); glVertex3f(startingPointX + (i + resolution)* ratio, startingPointY - (j)*ratio, mainGrid->values[i+resolution][j]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1][j]); glVertex3f(startingPointX + (mainGrid->numCols - 1) * ratio, startingPointY - (j)*ratio, mainGrid->values[mainGrid->numCols-1][j]/heightRatio); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution) * ratio, startingPointY - (j + resolution) * ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); glEnd(); glBegin(GL_POLYGON); colorFunction(mainGrid->values[i + resolution][j + resolution]); glVertex3f(startingPointX + (i + resolution)*ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[i+resolution] [j+resolution]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1][j]); glVertex3f(startingPointX + (mainGrid->numCols - 1)* ratio, startingPointY - (j)*ratio, mainGrid->values[mainGrid->numCols-1][j]/heightRatio); colorFunction(mainGrid->values[mainGrid->numCols - 1] [j + resolution]); glVertex3f(startingPointX + (mainGrid->numCols - 1)*ratio, startingPointY - (j + resolution)*ratio, mainGrid->values[mainGrid->numCols-1] [j+resolution]/heightRatio); glEnd(); } } } } } } /* This function initializes all of the arrays at the beginning of the program and when a key is pressed to initialize the scene. */ void initView() { pos[0] = 0; pos[1] = -0.4; pos[2] = 0.2; rot[0] = -55; rot[1] = 0; rot[2] = 45; eye[0] = 0; eye[1] = 0; eye[2] = -3; pitch = 0; yaw = 0; } /* initView */ /* This function controls the different colors of the heights. For some cases it changes the colors based on the current height in relation to the tallest and shortest heights on the grid while in other cases it just assigns groups of heights a color. */ void colorFunction(float height) { float difference = mainGrid->largestHeight - mainGrid->smallestHeight; float color = ((height - mainGrid->smallestHeight)/difference); if (colorScheme == 0) { if (height == mainGrid->nodataVal) glColor3f(0, 0.2, 0.4); else glColor3f(color, color, color); } else if (colorScheme == 1) { if (color < 0.2) glColor3f(0, 0, color * 5); else if (color < 0.4) glColor3f(0, (color - .2) * 5, 1); else if (color < 0.6) glColor3f(0, 1, 1 - (color - .4)*5); else if (color < 0.8) glColor3f((color-.6) * 5, 1, 0); else glColor3f(1, 1- (color-.8)*5, 0); } else if (colorScheme == 2) { if (color < 0.2) glColor3f(color * 5, 0, 0); else if (color < 0.4) glColor3f(1, (color - .2) * 5, 0); else if (color < 0.6) glColor3f(1 - (color - .4)*5, 1, 0); else if (color < 0.8) glColor3f(0, 1, (color-.6) * 5); else glColor3f(0, 1- (color-.8)*5, 1); } } /* colorFunction */ /* This function handles all of the special key bindings. */ void specialKey(int key, int x, int y) { switch (key) { case GLUT_KEY_DOWN: pitch -= 1; glutPostRedisplay(); break; case GLUT_KEY_UP: pitch += 1; glutPostRedisplay(); break; case GLUT_KEY_RIGHT: yaw += 1; glutPostRedisplay(); break; case GLUT_KEY_LEFT: yaw -= 1; glutPostRedisplay(); break; } } /* specialKey */ /* This method uses the existing pos, rot, eye, center, and up arrays to determine the rotation and translation of the camera and the scene itself. */ void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, 1, 0, 10); glRotatef(pitch, 1, 0, 0); glRotatef(yaw, 0, 1, 0); glTranslatef(eye[0], eye[1], eye[2]); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(pos[0], pos[1], pos[2]); glRotatef(rot[0], 1, 0, 0); glRotatef(rot[1], 0, 1, 0); glRotatef(rot[2], 0, 0, 1); display(); glFlush(); } /* renderScene */ /* This method handles all the key binding for the program. */ void keypress(unsigned char key, int x, int y) { switch(key) { case 'q': exit(0); break; case 'w': /* this toggles fill on and off */ if (fillToggle == 0) fillToggle = 1; else fillToggle = 0; glutPostRedisplay(); break; case '>': /* this increases and decreases the resolution */ resolution ++; glutPostRedisplay(); break; case '<': if (resolution > 1) { resolution --; glutPostRedisplay(); } break; case 'e': /* this cycles through the color schemes for the terrain */ if (colorScheme < 2) colorScheme ++; else colorScheme = 0; glutPostRedisplay(); break; case 'r': /* this increases and decreases the relief of the terrain */ heightLevel++; glutPostRedisplay(); break; case 'R': if (heightLevel > 1) { heightLevel--; glutPostRedisplay(); } break; /* these keys handle the movement and rotation of the landscape */ case 'x': rot[0] += 5; glutPostRedisplay(); break; case 'X': rot[0] -= 5; glutPostRedisplay(); break; case 'c': rot[1] += 5; glutPostRedisplay(); break; case 'C': rot[1] -= 5; glutPostRedisplay(); break; case 'z': rot[2] += 5; glutPostRedisplay(); break; case 'Z': rot[2] -= 5; glutPostRedisplay(); break; case 'a': pos[2] -= 0.2; glutPostRedisplay(); break; case 'A': pos[2] += 0.2; glutPostRedisplay(); break; case 's': pos[0] -= 0.2; glutPostRedisplay(); break; case 'S': pos[0] += 0.2; glutPostRedisplay(); break; case 'd': pos[1] -= 0.2; glutPostRedisplay(); break; case 'D': pos[1] += 0.2; glutPostRedisplay(); break; /* this resets the veiw to the intial position */ case 't': initView(); glutPostRedisplay(); break; /* keys that handle the movement of the camera */ case 'b': eye[2] += 0.05; glutPostRedisplay(); break; case 'B': eye[2] -= 0.05; glutPostRedisplay(); break; } } /* keypress */ /* This method just initializes the values within the menu when you right-click the mouse. */ void main_menu(int value) { switch (value) { case 1: if (fillToggle == 0) fillToggle = 1; else fillToggle = 0; display(); break; case 2: if (colorScheme < 3) colorScheme++; else colorScheme = 0; break; case 3: exit(0); } glutPostRedisplay(); } /* main_menu */ /* Reads in the specified file if the arguments are correct and the file exists and then calls a function to build the grid, initializes openGL, and calls another function to draw the grid. */ int main(int argc, char** argv) { if (argc != 2) { printf("usage: gfoilhw4 in-grid \n\n"); exit(1); } char* inFilename; int multString; inFilename = argv[1]; mainGrid = readGrid(inFilename); printInfo(mainGrid); fillToggle = 0; /* sets fill to the off setting */ colorScheme = 0; /* sets to black and white setting */ resolution = 10; /* sets the resolution to 1 to 1 */ heightLevel = 2; /* sets it so the heights are displayed half as high */ /* initialize openGL */ glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 600); glutCreateWindow(argv[0]); glClearColor(0, 0, 0, 0); glColor3f(1, 1, 1); glutDisplayFunc(renderScene); glutKeyboardFunc(keypress); glutSpecialFunc(specialKey); initView(); glutCreateMenu(main_menu); glutAddMenuEntry("Fill/Outline", 1); glutAddMenuEntry("Change color scheme", 2); glutAddMenuEntry("Quit", 3); glutAttachMenu(GLUT_LEFT_BUTTON); glutMainLoop(); return 1; } /* main */