/* Greydon Foil 5.21.04 */ /* ppmRender.c */ #include "ppmRender.h" #include #include #include #include #ifdef __APPLE__ #include #else #include #endif Grid* mainGrid; normalGrid* normGrid; int fillToggle; int colorScheme; int lightToggle; int fogEnabled; float ratio; float heightAdjust; float pos[3] = {0, 0, 0}; float rot[3] = {0, 0, 0}; float eye[3] = {0, 0, 0}; float lightColor[4] = {0, 0, 0, 1}; float light[4] = {0, 0, 0.50, 1.0}; float pitch; float yaw; int mouseX, mouseY, mouseIdle; /* This function is used to quickly calculate the height at a given point, then returning that point. */ static inline point findHeight(int x, int y) { point p; p.x = (float)y; // col p.y = (float)x; // row p.z = (float)(mainGrid->maxValue * 3 - (mainGrid->values[x][y] + mainGrid->values[x][y+1] + mainGrid->values[x][y + 2])/(mainGrid->maxValue * 3)); return p; } /* findHeight */ /* Listens for commands from the user and then calls the appropriate functions depending on those commands. There are two different possibilities for the user to choose, two-dimensional viewing and three-dimensional viewing. */ int main(int argc, char** argv) { if (argc != 1) { printf("usage: ppmTest \n\n"); exit(1); } char inFilename[80]; char outFilename[80]; char str[30]; fillToggle = 1; /* sets fill to the on setting */ colorScheme = 0; /* sets to color setting */ lightToggle = 0; /* sets the mouse to move the scene */ fogEnabled = 0; /* fog is disabled */ heightAdjust = 0; /* height of the light above the terrain */ /* Loop to check the user's input into the program */ while (1) { printf("\n\tAvailable commands are '2d' to render in two dimensions\n"); printf("\tand '3d' to render in three dimensions, or 'exit'.\n\n"); printf("Graphics>>: "); scanf("%30s", str); /* This loads up the three-dimensional viewing using the specified file name */ if (strcmp("3d", str) == 0) { printf("Enter the filename:: "); scanf("%80s", inFilename); printf("Reading in %s...\n", inFilename); mainGrid = readGrid(inFilename); /* This reads in the file and builds the grid */ findRatio(); /* This finds the ratio between height and width */ findAllNormals(); /* This iterates through the points in the grid to calculate the normal at each point, storing that normal in a separate grid structure */ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); /* If, for some reason, the line glutEnterGameMode(); causes viewing errors, uncomment these three lines to use the original viewing method */ /* glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); */ glutGameModeString("800x600"); glutEnterGameMode(); /* enables full-screen viewing */ glClearColor(0, 0, 0, 0); glColor3f(1, 1, 1); initView(); /* This initializes the viewing angles and position */ /* callback methods */ glutKeyboardFunc(keypress3d); glutSpecialFunc(specialKey); glutMotionFunc(mouseFunction); glutPassiveMotionFunc(mouseIdleFunction); glutDisplayFunc(renderScene); glutCreateMenu(main_menu); glutAddMenuEntry("Fill/Outline", 1); glutAddMenuEntry("Change color scheme", 2); glutAddMenuEntry("Quit", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); glEnable(GL_CULL_FACE); /* disables rendering the back side of polygons */ glEnable(GL_DEPTH_TEST); /* depth testing */ glEnable(GL_COLOR_MATERIAL); /* enables the glColor3f calls when rendering */ glEnable(GL_POLYGON_SMOOTH); /* enables smoothing of polygons */ glutMainLoop(); } /* This handlesa the viewing of an image in two dimensions. Besides the different callbacks, all of these methods are similar to those for viewing in three dimensions. */ else if (strcmp("2d", str) == 0) { printf("Enter the filename:: "); scanf("%80s", inFilename); printf("Reading in %s...\n", inFilename); mainGrid = readGrid(inFilename); findRatio(); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glEnable(GL_DEPTH_TEST); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); glClearColor(0, 0.2, 0.4, 0); glColor3f(0, 1, 1); glutDisplayFunc(display2d); glutKeyboardFunc(keypress2d); glutCreateMenu(main_menu); glutAddMenuEntry("Fill/Outline", 1); glutAddMenuEntry("Change color scheme", 2); glutAddMenuEntry("Quit", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop(); } else if (strcmp("exit", str) == 0) { exit(0); } } } /* main */ /* This method initializes all of the lighting functions and lights as well as fog */ void initLighting(void) { float mat_specular[] = {0.2, 0.2, 0.2}; /* This dictates how the terrain will look when lit by a specular light */ glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glLightfv(GL_LIGHT0, GL_SPECULAR, lightColor); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); if (fogEnabled) glEnable(GL_FOG); else glDisable(GL_FOG); glFogf(GL_FOG_START, 0.0); glFogf(GL_FOG_DENSITY, 1.0); float fog_color[] = {0.3, 0.2, 0.7, 1.0}; /* a dark blue color */ glFogfv(GL_FOG_COLOR, fog_color); } /* This method is called each time the scene needs to be redrawn when using 3d mode. It first initializes the viewpoint of the camera and then places the light and draws a square in the same position (for reference) and then draws the scene */ void renderScene(void) { initLighting(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, 1, 0.01, 10); glTranslatef(0,0,-3); glRotatef(pitch, 1, 0, 0); glRotatef(yaw, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(rot[0], 1, 0, 0); glRotatef(rot[1], 0, 1, 0); glRotatef(rot[2], 0, 0, 1); glPushMatrix(); light[0] = eye[0]; light[1] = eye[1]; light[2] = eye[2]; /* draws the small square at the same position as the light */ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBegin(GL_QUADS); glColor3f(1, 0, 0); glVertex3f(eye[0], eye[1], eye[2]); glVertex3f(eye[0]+ 2*ratio, eye[1], eye[2]); glVertex3f(eye[0] + 2*ratio, eye[1] + 2*ratio, eye[2]); glVertex3f(eye[0], eye[1] + 2*ratio, eye[2]); glEnd(); glLightfv(GL_LIGHT0, GL_POSITION, light); glPopMatrix(); display3d(); glutSwapBuffers(); } /* renderScene */ /* This method initializes the camera and light positions */ void initView(void) { pos[0] = 0; pos[1] = 0; pos[2] = 0; rot[0] = 0; rot[1] = 0; rot[2] = 0; eye[0] = 0; eye[1] = 0; adjustHeights(); /* sets eye[2] (the z-position of the light) using the grid's height value at that x- and y-coordinate */ pitch = 0; yaw = 0; } /* initView */ /* This just calculates the ratio between the width and the height depending on the number of rows versus columns in the grid */ void findRatio(void) { if (mainGrid->numCols > mainGrid->numRows) { ratio = 2/((float)mainGrid->numCols -1); } else { ratio = 2/((float)mainGrid->numRows-1); } } /* findRatio */ /* This method is used to either rotate the image or move the light source around on the stage, depending on the current value of lightToggle. It is called while the mouse is pressed down and moves away from its current position */ void mouseFunction(int x, int y) { /* If the mouse was just idle (not pressed), then this is the first time it's been pressed and moved so we change the cursor and make sure we don't change it again */ if (mouseIdle) { glutSetCursor(GLUT_CURSOR_CYCLE); /* changes the cursor to a pair of rotating arrows */ mouseIdle = 0; } /* These are used to see how the mouse has moved relative to its last known position */ int lastMouseX = mouseX; int lastMouseY = mouseY; mouseX = x; mouseY = y; /* rotates the terrain according to how the mouse has been moved */ if (lightToggle == 0) { if (mouseX > lastMouseX) yaw += 1; else if (mouseX < lastMouseX) yaw -= 1; if (mouseY > lastMouseY) pitch -= 1; else if (mouseY < lastMouseY) pitch += 1; } /* moves the light according to how the mouse has moved */ else { if (mouseX > lastMouseX && eye[0] < 1-ratio) eye[0] += ratio; else if (mouseX < lastMouseX && eye[0] > -1 + ratio) eye[0] -= ratio; if (mouseY > lastMouseY && eye[1] > -1 + ratio) eye[1] -= ratio; else if (mouseY < lastMouseY && eye[1] < 1-ratio) eye[1] += ratio; adjustHeights(); } glutPostRedisplay(); } /* mouseFunction */ /* This is called when the mouse moves and no mouse buttons are pressed. it resets the cursor if the mouse button was just pressed and updates the current position of the mouse */ void mouseIdleFunction(int x, int y) { if (!mouseIdle){ glutSetCursor(GLUT_CURSOR_LEFT_ARROW); mouseIdle = 1; } mouseX = x; mouseY = y; } /* mouseIdleFunction */ /* This handles all of the key bindings for the 3d version of the program */ void keypress3d(unsigned char key, int x, int y) { switch(key) { case 'q': exit(0); break; case 'f': if (fillToggle == 0) fillToggle = 1; else fillToggle = 0; glutPostRedisplay(); break; case 'e': if (colorScheme < 1) colorScheme ++; else colorScheme = 0; glutPostRedisplay(); break; 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 't': initView(); glutPostRedisplay(); break; case 'l': if (lightToggle == 0) lightToggle = 1; else lightToggle = 0; break; case 'i': if (fogEnabled) { fogEnabled = 0; glDisable(GL_FOG); } else { fogEnabled = 1; glEnable(GL_FOG); } glutPostRedisplay(); break; case 'r': if (lightColor[0] > 0) { lightColor[0] -= 0.1; glutPostRedisplay(); } break; case 'R': if (lightColor[0] < 1) { lightColor[0] += 0.1; glutPostRedisplay(); } break; case 'g': if (lightColor[1] > 0) { lightColor[1] -= 0.1; glutPostRedisplay(); } break; case 'G': if (lightColor[1] < 1) { lightColor[1] += 0.1; glutPostRedisplay(); } break; case 'b': if (lightColor[2] > 0) { lightColor[2] -= 0.1; glutPostRedisplay(); } break; case 'B': if (lightColor[2] < 1) { lightColor[2] += 0.1; glutPostRedisplay(); } break; case 'd': /* moves the light right */ if (eye[0] < 1 - ratio) { eye[0] += ratio; adjustHeights(); glutPostRedisplay(); } break; case 'a': /* moves the light left */ if (eye[0] > -1 + ratio) { eye[0] -= ratio; adjustHeights(); glutPostRedisplay(); } break; case 's': /* moves the light down */ if (eye[1] > -1 + ratio) { eye[1] -= ratio; adjustHeights(); glutPostRedisplay(); } break; case 'w': /* moves the light up */ if (eye[1] < 1 - ratio) { eye[1] += ratio; adjustHeights(); glutPostRedisplay(); } break; case 'n': heightAdjust += ratio; eye[2] += ratio; glutPostRedisplay(); break; case 'N': heightAdjust -= ratio; eye[2] -= ratio; glutPostRedisplay(); break; } } /* keypress3d */ /* This method checks the current position of the light and calculates where it should be in relation to the terrain */ void adjustHeights(void) { int tx, ty; tx = mainGrid->numRows - (int)(floor(mainGrid->numRows/2) + eye[1]/ratio); ty = (int)(mainGrid->numCols - floor(mainGrid->numCols/2) + eye[0]/ratio) *3; eye[2] = 5*ratio + heightAdjust + (1 - (float)(mainGrid->values[tx][ty] + mainGrid->values[tx][ty+1] + mainGrid->values[tx][ty+2]) / (float)(mainGrid->maxValue*3)); } /* adjustHeights */ /* This handles the key-bindings for the arrow keys */ 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(); case GLUT_KEY_RIGHT: yaw += 1; glutPostRedisplay(); break; case GLUT_KEY_LEFT: yaw -= 1; glutPostRedisplay(); break; } } /* specialKey */ /* This handles the creation of the menu */ void main_menu(int value) { switch (value) { case 1: if (fillToggle == 0) fillToggle = 1; else fillToggle = 0; glutPostRedisplay(); break; case 2: if (colorScheme < 1) colorScheme++; else colorScheme = 0; break; case 3: exit(0); } glutPostRedisplay(); } /* main_menu */ /* 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. */ void display3d(void) { if (fillToggle == 1) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } float startingPointX, startingPointY; if (mainGrid->numCols > mainGrid->numRows) { startingPointX = -1; startingPointY = 1 - ((float)(mainGrid->numCols - mainGrid->numRows)/2)*ratio; } else { startingPointX = -1 + ((float)(mainGrid->numRows - mainGrid->numCols)/2)*ratio; startingPointY = 1; } int highest = mainGrid->maxValue * 3; /* the maximum value for the averages of the color values */ /* iterates through the grid, drawing all of the triangles and assigning normal vectors and colors for each of the points */ point norm; int i, j; for (i = 0; i < mainGrid->numRows-1; i++) { for (j = 0; j < (mainGrid->numCols-1) * 3; j+= 3) { glBegin(GL_TRIANGLE_STRIP); /* can be faster than GL_TRIANGLES */ norm = normGrid->values[i][j]; colorFunction(mainGrid->values[i][j], mainGrid->values[i][j+1], mainGrid->values[i][j+2]); glNormal3f(norm.x, norm.y, norm.z); glVertex3f(startingPointX + (float)(j/3)*ratio, startingPointY - (float)i*ratio, (1 - (float)(mainGrid->values[i][j] + mainGrid->values[i][j+1] + mainGrid->values[i][j+2])/(float)highest)); norm = normGrid->values[i+1][j]; colorFunction(mainGrid->values[i+1][j], mainGrid->values[i+1][j+1], mainGrid->values[i+1][j+2]); glNormal3f(norm.x, norm.y, norm.z); glVertex3f(startingPointX + (float)(j/3)* ratio, startingPointY - (float)(i+1)*ratio, (1 - (float)(mainGrid->values[i+1][j] + mainGrid->values[i+1][j+1] + mainGrid->values[i+1][j+2])/(float)highest)); norm = normGrid->values[i][j+3]; colorFunction(mainGrid->values[i][j+3], mainGrid->values[i+1][j+4], mainGrid->values[i][j+5]); glNormal3f(norm.x, norm.y, norm.z); glVertex3f(startingPointX + (float)(j/3 + 1)*ratio, startingPointY - (float)(i) * ratio, (1 - (float)(mainGrid->values[i][j+3] + mainGrid->values[i][j+4] + mainGrid->values[i][j+5])/(float)highest)); glEnd(); glBegin(GL_TRIANGLE_STRIP); norm = normGrid->values[i][j+3]; colorFunction(mainGrid->values[i][j+3], mainGrid->values[i][j+4], mainGrid->values[i][j+5]); glNormal3f(norm.x, norm.y, norm.z); glVertex3f(startingPointX + (float)(j/3 +1)*ratio, startingPointY - (float)(i)*ratio, (1 - (float)(mainGrid->values[i][j+3] + mainGrid->values[i][j+4] + mainGrid->values[i][j+5])/(float)highest)); norm = normGrid->values[i+1][j]; colorFunction(mainGrid->values[i+1][j], mainGrid->values[i+1][j+1], mainGrid->values[i+1][j+2]); glNormal3f(norm.x, norm.y, norm.z); glVertex3f(startingPointX + (float)(j/3)* ratio, startingPointY - (float)(i+1)*ratio, (1 - (float)(mainGrid->values[i+1][j] + mainGrid->values[i+1][j+1] + mainGrid->values[i+1][j+2])/(float)highest)); norm = normGrid->values[i+1][j+3]; colorFunction(mainGrid->values[i+1][j+3], mainGrid->values[i+1][j+4], mainGrid->values[i+1][j+5]); glNormal3f(norm.x, norm.y, norm.z); glVertex3f(startingPointX + (float)(j/3 +1)*ratio, startingPointY - (float)(i+1)*ratio, (1 - (float)(mainGrid->values[i+1][j+3] + mainGrid->values[i+1][j+4] + mainGrid->values[i+1][j+5])/(float)highest)); glEnd(); } } glFlush(); } /* display3d */ /* 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. */ void display2d(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (fillToggle == 1) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } float startingPointX, startingPointY; if (mainGrid->numCols > mainGrid->numRows) { startingPointX = -1; startingPointY = 1 - ((float)(mainGrid->numCols - mainGrid->numRows)/2)*ratio; } else { startingPointX = -1 + ((float)(mainGrid->numRows - mainGrid->numCols)/2)*ratio; startingPointY = 1; } int i, j; for (j = 0; j < mainGrid->numRows-1; j++) { for (i = 0; i < (mainGrid->numCols-1) * 3; i+= 3) { glBegin(GL_TRIANGLE_STRIP); colorFunction(mainGrid->values[j][i], mainGrid->values[j][i+1], mainGrid->values[j][i+2]); glVertex2f(startingPointX + (float)(i/3)*ratio, startingPointY - (float)j*ratio); colorFunction(mainGrid->values[j+1][i], mainGrid->values[j+1][i+1], mainGrid->values[j+1][i+2]); glVertex2f(startingPointX + (float)(i/3)* ratio, startingPointY - (float)(j+1)*ratio); colorFunction(mainGrid->values[j][i+3], mainGrid->values[j+1][i+4], mainGrid->values[j][i+5]); glVertex2f(startingPointX + (float)(i/3 + 1)*ratio, startingPointY - (float)(j) * ratio); glEnd(); glBegin(GL_TRIANGLE_STRIP); colorFunction(mainGrid->values[j][i+3], mainGrid->values[j][i+4], mainGrid->values[j][i+5]); glVertex2f(startingPointX + (float)(i/3 +1)*ratio, startingPointY - (float)(j)*ratio); colorFunction(mainGrid->values[j+1][i], mainGrid->values[j+1][i+1], mainGrid->values[j+1][i+2]); glVertex2f(startingPointX + (float)(i/3)* ratio, startingPointY - (float)(j+1)*ratio); colorFunction(mainGrid->values[j+1][i+3], mainGrid->values[j+1][i+4], mainGrid->values[j+1][i+5]); glVertex2f(startingPointX + (float)(i/3 +1)*ratio, startingPointY - (float)(j+1)*ratio); glEnd(); } } glFlush(); } /* display2d */ /* function that 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(int heightR, int heightG, int heightB) { if (colorScheme == 0){ /* original image */ glColor3f((float)(heightR)/(float)mainGrid->maxValue, (float)(heightG)/(float)mainGrid->maxValue, (float)(heightB)/(float)mainGrid->maxValue); } else if (colorScheme == 1) { /* black and white */ float avg = (float)(heightR + heightG + heightB)/ ((float)mainGrid->maxValue * 3); glColor3f(avg, avg, avg); } } /* colorFunction */ /* This handles the key-binding for the 2d part of the program */ void keypress2d(unsigned char key, int x, int y) { switch(key) { case 'q': exit(0); break; case 'f': if (fillToggle == 0) fillToggle = 1; else fillToggle = 0; glutPostRedisplay(); break; case 'e': if (colorScheme < 1) colorScheme ++; else colorScheme = 0; glutPostRedisplay(); break; } } /* keypress2d */ /* This just prints out information about the grid. */ void printInfo(Grid* inGrid) { 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 maxValue is: %d\n", inGrid->maxValue); } /* printInfo */ /* This method iterates through the grid and, depending on what point it is current calculating the normal for, finds all the normals of that point and the surrounding verticesa and then averages them, storing that average in the normGrid array */ void findAllNormals(void) { buildNormalGrid(); /* allocates memory for the normGrid array */ printf("Calculating the normal grid for the graph... \n"); int i, j; for (i = 0; i < mainGrid->numRows; i++) { for (j = 0; j < mainGrid->numCols * 3; j+= 3) { point center; center = findHeight(i, j); if (i == 0 && j == 0) { /* upper-left corner point */ point normal1, left, right; left = findHeight(i, j+3); right = findHeight(i+1, j); normal1 = calcNormal(center, left, right); normGrid->values[i][j] = normal1; } else if (j == 0 && i == mainGrid->numRows -1) { /* lower-left corner */ point normal1, normal2, left, right; left = findHeight(i-1, j); right = findHeight(i-1, j+3); normal1 = calcNormal(center, left, right); left = findHeight(i, j+3); normal2 = calcNormal(center, right, left); normal1.x = (normal1.x + normal2.x)/2; normal1.y = (normal1.y + normal2.y)/2; normal1.z = (normal1.z + normal2.z)/2; normGrid->values[i][j] = normal1; } else if (j == 0) { /* left side points */ point normal1, normal2, normal3, left, right; left = findHeight(i-1, j); right = findHeight(i-1, j+3); normal1 = calcNormal(center, left, right); left = findHeight(i, j+3); normal2 = calcNormal(center, right, left); right = findHeight(i+1, j); normal3 = calcNormal(center, left, right); normal1.x = (normal1.x + normal2.x + normal3.x)/3; normal1.y = (normal1.y + normal2.y + normal3.y)/3; normal1.z = (normal1.z + normal2.z + normal3.z)/3; normGrid->values[i][j] = normal1; } else if (i == 0 && j == mainGrid->numCols/3 - 3) { /*upper-right corner */ point normal1, normal2, left, right; left = findHeight(i, j-3); right = findHeight(i+1, j-3); normal1 = calcNormal(center, left, right); left = findHeight(i+1, j); normal2 = calcNormal(center, right, left); normal1.x = (normal1.x + normal2.x)/2; normal1.y = (normal1.y + normal2.y)/2; normal1.z = (normal1.z + normal2.z)/2; normGrid->values[i][j] = normal1; } else if (i == 0) { /* top row of points */ point normal1, normal2, normal3, left, right; left = findHeight(i, j-3); right = findHeight(i+1, j-3); normal1 = calcNormal(center, left, right); left = findHeight(i+1, j); normal2 = calcNormal(center, right, left); right = findHeight(i, j+3); normal3 = calcNormal(center, left, right); normal1.x = (normal1.x + normal2.x + normal3.x)/3; normal1.y = (normal1.y + normal2.y + normal3.y)/3; normal1.z = (normal1.z + normal2.z + normal3.z)/3; normGrid->values[i][j] = normal1; } /* lower-right corner */ else if (i == mainGrid->numRows -1 && j == mainGrid->numCols/3 -3) { point normal1, left, right; left = findHeight(i-1, j); right = findHeight(i, j-3); normal1 = calcNormal(center, left, right); normGrid->values[i][j] = normal1; } else if (i == mainGrid->numRows - 1) { /* bottom row of points */ point normal1, normal2, normal3, left, right; left = findHeight(i, j-3); right = findHeight(i-1, j); normal1 = calcNormal(center, left, right); left = findHeight(i-1, j+3); normal2 = calcNormal(center, right, left); right = findHeight(i, j+3); normal3 = calcNormal(center, left, right); normal1.x = (normal1.x + normal2.x + normal3.x)/3; normal1.y = (normal1.y + normal2.y + normal3.y)/3; normal1.z = (normal1.z + normal2.z + normal3.z)/3; normGrid->values[i][j] = normal1; } else if (j == mainGrid->numCols/3 - 3) { /* right column of points */ point normal1, normal2, normal3, left, right; left = findHeight(i-1, j); right = findHeight(i, j-3); normal1 = calcNormal(center, left, right); left = findHeight(i+1, j-3); normal2 = calcNormal(center, right, left); right = findHeight(i+1, j); normal3 = calcNormal(center, left, right); normal1.x = (normal1.x + normal2.x + normal3.x)/3; normal1.y = (normal1.y + normal2.y + normal3.y)/3; normal1.z = (normal1.z + normal2.z + normal3.z)/3; normGrid->values[i][j] = normal1; } else { /* all other central points */ point normal1, normal2, normal3, normal4, normal5, normal6, left, right; left = findHeight(i, j-3); right = findHeight(i-1, j); normal1 = calcNormal(center, left, right); left = findHeight(i-1, j+3); normal2 = calcNormal(center, right, left); right = findHeight(i, j+3); normal3 = calcNormal(center, left, right); left = findHeight(i+1, j); normal4 = calcNormal(center, right, left); right = findHeight(i+1, j-3); normal5 = calcNormal(center, left, right); left = findHeight(i, j-3); normal6 = calcNormal(center, right, left); normal1.x = (normal1.x + normal2.x + normal3.x + normal4.x + normal5.x + normal6.x)/6; normal1.y = (normal1.y + normal2.y + normal3.y + normal4.y + normal5.y + normal6.y)/6; normal1.z = (normal1.z + normal2.z + normal3.z + normal4.z + normal5.z + normal6.z)/6; normGrid->values[i][j] = normal1; } } } } /* findAllNormals */ /* This method allocates the space for the normGrid array */ void buildNormalGrid(void) { normGrid = (normalGrid*)malloc(sizeof(normalGrid)); assert(normGrid); normGrid->values = (point**)malloc(sizeof(point*)*(mainGrid->numRows)); if (normGrid->values == NULL) { printf("Memory allocation problems.\n"); exit(1); } int i; for (i = 0; i < mainGrid->numRows; i++) { normGrid->values[i] = (point*)malloc(sizeof(point)* (mainGrid->numCols * 3)); if (normGrid->values[i] == NULL) { printf("Memory allocation problems.\n"); exit(1); } } } /* buildNormalGrid */ /* 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); } char name[10]; int numI = 0; /* ncols */ if (fscanf(fp, "%s", name) == EOF) { printf("Error reading file.\n"); exit(1); } 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, "%d", &numI) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->numRows = numI; /* maxValue */ if (fscanf(fp, "%d", &numI) == EOF) { printf("Error reading file.\n"); exit(1); } inGrid->maxValue = numI; inGrid->values = (int**)malloc(sizeof(int*)*(inGrid->numRows)); if (inGrid->values == NULL){ printf("Memory allocation problems.\n"); exit(1); } int i; for (i = 0;i < inGrid->numRows; i++) { inGrid->values[i] = (int*)malloc(sizeof(int)*(inGrid->numCols * 3)); if (inGrid->values[i] == NULL) { printf("Memory allocation problems. \n"); exit(1); } } int currentRow = 0; int currentCol = 0; int numI1, numI2, numI3; while(fscanf(fp, "%d", &numI1) != EOF && fscanf(fp, "%d", &numI2) != EOF && fscanf(fp, "%d", &numI3) != EOF) { inGrid->values[currentRow][currentCol] = numI1; inGrid->values[currentRow][currentCol + 1] = numI2; inGrid->values[currentRow][currentCol + 2] = numI3; currentCol += 3; if (currentCol == inGrid->numCols * 3) { currentCol = 0; currentRow++; } } fclose(fp); return inGrid; } /* readFile */