#include #include #include #include #include using namespace std; Terrain :: Terrain() { width = 0; height = 0; heightmap = NULL; texture = NULL; normals = NULL; glTexture = 0; glList = 0; isTextured = false; } inline vec3 & Terrain :: getCoords(uint _i, uint _j) { return *(heightmap + _j * width + _i); } inline vec3 & Terrain :: getNormal(uint _i, uint _j) { return *(normals + _j * width + _i); } bool Terrain :: loadTexture(const char * _filename, int & _w, int & _h) { ifstream file(_filename, ios::binary); string magic, line; int offset, w, h, val; if(texture != NULL) delete [] texture; isTextured = false; if(file.is_open() == false) { cerr << "[-] Terrain::loadPPMTexture - Impossible d'ouvrir le fichier " << _filename << endl; return false; } file >> magic; if(magic != "P3" && magic != "P6") { cerr << "[-] Terrain::loadPPMTexture - Le fichier n'est pas au format PPM (format : " << magic << "). Abandon du chargement." << endl; return false; } file >> std::ws; while(file.peek() == '#') getline(file, line); file >> w; file >> h; file >> offset; file >> std::ws; if(offset > 255) { cerr << "[-] Terrain::loadPPMTexture - Les pixels ne sont pas codes sur 1 octet. Abandon du chargement." << endl; return false; } if(w <= 0 || h <= 0) { cerr << "[Image::loadPNM] Erreur. Les dimensions de l'image sont incorrectes (x : " << w << ", y : " << h << "). Abandon du chargement." << endl; return false; } texture = new unsigned char[w * h * 3]; if(magic == "P6") { for(int j(0); j < h; j++) file.read((char *)&texture[j * w * 3], w * 3 * sizeof(char)); } else { for(int j(0); j < h; j++) for(int i(0); i < w; i++) for(int k(0); k < 3; k++) { file >> val; texture[(j * w + i) * 3 + k] = (unsigned char)val; } } file.close(); /* glGenTextures(1, &glTexture); glBindTexture(GL_TEXTURE_2D, glTexture); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h, GL_RGB, GL_UNSIGNED_BYTE, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); */ isTextured = true; _w = w; _h = h; //delete [] texture; return true; } bool Terrain :: load(const char * _filename, int _width, int _height, const char * _texture) { ifstream fileTerrain(_filename, ios::binary); string magic, line; int offset, w, h; double center, max, min; if(heightmap != NULL) delete [] heightmap; if(normals != NULL) delete [] normals; if(_texture != NULL) { if(loadTexture(_texture, w, h) == true) { if(_width == -1 && _height == -1) { width = w; height = h; } else { if(_width != w || _height != h) { cerr << "[-] Terrain::load - Le terrain et la texture ne sont pas de meme dimensions. Abandon du chargement." << endl; return false; } } } else { if(_width == -1 && _height == -1) { cerr << "[-] Terrain::load - Impossible de trouver les dimensions du terrain. Abandon du chargement." << endl; return false; } else { width = _width; height = _height; } } } if(fileTerrain.is_open() == false) { cerr << "[-] Terrain::load - Impossible d'ouvrir le fichier " << _filename << ". Abandon du chargement." << endl; return false; } if(_width == -1 && _height == -1) { fileTerrain >> magic; if(magic != "P2" && magic != "P5") { cerr << "[-] Terrain::load - Le terrain n'est pas au format PGM. Abandon du chargement." << endl; return false; } else { fileTerrain >> std::ws; while(fileTerrain.peek() == '#') getline(fileTerrain, line); fileTerrain >> w; fileTerrain >> h; fileTerrain >> offset; fileTerrain >> std::ws; if(offset > 255) { cerr << "[-] Terrain::load - Les coordonnees du terrain ne sont pas codees sur 1 octet. Abandon du chargement." << endl; return false; } if(w <= 0 || h <= 0) { cerr << "[-] Terrain::load - Les dimensions du terrain sont incorrectes (x : " << w << ", y : " << h << "). Abandon du chargement." << endl; return false; } width = w; height = h; heightmap = new vec3[width * height]; max = 0; min = 255; int p; if(magic == "P5") { cout << "ici" << endl; unsigned char pix[width * height]; fileTerrain.read((char *)&pix, sizeof(char) * width * height); for(uint j(0); j < height; j++) for(uint i(0); i < width; i++) { p = *(pix + j * width + i); getCoords(i, j).x = i - width / 2.0; getCoords(i, j).y = p; getCoords(i, j).z = j - height / 2.0; if(min > p) min = p; if(max < p) max = p; } } else { for(uint j(0); j < height; j++) for(uint i(0); i < width; i++) { fileTerrain >> p; getCoords(i, j).x = i - width / 2.0; getCoords(i, j).y = p; getCoords(i, j).z = j - height / 2.0; if(min > p) min = p; if(max < p) max = p; } } } } else { short pix[_width * _height], p; width = _width; height = _height; heightmap = new vec3[width * height]; fileTerrain.read((char *)&pix, sizeof(short) * width * height); max = pix[0]; min = pix[0]; for(uint j(0); j < height; j++) for(uint i(0); i < width; i++) { p = *(pix + j * width + i); getCoords(i, j).x = i - width / 2.0; getCoords(i, j).y = (float)p; getCoords(i, j).z = j - height / 2.0; if(min > p) min = p; if(max < p) max = p; } } center = (max + min) / 2.0; for(uint i(0); i < width * height; i++) (heightmap + i)->y -= center; normals = new vec3[width * height]; fileTerrain.close(); return true; } void Terrain :: computeNormals() { for(uint i(0); i < width * height; i++) *(normals + i) = vec3::zero; vec3 v1, v2, normal; for(uint j(0); j < height - 1; j++) { for(uint i(0); i < width - 1; i++) { vec3 & p1 = getCoords(i , j ); vec3 & p2 = getCoords(i + 1, j ); vec3 & p3 = getCoords(i + 1, j + 1); vec3 & p4 = getCoords(i , j + 1); v1 = p2 - p1; v2 = p4 - p1; normal = v1 ^ v2; getNormal(i , j ) += normal; getNormal(i + 1, j ) += normal; getNormal(i , j + 1) += normal; v1 = p4 - p3; v2 = p2 - p3; normal = v1 ^ v2; getNormal(i + 1, j + 1) += normal; getNormal(i + 1, j ) += normal; getNormal(i , j + 1) += normal; } } for(uint i(0); i < width * height; i++) (normals + i)->normalize(); } void Terrain :: scale(double _s) { for(uint i(0); i < width * height; i++) (heightmap + i)->y /= _s; } void Terrain :: createGLList() { if(glList != 0) glDeleteLists(glList, 1); glList = glGenLists(1); glNewList(glList, GL_COMPILE); if(isTextured == true) { glGenTextures(1, &glTexture); glBindTexture(GL_TEXTURE_2D, glTexture); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnable(GL_TEXTURE_2D); glColor3f(1, 1, 1); glBindTexture(GL_TEXTURE_2D, glTexture); } for(uint j(0); j < height - 1; j++) { glBegin(GL_TRIANGLE_STRIP); for(uint i(0); i < width; i++) { if(glTexture != 0) glTexCoord2f((float)i / width, (float)(j + 1)/height); glNormal3fv(getNormal(i, j)); glVertex3fv(getCoords(i, j)); if(glTexture != 0) glTexCoord2f((float)i / width, (float)(j)/height); glNormal3fv(getNormal(i, j + 1)); glVertex3fv(getCoords(i, j + 1)); } glEnd(); } if(isTextured == true) { glDisable(GL_TEXTURE_2D); } glEndList(); } void Terrain :: display() { //glEnable(GL_TEXTURE_2D); glCallList(glList); //glDisable(GL_TEXTURE_2D); }