#include "stdafx.h" #include #include "glut.h" #include "utils.h" #include "camera.h" #pragma unmanaged Camera theCamera(Camera::AIRCRAFT); float finalTerrainTexture[MAP_SIZE+1][MAP_SIZE+1][3]; float fovy = 45.0, aspect, zNear = 1.0, zFar = 1000.0; float randoms[NUMBER_OF_SPHERES+4][6]; float roughness = .9f; float terrain[MAP_SIZE+1][MAP_SIZE+1]; float terrainTexture1[MAP_SIZE+1][MAP_SIZE+1][3]; float terrainTexture2[MAP_SIZE+1][MAP_SIZE+1][3]; float terrainTexture4[MAP_SIZE+1][MAP_SIZE+1][3]; float terrainTexture8[MAP_SIZE+1][MAP_SIZE+1][3]; float terrainTexture16[MAP_SIZE+1][MAP_SIZE+1][3]; int treeMap[MAP_SIZE][MAP_SIZE]; MATRIX4X4 lightProjectionMatrix, lightViewMatrix; MATRIX4X4 cameraProjectionMatrix, cameraViewMatrix; GLuint shadowMapTexture; int treeCount = 0; int windowWidth = glutGet(GLUT_SCREEN_WIDTH) - 100; int windowHeight = windowWidth/2; VECTOR3D lightPos(0.0f, (MAP_SIZE), 0.0f); // given random numbers x1 and x2 with equal distribution from -1 to 1 // generate numbers y1 and y2 with normal distribution centered at 0.0 // and with standard deviation 1.0. void Gaussian(float &y1, float &y2) { float x1, x2, w; do { x1 = 2.0 * 0.001*(float)(rand()%1001) - 1.0; x2 = 2.0 * 0.001*(float)(rand()%1001) - 1.0; w = x1 * x1 + x2 * x2; } while ( w >= 1.0 ); w = sqrt( (-2.0 * log( w ) ) / w ); y1 = x1 * w; y2 = x2 * w; } //ymid = (y(a)+y(b))/2 + r //r = srg|b-a|, float midpoint(float a, float b, int width) { float temp1 = rand() % 1000 + 1; float temp2 = rand() % 1000 + 1; Gaussian(temp1, temp2); float r = roughness * temp1 * width; float ymid = (a + b)/2 + r; return ymid; } // the recursive midpoint displacement algorithm void recursive(int x, int z, int width) { if (width > 1) { int half = width/2; terrain[x+half][z] = midpoint(terrain[x][z], terrain[x+width][z], width); terrain[x+width][z+half] = midpoint(terrain[x+width][z], terrain[x+width][z+width], width); terrain[x+half][z+width] = midpoint(terrain[x+width][z+width], terrain[x][z+width], width); terrain[x][z+half] = midpoint(terrain[x][z+width], terrain[x][z], width); terrain[x+half][z+half] = (terrain[x+half][z] + terrain[x+width][z+half] + terrain[x+half][z+width] + terrain[x][z+half]) / 4; recursive(x, z, half); recursive(x+half, z, half); recursive(x+half, z+half, half); recursive(x, z+half, half); } } // initialization of the corners and calls the recursive function that calculates each point using midpoint displacement void getHeightField() { // Initialize the corners of the height field int rand1 = rand() % 256; int rand2 = rand() % 256; int rand3 = rand() % 256; int rand4 = rand() % 256; terrain[0][0] = rand1; terrain[0][MAP_SIZE] = rand2; terrain[MAP_SIZE][MAP_SIZE] = rand3; terrain[MAP_SIZE][0] = rand4; recursive(0, 0, MAP_SIZE); } void noiseHelper(int lod, float a[MAP_SIZE+1][MAP_SIZE+1][3]) { int halfLoD = lod/2; for (int i=halfLoD; i<(MAP_SIZE+1); i+=lod) { for (int j=0; j<(MAP_SIZE+1); j+=lod) { if (terrain[i][j] < 10.0f) { a[i][j][0] = 0; a[i][j][1] = 0; a[i][j][2] = (a[i-halfLoD][j][2] + a[i+halfLoD][j][2]) / 2; } else if (terrain[i][j] < 255.0f) { a[i][j][0] = 0; a[i][j][1] = (a[i-halfLoD][j][1] + a[i+halfLoD][j][1]) / 2; a[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { a[i][j][0] = (a[i-halfLoD][j][0] + a[i+halfLoD][j][0]) / 2; a[i][j][1] = (a[i-halfLoD][j][1] + a[i+halfLoD][j][1]) / 2; a[i][j][2] = (a[i-halfLoD][j][2] + a[i+halfLoD][j][2]) / 2; } } } for (int i=0; i<(MAP_SIZE+1); i+=lod) { for (int j=halfLoD; j<(MAP_SIZE+1); j+=lod) { if (terrain[i][j] < 10.0f) { a[i][j][0] = 0; a[i][j][1] = 0; a[i][j][2] = (a[i][j-halfLoD][2] + a[i][j+halfLoD][2]) / 2; } else if (terrain[i][j] < 255.0f) { a[i][j][0] = 0; a[i][j][1] = (a[i][j-halfLoD][1] + a[i][j+halfLoD][1]) / 2; a[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { a[i][j][0] = (a[i][j-halfLoD][0] + a[i][j+halfLoD][0]) / 2; a[i][j][1] = (a[i][j-halfLoD][1] + a[i][j+halfLoD][1]) / 2; a[i][j][2] = (a[i][j-halfLoD][2] + a[i][j+halfLoD][2]) / 2; } } } for (int i=halfLoD; i<(MAP_SIZE+1); i+=lod) { for (int j=halfLoD; j<(MAP_SIZE+1); j+=lod) { if (terrain[i][j] < 10.0f) { a[i][j][0] = 0; a[i][j][1] = 0; a[i][j][2] = (a[i][j+halfLoD][2] + a[i+halfLoD][j][2] + a[i][j-halfLoD][2] + a[i-halfLoD][j][2]) / 4; } else if (terrain[i][j] < 255.0f) { a[i][j][0] = 0; a[i][j][1] = (a[i][j+halfLoD][1] + a[i+halfLoD][j][1] + a[i][j-halfLoD][1] + a[i-halfLoD][j][1]) / 4; a[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { a[i][j][0] = (a[i][j+halfLoD][0] + a[i+halfLoD][j][0] + a[i][j-halfLoD][0] + a[i-halfLoD][j][0]) / 4; a[i][j][1] = (a[i][j+halfLoD][1] + a[i+halfLoD][j][1] + a[i][j-halfLoD][1] + a[i-halfLoD][j][1]) / 4; a[i][j][2] = (a[i][j+halfLoD][2] + a[i+halfLoD][j][2] + a[i][j-halfLoD][2] + a[i-halfLoD][j][2]) / 4; } } } } void noise(int lod, float a[MAP_SIZE+1][MAP_SIZE+1][3]) { for (int z=0; z<(MAP_SIZE+1); z+=lod) { for (int x=0; x<(MAP_SIZE+1); x+=lod) { float r = (float)((float)(rand() % 256) / 255.0f); if (terrain[x][z] < 10.0f) { a[x][z][0] = 0; a[x][z][1] = 0; a[x][z][2] = r; } else if (terrain[x][z] < 255.0f) { a[x][z][0] = 0; a[x][z][1] = r; a[x][z][2] = 0; } else // (terrain[x][z] >= 255.0f) { a[x][z][0] = .5 + r; a[x][z][1] = .5 + r; a[x][z][2] = .5 + r; } } } if (lod > 1) noiseHelper(lod, a); if (lod > 2) { int halfLoD = lod/2; noiseHelper(halfLoD, a); } if (lod > 4) { int quarterLoD = lod/4; noiseHelper(quarterLoD, a); } if (lod > 8) { int eighthLoD = lod/8; noiseHelper(eighthLoD, a); } } void turbulence() { noise(1, terrainTexture1); noise(2, terrainTexture2); noise(4, terrainTexture4); noise(8, terrainTexture8); noise(16, terrainTexture16); for (int z=0; z<(MAP_SIZE+1); z++) { for (int x=0; x<(MAP_SIZE+1); x++) { finalTerrainTexture[x][z][0] = (terrainTexture16[x][z][0]/2 + terrainTexture8[x][z][0]/4 + terrainTexture4[x][z][0]/8 + terrainTexture2[x][z][0]/16 + terrainTexture1[x][z][0]/32); finalTerrainTexture[x][z][1] = (terrainTexture16[x][z][1]/2 + terrainTexture8[x][z][1]/4 + terrainTexture4[x][z][1]/8 + terrainTexture2[x][z][0]/16 + terrainTexture1[x][z][0]/32); finalTerrainTexture[x][z][2] = (terrainTexture16[x][z][2]/2 + terrainTexture8[x][z][2]/4 + terrainTexture4[x][z][2]/8 + terrainTexture2[x][z][0]/16 + terrainTexture1[x][z][0]/32); } } } void renderTerrain() { glNormal3f(0.0, 1.0, 0.0); for (int z=0; z= 10.0f) { int temp = rand() % 1001; if (temp < 10) // 1.0% { treeMap[x][z] = 1; // tree1 treeCount++; } } else treeMap[x][z] = 0; } } } void drawScene() { static GLuint sunList = 0, terrainList = 0; if(!sunList) { sunList = glGenLists(1); glNewList(sunList, GL_COMPILE); { glColor4f(1.0f, 1.0f, 0.0f, 1.0f); glPushMatrix(); glNormal3f(0.0, 1.0, 0.0); glutSolidSphere(.2, 24, 24); glPopMatrix(); } glEndList(); } if(!terrainList) { terrainList = glGenLists(1); glNewList(terrainList, GL_COMPILE); { glPushMatrix(); glScalef(1.0f, SCALE_VALUE, 1.0f); renderTerrain(); glPopMatrix(); } glEndList(); } glPushMatrix(); glTranslatef(-(MAP_SIZE/2), 0, -(MAP_SIZE/2)); glCallList(terrainList); glPopMatrix(); glPushMatrix(); glTranslatef(lightPos.x, lightPos.y, lightPos.z); glCallList(sunList); glPopMatrix(); } bool init() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glShadeModel(GL_SMOOTH); glClearColor(0.5f, 0.5f, 1.0f, 1.0f); glColor4f(0.5f, 0.5f, 1.0f, 1.0f); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glClearDepth(1.0f); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_NORMALIZE); glGenTextures(1, &shadowMapTexture); glBindTexture(GL_TEXTURE_2D, shadowMapTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, windowWidth, windowHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT, GL_SPECULAR, white); glMaterialf(GL_FRONT, GL_SHININESS, 16.0f); glPushMatrix(); glLoadIdentity(); aspect = (float)windowWidth/windowHeight; gluPerspective(fovy, aspect, zNear, zFar); glGetFloatv(GL_MODELVIEW_MATRIX, cameraProjectionMatrix); glLoadIdentity(); SF3dVector cameraPos, cameraLook, viewPoint, cameraUp; theCamera.getPosition(&cameraPos); theCamera.getLook(&cameraLook); viewPoint = cameraPos + cameraLook; theCamera.getUp(&cameraUp); gluLookAt(cameraPos.x, cameraPos.y, cameraPos.z, viewPoint.x, viewPoint.y, viewPoint.z, cameraUp.x, cameraUp.y, cameraUp.z); glGetFloatv(GL_MODELVIEW_MATRIX, cameraViewMatrix); glLoadIdentity(); gluPerspective(fovy, aspect, zNear, zFar); glGetFloatv(GL_MODELVIEW_MATRIX, lightProjectionMatrix); glLoadIdentity(); gluLookAt(lightPos.x, lightPos.y, lightPos.z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix); glPopMatrix(); return true; } void generateRandoms() { srand(time(NULL)); for (int i=0; i<(NUMBER_OF_SPHERES+4); i++) { randoms[i][0] = -((MAP_SIZE/2) - 1) + (rand()%31); // x randoms[i][1] = 10 + (rand()%11); // y randoms[i][2] = -((MAP_SIZE/2) - 1) + (rand()%31); // z if ((i%6) == 0) // red { randoms[i][3] = 1.0f; randoms[i][4] = 0.0f; randoms[i][5] = 0.0f; } else if ((i%6) == 1) // orange { randoms[i][3] = 1.0f; randoms[i][4] = 0.5f; randoms[i][5] = 0.0f; } else if ((i%6) == 2) // yellow { randoms[i][3] = 1.0f; randoms[i][4] = 1.0f; randoms[i][5] = 0.0f; } else if ((i%6) == 3) // green { randoms[i][3] = 0.0f; randoms[i][4] = 1.0f; randoms[i][5] = 0.0f; } else if ((i%6) == 4) // blue { randoms[i][3] = 0.0f; randoms[i][4] = 0.0f; randoms[i][5] = 1.0f; } else // ((i%6) == 5) // violet { randoms[i][3] = 1.0f; randoms[i][4] = 0.0f; randoms[i][5] = 1.0f; } } } void drawObjects() { glPushMatrix(); glTranslatef(-(MAP_SIZE/2), 0, -(MAP_SIZE/2)); int i = 0; for (int z=1; z<(MAP_SIZE-1); z++) { for (int x=1; x<(MAP_SIZE-1); x++) { if (treeMap[x][z] == 1) { glPushMatrix(); glTranslatef(x, terrain[x][z]*SCALE_VALUE, z); glPushMatrix(); glColor3f(randoms[i][3], randoms[i][4], randoms[i][5]); glTranslatef(0.45f, 2.0f, 0.45f); glutSolidSphere(0.2, 24, 24); glColor3f(randoms[i+1][3], randoms[i+1][4], randoms[i+1][5]); glTranslatef(-0.9f, 0.0f, 0.0f); glutSolidSphere(0.2, 24, 24); glColor3f(randoms[i+2][3], randoms[i+2][4], randoms[i+2][5]); glTranslatef(0.0f, 0.0f,-0.9f); glutSolidSphere(0.2, 24, 24); glColor3f(randoms[i+3][3], randoms[i+3][4], randoms[i+3][5]); glTranslatef(0.9f, 0.0f, 0.0f); glutSolidSphere(0.2, 24, 24); glPopMatrix(); glPushMatrix(); glColor3f(randoms[i+4][3], randoms[i+4][4], randoms[i+4][5]); glTranslatef(0.0f, 0.5f, 0.0f); glutSolidCube(2.0f); glPopMatrix(); glPopMatrix();i++; } } } glPopMatrix(); } void display() { // 1st pass - from light's point of view glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadMatrixf(lightProjectionMatrix); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(lightViewMatrix); glViewport(0, 0, windowWidth, windowHeight); glCullFace(GL_FRONT); glShadeModel(GL_FLAT); glColorMask(0, 0, 0, 0); drawScene(); drawObjects(); glBindTexture(GL_TEXTURE_2D, shadowMapTexture); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, windowWidth, windowHeight); glCullFace(GL_BACK); glShadeModel(GL_SMOOTH); glColorMask(1, 1, 1, 1); // 2nd pass - from camera's point of view glClear(GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadMatrixf(cameraProjectionMatrix); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(cameraViewMatrix); glViewport(0, 0, windowWidth, windowHeight); glLightfv(GL_LIGHT1, GL_POSITION, VECTOR4D(lightPos)); glLightfv(GL_LIGHT1, GL_AMBIENT, white*0.2f); glLightfv(GL_LIGHT1, GL_DIFFUSE, white*0.2f); glLightfv(GL_LIGHT1, GL_SPECULAR, black); glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); drawScene(); drawObjects(); // 3rd pass - with bright light glLightfv(GL_LIGHT1, GL_DIFFUSE, white); glLightfv(GL_LIGHT1, GL_SPECULAR, white); static MATRIX4X4 biasMatrix(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f); MATRIX4X4 textureMatrix=biasMatrix*lightProjectionMatrix*lightViewMatrix; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix.GetRow(0)); glEnable(GL_TEXTURE_GEN_S); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix.GetRow(1)); glEnable(GL_TEXTURE_GEN_T); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix.GetRow(2)); glEnable(GL_TEXTURE_GEN_R); glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix.GetRow(3)); glEnable(GL_TEXTURE_GEN_Q); glBindTexture(GL_TEXTURE_2D, shadowMapTexture); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); glAlphaFunc(GL_GEQUAL, 0.99f); glEnable(GL_ALPHA_TEST); drawScene(); drawObjects(); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glDisable(GL_TEXTURE_GEN_Q); glDisable(GL_LIGHTING); glDisable(GL_ALPHA_TEST); glFinish(); glutSwapBuffers(); glutPostRedisplay(); } void reshape(int w, int h) { windowWidth = w, windowHeight = h; aspect = (float)windowWidth/windowHeight; glPushMatrix(); glLoadIdentity(); gluPerspective(fovy, aspect, zNear, zFar); glGetFloatv(GL_MODELVIEW_MATRIX, cameraProjectionMatrix); glPopMatrix(); } // keyboard handler void keyboard(unsigned char key, int x, int y) { if (key == 27) // Esc key exit(0); if (key == '1') theCamera.setCameraType(Camera::LANDOBJECT); if (key == '2') theCamera.setCameraType(Camera::AIRCRAFT); if (key == 'q') // strafe left theCamera.strafe(-7); if (key == 'w') // walk forward theCamera.walk(7); if (key == 'e') // strafe right theCamera.strafe(7); if (key == 'r') // look up theCamera.pitch(7); if (key == 'u') // light up lightPos.y += 1; if (key == 'o') // light forward lightPos.z -= 1; if (key == 'a') // turn left theCamera.yaw(7); if (key == 's') // walk backward theCamera.walk(-7); if (key == 'd') // turn right theCamera.yaw(-7); if (key == 'f') // look down theCamera.pitch(-7); if (key == 'j') // light down lightPos.y -= 1; if (key == 'k') // light left lightPos.x -= 1; if (key == 'l') // light backward lightPos.z += 1; if (key == ';') // light right lightPos.x += 1; if (key == ' ') // fly up { if (theCamera.getCameraType() == Camera::LANDOBJECT) // jump { for (int i=0; i<5; i++) { theCamera.fly(.7); init(); display(); } for (int i=0; i<4; i++) { theCamera.fly(-.7); init(); display(); } theCamera.fly(-.7); } else theCamera.fly(7); } if (key == 'z') // zoom out { if (fovy < 179) fovy += 2; } if (key == 'x') // zoom in { if (fovy > 1) fovy -= 2; } init(); display(); } // special key handler void special(int key, int x, int y) { if (key == GLUT_KEY_DOWN) // fly down theCamera.fly(-7); init(); display(); } int main() { glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(50, 50); glutInitWindowSize(windowWidth, windowHeight); glutCreateWindow("Project 3"); generateRandoms(); init(); srand(time(NULL)); getHeightField(); turbulence(); generateTreeMap(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutMainLoop(); return 0; }