/**************************************************************************** Copyright (C) 2002-2006 Gilles Debunne (Gilles.Debunne@imag.fr) This file is part of the QGLViewer library. Version 2.2.4-1, released on December 12, 2006. http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer libQGLViewer is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. libQGLViewer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libQGLViewer; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ // TP OpenGL: Joerg Liebelt, Serigne Sow #include #include #include #include "terrain.h" bool TERRAIN::LoadHeightMap( char* filename, int size ) { FILE* pFile; if( heightMap.arrayHeightMap ) UnloadHeightMap( ); pFile= fopen( filename, "rb" ); if( pFile==NULL ) { return false; } heightMap.arrayHeightMap = new unsigned char [size*size]; if( heightMap.arrayHeightMap==NULL ) { return false; } //lire la carte d'hauteurs, format RAW fread( heightMap.arrayHeightMap, 1, size*size, pFile ); fclose( pFile ); sizeHeightMap = size; return true; } bool TERRAIN::SaveHeightMap( char* filename ) { FILE* pFile; pFile= fopen( filename, "wb" ); if( pFile==NULL ) { return false; } if( heightMap.arrayHeightMap==NULL ) { return false; } fwrite( heightMap.arrayHeightMap, 1, sizeHeightMap*sizeHeightMap, pFile ); fclose( pFile ); return true; } bool TERRAIN::UnloadHeightMap( void ) { if( heightMap.arrayHeightMap ) { delete[] heightMap.arrayHeightMap; sizeHeightMap= 0; } return true; } void TERRAIN::Smooth1DTerrain(float* heightData, int kernelSize) //filtrage unidirectionel (moins lisse) { int i,j,kernelPos,effectSize,base; float sum; float* temp = new float [sizeHeightMap*sizeHeightMap]; for (i=0;i=0 && kernelPos < sizeHeightMap*sizeHeightMap) { sum += heightData[kernelPos]; effectSize++; } j++; } while (j=0 && kernelPos < sizeHeightMap*sizeHeightMap) { sum += heightData[kernelPos]; effectSize++; } j++; } while (jmax ) max= heightData[i]; else if( heightData[i]detaille) //.. meme si toujours le meme point est choisi, on ne depasse pas la hauteur max. height= max - ( ( max-min )*currentIteration )/iterations; //choisir deux points de la carte aleatoirement randX1= rand( )%sizeHeightMap; randZ1= rand( )%sizeHeightMap; //...tant qu'ils sont differents do { randX2= rand( )%sizeHeightMap; randZ2= rand( )%sizeHeightMap; } while ( randX2==randX1 && randZ2==randZ1 ); //le vecteur de la ligne aleatoire qui divise la carte en deux dirX1= randX2-randX1; dirZ1= randZ2-randZ1; for( z=0; z0 ) tempBuffer[( z*sizeHeightMap )+x]+= ( float )height; } } //effectuer erosion SmoothTerrain(tempBuffer,smooth); //MOYENNE //Smooth1DTerrain(tempBuffer,smooth); } //adapter l'echelle de valeurs NormalizeTerrain( tempBuffer ); //sauvegarder le terrain cree dans la variable de la classe TERRAIN, //.. on n'a plus besoin de la precision float for( z=0; ztextures.region[type].highHeight ) return 0.0f; //hauteur est au-dessous de la hauteur optimale: on calcule le pourcentage d'utilisation if( heighttextures.region[type].optimalHeight ) { temp1= ( float )textures.region[type].highHeight-textures.region[type].optimalHeight; return ( ( temp1-( height-textures.region[type].optimalHeight ) )/temp1 ); } //default return 0.0f; } // on repete la texture plusieurs fois si on veut remplir un terrain plus grand que la texture elle-meme; // .. afin de savoir quelle pixel de la texture a afficher a une position sur dans le terrain // .. (en tenant compte des repetitions et du fait qu'un pixel de la texture doit harmoniser avec ses voisins),.. // .. on teste combien de repetitions ont deja ete faites et on renvoie la position locale a utiliser sur la texture void TERRAIN::GetTexCoords( QImage texture, unsigned int* x, unsigned int* y ) { unsigned int width = texture.width( ); unsigned int height= texture.height( ); int repeatX= -1; int repeatY= -1; int i= 0; //determiner nombre de repetitions de la texture en x while( repeatX==-1 ) { i++; if( *x<( width*i ) ) repeatX= i-1; } i= 0; //determiner nombre de repetitions de la texture en y while( repeatY==-1 ) { i++; if( *y<( height*i ) ) repeatY= i-1; } //on renvoie la position locale contenant le pixel a utiliser sur la texture *x= *x-( width*repeatX ); *y= *y-( height*repeatY ); } //a l'interieur de chaque texture, on tient compte des variations d'hauteur //.. pour ne pas avoir des regions de couleur identique bien que la hauteur varie //.. pour cela, on doit savoir la hauteur interpole a chaque position // heightToTexRatio: relation taille de map d'hauteur / taille de texture unsigned char TERRAIN::InterpolateHeight( int x, int z, float heightToTexRatio ) { unsigned char Low, HighX, HighZ; float X, Z; float scaledX= x*heightToTexRatio; //echelle d'interpolation necessaire float scaledZ= z*heightToTexRatio; float interpolation; //borne inf Low= GetTrueHeightAtPoint( ( int )scaledX, ( int )scaledZ ); //borne sup x if( ( scaledX+1 )>sizeHeightMap ) return Low; else HighX= GetTrueHeightAtPoint( ( int )scaledX+1, ( int )scaledZ ); //valeur interpolee x interpolation= ( scaledX-( int )scaledX ); X= ( ( HighX- Low )*interpolation )+ Low; //borne sup z if( ( scaledZ+1 )>sizeHeightMap ) return Low; else HighZ= GetTrueHeightAtPoint( ( int )scaledX, ( int )scaledZ+1 ); //valeur interpolee z interpolation= ( scaledZ-( int )scaledZ ); Z= ( ( HighZ- Low )*interpolation )+ Low; //moyenne des deux ~= approx. de la vraie hauteur return ( ( unsigned char )( ( X+ Z )/2 ) ); } //creer une carte de texture en melangeant les quatres types de textures de base void TERRAIN::GenerateTextureMap( unsigned int size ) { unsigned char Red, Green, Blue; unsigned int tempID; unsigned int x, z; unsigned int TexX, TexZ; float totalRed, totalGreen, totalBlue; float blend[4]; float mapRatio; int lastHeight; int i; //determiner le nombre de textures de bases presentes textures.numTextures= 0; for( i=0; i=directionZ && x>=directionX ) { //comparer les hauteurs, et on rend plus doux les frontieres //ici, on ne fait PAS de calcul genre "tracer les rayons"... shade= 1.0f-( GetTrueHeightAtPoint( x-directionX, z-directionZ ) - GetTrueHeightAtPoint( x, z ) )/lightSoftness; } else shade= 1.0f; if( shademaxBrightness ) shade= maxBrightness; SetBrightnessAtPoint( x, z, ( unsigned char )( shade*255 ) ); } } } //tourner la lumiere par un pas de 45° void TERRAIN::StepLightingDirection(void) { if ((directionX==-1)&&(directionZ==-1)) {directionX++;} else if ((directionX==0)&&(directionZ==-1)) {directionX++;} else if ((directionX==1)&&(directionZ==-1)) {directionZ++;} else if ((directionX==1)&&(directionZ==0)) {directionZ++;} else if ((directionX==1)&&(directionZ==1)) {directionX--;} else if ((directionX==0)&&(directionZ==1)) {directionX--;} else if ((directionX==-1)&&(directionZ==1)) {directionZ--;} else if ((directionX==-1)&&(directionZ==0)) {directionZ--;} } bool TERRAIN::LoadTexture( char* filename ) { int type; if (!myTexture.load(filename)) return false; QImage temp = QGLWidget::convertToGLFormat(myTexture); if( temp.depth()==24 ) //devrait etre toujours 32 type= GL_RGB; else type= GL_RGBA; //construire les textures openGL glGenTextures( 1, &textureColorID ); glBindTexture( GL_TEXTURE_2D, textureColorID ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, type, temp.width(), temp.height(), 0, type, GL_UNSIGNED_BYTE, temp.bits() ); return true; } //besoin d'un fonctionnement different car mipmap utilise bool TERRAIN::LoadDetailMap( char* filename ) { int type; if (!myDetailMap.load(filename)) return false; QImage temp = QGLWidget::convertToGLFormat(myDetailMap); if( temp.depth()==24 ) //devrait etre toujours 32 type= GL_RGB; else type= GL_RGBA; //construire les textures openGL glGenTextures( 1, &textureDetailID ); glBindTexture( GL_TEXTURE_2D, textureDetailID ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); gluBuild2DMipmaps( GL_TEXTURE_2D, type, temp.width(), temp.height(), type, GL_UNSIGNED_BYTE, temp.bits() ); return true; }