// author: Yutaka Blizman // This is the main project file for VC++ application project // generated using an Application Wizard. #include "stdafx.h" #include #include "glut.h" #include #include #include #include "billboard.h" #include "tga.h" #using using namespace System; #define MAP_SIZE 256 #define SCALE_VALUE 0.1f #define LANDOBJECT 0 #define AIRCRAFT 1 #define NUMBER_OF_TEXTURES 4 bool billboard = true; bool wireframe = false; float angle = 0.0, yawDelta = 0.0; float eyeX = -10, eyeY = (MAP_SIZE/3), eyeZ = (MAP_SIZE+10); float finalTerrainTexture[MAP_SIZE+1][MAP_SIZE+1][3]; float fovy = 45, aspect, zNear = 1, zFar = 1000; float lookX = 0.0f, lookY = 0.0f, lookZ = -1.0f; float marbleTexture[20][20]; 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]; float treeMap[MAP_SIZE][MAP_SIZE]; float upX = 0.0f, upY = 1.0f, upZ = 0.0f; int cameraType = AIRCRAFT; int treeCount = 0; int walkDelta = 0, pitchDelta = 0, flyDelta = 0; int width = 1000, height = 500; unsigned int texName[NUMBER_OF_TEXTURES]; // 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 y, int width) { if (width > 1) { int half = width/2; terrain[x+half][y] = midpoint(terrain[x][y], terrain[x+width][y], width); terrain[x+width][y+half] = midpoint(terrain[x+width][y], terrain[x+width][y+width], width); terrain[x+half][y+width] = midpoint(terrain[x+width][y+width], terrain[x][y+width], width); terrain[x][y+half] = midpoint(terrain[x][y+width], terrain[x][y], width); terrain[x+half][y+half] = (terrain[x+half][y] + terrain[x+width][y+half] + terrain[x+half][y+width] + terrain[x][y+half]) / 4; recursive(x, y, half); recursive(x+half, y, half); recursive(x+half, y+half, half); recursive(x, y+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 z[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) { z[i][j][0] = 0; z[i][j][1] = 0; z[i][j][2] = (z[i-halfLoD][j][2] + z[i+halfLoD][j][2]) / 2; } else if (terrain[i][j] < 255.0f) { z[i][j][0] = 0; z[i][j][1] = (z[i-halfLoD][j][1] + z[i+halfLoD][j][1]) / 2; z[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { z[i][j][0] = (z[i-halfLoD][j][0] + z[i+halfLoD][j][0]) / 2; z[i][j][1] = (z[i-halfLoD][j][1] + z[i+halfLoD][j][1]) / 2; z[i][j][2] = (z[i-halfLoD][j][2] + z[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) { z[i][j][0] = 0; z[i][j][1] = 0; z[i][j][2] = (z[i][j-halfLoD][2] + z[i][j+halfLoD][2]) / 2; } else if (terrain[i][j] < 255.0f) { z[i][j][0] = 0; z[i][j][1] = (z[i][j-halfLoD][1] + z[i][j+halfLoD][1]) / 2; z[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { z[i][j][0] = (z[i][j-halfLoD][0] + z[i][j+halfLoD][0]) / 2; z[i][j][1] = (z[i][j-halfLoD][1] + z[i][j+halfLoD][1]) / 2; z[i][j][2] = (z[i][j-halfLoD][2] + z[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) { z[i][j][0] = 0; z[i][j][1] = 0; z[i][j][2] = (z[i][j+halfLoD][2] + z[i+halfLoD][j][2] + z[i][j-halfLoD][2] + z[i-halfLoD][j][2]) / 4; } else if (terrain[i][j] < 255.0f) { z[i][j][0] = 0; z[i][j][1] = (z[i][j+halfLoD][1] + z[i+halfLoD][j][1] + z[i][j-halfLoD][1] + z[i-halfLoD][j][1]) / 4; z[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { z[i][j][0] = (z[i][j+halfLoD][0] + z[i+halfLoD][j][0] + z[i][j-halfLoD][0] + z[i-halfLoD][j][0]) / 4; z[i][j][1] = (z[i][j+halfLoD][1] + z[i+halfLoD][j][1] + z[i][j-halfLoD][1] + z[i-halfLoD][j][1]) / 4; z[i][j][2] = (z[i][j+halfLoD][2] + z[i+halfLoD][j][2] + z[i][j-halfLoD][2] + z[i-halfLoD][j][2]) / 4; } } } } void noise(int lod, float z[MAP_SIZE+1][MAP_SIZE+1][3]) { for (int i=0; i<(MAP_SIZE+1); i+=lod) { for (int j=0; j<(MAP_SIZE+1); j+=lod) { float r = (float)((float)(rand() % 256) / 255.0f); if (terrain[i][j] < 10.0f) { z[i][j][0] = 0; z[i][j][1] = 0; z[i][j][2] = r; } else if (terrain[i][j] < 255.0f) { z[i][j][0] = 0; z[i][j][1] = r; z[i][j][2] = 0; } else // (terrain[i][j] >= 255.0f) { z[i][j][0] = .5 + r; z[i][j][1] = .5 + r; z[i][j][2] = .5 + r; } } } if (lod > 1) noiseHelper(lod, z); if (lod > 2) { int halfLoD = lod/2; noiseHelper(halfLoD, z); } if (lod > 4) { int quarterLoD = lod/4; noiseHelper(quarterLoD, z); } if (lod > 8) { int eighthLoD = lod/8; noiseHelper(eighthLoD, z); } } void turbulence() { noise(1, terrainTexture1); noise(2, terrainTexture2); noise(4, terrainTexture4); noise(8, terrainTexture8); noise(16, terrainTexture16); for (int i=0; i<(MAP_SIZE+1); i++) { for (int j=0; j<(MAP_SIZE+1); j++) { finalTerrainTexture[i][j][0] = (terrainTexture16[i][j][0]/2 + terrainTexture8[i][j][0]/4 + terrainTexture4[i][j][0]/8 + terrainTexture2[i][j][0]/16 + terrainTexture1[i][j][0]/32); finalTerrainTexture[i][j][1] = (terrainTexture16[i][j][1]/2 + terrainTexture8[i][j][1]/4 + terrainTexture4[i][j][1]/8 + terrainTexture2[i][j][0]/16 + terrainTexture1[i][j][0]/32); finalTerrainTexture[i][j][2] = (terrainTexture16[i][j][2]/2 + terrainTexture8[i][j][2]/4 + terrainTexture4[i][j][2]/8 + terrainTexture2[i][j][0]/16 + terrainTexture1[i][j][0]/32); } } } void marble() { for (int i=0; i<20; i++) { for (int j=0; j<20; j++) { marbleTexture[i][j] = cos(finalTerrainTexture[i][j][0]); } } } void renderMarbleSlab() { glBegin(GL_TRIANGLES); for (int i=0; i<20; i++) { for (int j=0; j<20; j++) { float color = marbleTexture[i][j]; glColor3f(color, color, color); if (terrain[20][20] >= 10.0f) { glVertex3f(20, terrain[20][20]*SCALE_VALUE, 20); } } } } void renderTerrain() { if (wireframe) glBegin(GL_LINES); else glBegin(GL_TRIANGLES); //glNormal3f(0.0,1.0,0.0); for (int i=0; i= 10.0f) { int temp = rand() % 1001; if (temp == 0) // 0.1% { treeMap[i][j] = 1.0f; // tree1 treeCount++; } else if (temp == 1) // 0.1% { treeMap[i][j] = 2.0f; // tree2 treeCount++; } else // (temp > 2) 99.8% treeMap[i][j] = 0; } else treeMap[i][j] = 0; } } } void reshape(int w1, int h1) { width = w1; height = h1; if (height == 0) height = 1; aspect = 1.0f * width / height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); width = w1; height = h1; glViewport(0, 0, width, height); gluPerspective(fovy, aspect, zNear, zFar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(eyeX, eyeY, eyeZ, eyeX+lookX, eyeY+lookY, eyeZ+lookZ, upX, upY, upZ); } void initTextures() { tgaInfo *image0, *image1;//, *image2, *image3; glEnable(GL_DEPTH_TEST); glGenTextures(NUMBER_OF_TEXTURES, texName); image0 = tgaLoad("tree1.tga"); image1 = tgaLoad("tree2.tga"); /* image2 = tgaLoad("clouds1a.tga"); image3 = tgaLoad("clouds1b.tga");*/ // tree1.tga glBindTexture(GL_TEXTURE_2D, texName[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image0->width, image0->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image0->imageData); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); // tree2.tga glBindTexture(GL_TEXTURE_2D, texName[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image1->width, image1->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1->imageData); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 1); // clouds1a.tga /* glBindTexture(GL_TEXTURE_2D, texName[2]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image2->width, image2->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image2->imageData); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 2); // clouds1b.tga glBindTexture(GL_TEXTURE_2D, texName[3]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image3->width, image3->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image3->imageData); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 3);*/ } void walk(float units) { eyeX += lookX * units; if (cameraType == AIRCRAFT) eyeY += lookY * units; eyeZ += lookZ * units; } void fly(float units) { if (cameraType == AIRCRAFT) { eyeX += upX * units; eyeY += upY * units; eyeZ += upZ * units; } } void pitch(float units) { lookY += 0.01 * units; } void yaw(float angle) { lookX = sin(angle); lookZ = -cos(angle); } void display() { float pos[3]; if (walkDelta) walk(walkDelta); if (pitchDelta) pitch(pitchDelta); if (yawDelta) { angle += yawDelta; yaw(angle); } if (flyDelta) fly(flyDelta); float cam[3] = {eyeX, eyeY, eyeZ}; glLoadIdentity(); gluLookAt(eyeX, eyeY, eyeZ, eyeX+lookX, eyeY+lookY, eyeZ+lookZ, upX, upY, upZ); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderTerrain(); // draw trees glColor3f(0.5f, 0.5f, 0.5f); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0); for(int i=0; i 1) { fovy -= 2; reshape(width, height); } } display(); } // keyboardUp handler void keyboardUp(unsigned char key, int x, int y) { if (key == 'w') walkDelta = 0; if (key == 'r') pitchDelta = 0; if (key == 'a') yawDelta = 0.0f; if (key == 's') walkDelta = 0; if (key == 'd') yawDelta = 0.0f; if (key == 'f') pitchDelta = 0; if (key == ' ') flyDelta = 0; display(); } // special key handler void special(int key, int x, int y) { if (key == GLUT_KEY_F5) // re-render map { treeCount = 0; getHeightField(); turbulence(); generateTreeMap(); printf("%i trees\n", treeCount); } if (key == GLUT_KEY_DOWN) // fly down flyDelta = -5; display(); } // specialUp key handler void specialUp(int key, int x, int y) { if (key == GLUT_KEY_DOWN) flyDelta = 0; display(); } // mouse handler void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { if (wireframe) wireframe = false; else wireframe = true; } if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { if (billboard) billboard = false; else billboard = true; } display(); } int main() { glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100, 100); glutInitWindowSize(width, height); glutCreateWindow("Project 2"); glClearColor(.5,.5,1,1); initTextures(); srand(time(NULL)); getHeightField(); turbulence(); generateTreeMap(); glutKeyboardFunc(keyboard); glutKeyboardUpFunc(keyboardUp); glutSpecialFunc(special); glutSpecialUpFunc(specialUp); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMainLoop(); return 0; }