/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program 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, or (at your option) any later version. ### File Specific: main-programmer: bottac@ee.ethz.ch review: patrick boenzli, patrick@orxonox.ethz.ch */ #include "height_map.h" #include "model.h" #include "texture.h" #include "vector.h" #include "material.h" #include "p_node.h" #include "state.h" #include "util/loading/resource_manager.h" #include "debug.h" // INCLUDING SDL_Image #ifdef HAVE_SDL_IMAGE_H #include #else #include #endif /** * default constructor * @param xOffset */ Tile::Tile(int xOffset, int yOffset, int i2, int j2, HeightMap* heightMapReference ) { PRINTF(0)("Tile Constructor\n"); this->highResModel = new VertexArrayModel(); this->lowResModel = new VertexArrayModel(); this->heightMapReference = heightMapReference; // create high res model this->load(xOffset, yOffset, i2, j2, this->highResModel, 4); // create low res model this->load(xOffset, yOffset, i2, j2, this->lowResModel, 8); } Tile::~Tile() { if( highResModel) delete highResModel; if( lowResModel) delete lowResModel; } /** * this darws the tile in diefferent resolutions */ void Tile::draw() { // draw the tile depending on the distance from the camera with different LOD (level of details) float cameraDistance = fabs((State::getCameraNode()->getAbsCoor() - Vector(this->x, heightMapReference->offsetY , this->z) ).len()); if (cameraDistance < HM_LOD_HIGH_RES ) { this->drawHighRes(); } else if( cameraDistance < HM_LOD_LOW_RES) { this->drawLowRes(); } } /** * loads a tile */ void Tile::load(int xOffset, int yOffset, int i2, int j2, VertexArrayModel* model, int sampleRate) { // #define heightMap this->heightMapReference->heightMap #define colors this->heightMapReference->colors #define scaleX this->heightMapReference->scaleX #define scaleY this->heightMapReference->scaleY #define scaleZ this->heightMapReference->scaleZ #define shiftX this->heightMapReference->shiftX #define shiftY this->heightMapReference->shiftY #define shiftZ this->heightMapReference->shiftZ #define normalVectorField this->heightMapReference->normalVectorField //FIXME: OLD implementation this->x = this->heightMapReference->offsetX + ( this->heightMapReference->heightMap->h - ((xOffset + i2) / 2)) * scaleX; this->z = this->heightMapReference->offsetZ + ((yOffset + j2 ) / 2 ) * scaleZ; //NEW: this->setAbsCoor(this->heightMapReference->offsetX + ( this->heightMapReference->heightMap->h - ((xOffset + i2) / 2)) * scaleX, 0, this->heightMapReference->offsetZ + ((yOffset + j2 ) / 2 ) * scaleZ); float height = 0; float r = 0.0; float g = 0.0; float b = 0.0; //if( this->heightMapReference->heightMap != NULL && this->heightMapReference->heightMap->format->BitsPerPixel == 8 ) SDL_LockSurface(this->heightMapReference->heightMap); SDL_LockSurface(this->heightMapReference->colorMap); for( int i = xOffset ; i <= i2 ; i +=sampleRate) { int w = 0; // adjust the colors acoring to the color map if( this->heightMapReference->hasColourMap) { r = colors[3 * w + 2 + 3 * i * this->heightMapReference->heightMap->w]; g = colors[3 * w + 1 + 3 * i * this->heightMapReference->heightMap->w]; b = colors[3 * w + 0 + 3 * i * this->heightMapReference->heightMap->w]; } w = yOffset; // PRINTF(0)("Values: i = %i, w = %i\n", i, w); // add a vertex to the list model->addVertex(scaleX * (this->heightMapReference->heightMap->h - i) + shiftX, shiftY, scaleZ * w + shiftZ); // Top Right model->addNormal(normalVectorField[i % this->heightMapReference->heightMap->h][w % this->heightMapReference->heightMap->w].y, normalVectorField[i % this->heightMapReference->heightMap->h][w % this->heightMapReference->heightMap->w].z, normalVectorField[i % this->heightMapReference->heightMap->h][w % this->heightMapReference->heightMap->w].x); model->addTexCoor((float)(yOffset-sampleRate) /(HM_TEX_RATE), (float)(i %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); for(int j = yOffset; j <= j2; j += sampleRate) { // adjust the colors acording to the color map if( this->heightMapReference->hasColourMap) { r = colors[3 * j + 2 + 3 * i * this->heightMapReference->heightMap->w]; g = colors[3 * j + 1 + 3 * i * this->heightMapReference->heightMap->w]; b = colors[3 * j + 0 + 3 * i * this->heightMapReference->heightMap->w]; } height = (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + i * (this->heightMapReference->heightMap->w)]; height += (float)(unsigned char)this->heightMapReference->heights[j + 1 + sampleRate + (i + 1) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j - 1 + sampleRate + (i + 1) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + (i + 2) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + i * (this->heightMapReference->heightMap->w)]; height /= 5.0; model->addVertex(scaleX * (this->heightMapReference->heightMap->h -i) + shiftX , ((double)(height)*scaleY) + shiftY , scaleZ*(j) + shiftZ); // Top Right model->addNormal(normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].y, normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].z, normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].x); model->addTexCoor((float)(j) /(HM_TEX_RATE), (float)(i %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); //PRINTF(0)("TexCoord: %f %f \n",(float)j / 100.0, (float)(i %this->heightMapReference->h)/100.0); w = j; } model->addVertex(scaleX*(this->heightMapReference->heightMap->h -i)+ shiftX,shiftY,scaleZ*(w)+ shiftZ); // Top Right model->addNormal(normalVectorField[i % this->heightMapReference->heightMap->h][w % this->heightMapReference->heightMap->w].y, normalVectorField[i % this->heightMapReference->heightMap->h][w % this->heightMapReference->heightMap->w].z, normalVectorField[i% this->heightMapReference->heightMap->h][w % this->heightMapReference->heightMap->w].x); model->addTexCoor((float)(j2+sampleRate) /(HM_TEX_RATE), (float)(i %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); } SDL_UnlockSurface(this->heightMapReference->heightMap); int cnt = 0; for( int i = xOffset; i < i2; i +=sampleRate) { for( int j = yOffset-sampleRate; j < j2 + 2 * sampleRate; j += sampleRate) { model->addIndice(cnt); model->addIndice(cnt + (j2 -yOffset + 3* sampleRate )/ sampleRate ); cnt++; } model->newStripe(); } cnt += (j2 -yOffset + 3* sampleRate)/ sampleRate; for( int j = yOffset; j <= j2; j += sampleRate) { int i = xOffset; // To be fixed if(this->heightMapReference->hasColourMap) { r = (float)colors[3 * j + 2 + 3 * i * this->heightMapReference->heightMap->w]; g = (float)colors[3 * j + 1 + 3 * i * this->heightMapReference->heightMap->w]; b = (float)colors[3 * j + 0 + 3 * i * this->heightMapReference->heightMap->w]; } model->addVertex(scaleX*(this->heightMapReference->heightMap->h -i) + shiftX , shiftY , scaleZ*(j) + shiftZ); // Top Right model->addNormal(normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].y, normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].z, normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].x); model->addTexCoor((float)j /(HM_TEX_RATE), (float)((i - sampleRate) %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); } for(int j = yOffset ; j <= j2 ; j += sampleRate) { int i = xOffset; height = (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + i * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + 1 + sampleRate + (i + 1) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j - 1 + sampleRate + (i + 1) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + (i + 2) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + i * this->heightMapReference->heightMap->w]; height=height/5.0; model->addVertex(scaleX*(this->heightMapReference->heightMap->h -i) + shiftX , ((double)(height)*scaleY) +shiftY , scaleZ*(j) + shiftZ); // Top Right model->addNormal(normalVectorField[i % this->heightMapReference->heightMap->h][j % this->heightMapReference->heightMap->w].y, normalVectorField[i % this->heightMapReference->heightMap->h][j% this->heightMapReference->heightMap->w].z, normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].x); model->addTexCoor((float)j /(HM_TEX_RATE), (float)(i %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); } for(int j = yOffset; j <= j2; j += sampleRate) { int i = i2; // To be fixed if( this->heightMapReference->hasColourMap) { r = (float)colors[3 * j + 2 + 3 * i * this->heightMapReference->heightMap->w]; g = (float)colors[3 * j + 1 + 3 * i * this->heightMapReference->heightMap->w]; b = (float)colors[3 * j + 0 + 3 * i * this->heightMapReference->heightMap->w]; } model->addVertex(scaleX*(this->heightMapReference->heightMap->h -i) + shiftX , shiftY , scaleZ*(j) + shiftZ); // Top Right model->addNormal(normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].y, normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].z, normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].x); model->addTexCoor((float)j /(HM_TEX_RATE), (float)((i+ sampleRate) %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); } for(int j = yOffset; j <= j2; j += sampleRate) { int i = i2; height = (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + i * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + 1 + sampleRate + (i + 1) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j - 1 + sampleRate + (i + 1) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + (i + 2) * this->heightMapReference->heightMap->w]; height += (float)(unsigned char)this->heightMapReference->heights[j + sampleRate + i * this->heightMapReference->heightMap->w]; height /= 5.0; model->addVertex(scaleX*(this->heightMapReference->heightMap->h -i) + shiftX , ((double)(height)*scaleY) +shiftY , scaleZ*(j) + shiftZ); // Top Right model->addNormal(normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].y, normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].z, normalVectorField[i%this->heightMapReference->heightMap->h][j%this->heightMapReference->heightMap->w].x); model->addTexCoor((float)j /(HM_TEX_RATE), (float)(i %this->heightMapReference->heightMap->h)/(HM_TEX_RATE)); model->addColor(r/255.0f, g/255.0f, b/255.0f); } // link Boarder Stripe for(int j = yOffset - sampleRate; j < j2; j += sampleRate) { model->addIndice(cnt); model->addIndice(cnt + (j2 - yOffset + sampleRate) / sampleRate ); cnt++; } cnt++; model->newStripe(); cnt += (j2-yOffset)/ sampleRate; // link 2nd BoarderStripe for(int j = yOffset-sampleRate; j < j2; j += sampleRate) { model->addIndice(cnt); model->addIndice(cnt + (j2 - yOffset + sampleRate) / sampleRate); cnt++; } SDL_UnlockSurface(this->heightMapReference->colorMap); model->finalize(); // #undef heightMap #undef colors #undef scaleX #undef scaleY #undef scaleZ #undef shiftX #undef shiftY #undef shiftZ #undef normalVectorField } /** * constructor * @param heightMapName file name of the height map */ HeightMap::HeightMap(const std::string& heightMapName) : VertexArrayModel() { this->init(heightMapName); this->colorMap = NULL; } /** * constructor * @param heightMapName file name of the height map * @param colorMapName file name of the color map */ HeightMap::HeightMap(const std::string& heightMapName, const std::string& colorMapName) : VertexArrayModel() { this->init(heightMapName); this->colorMap = IMG_Load(colorMapName.c_str()); if( this->colorMap != NULL) { PRINTF(0)("loading Image %s\n", colorMapName.c_str()); PRINTF(0)("width : %i\n", this->colorMap->w); PRINTF(0)("height : %i\n", this->colorMap->h); PRINTF(0)("%i Byte(s) per Pixel \n", this->colorMap->format->BytesPerPixel); PRINTF(0)("Rshift : %i\n", this->colorMap->format->Rshift); PRINTF(0)("Bshift: %i\n", this->colorMap->format->Bshift); PRINTF(0)("Gshift: %i\n", this->colorMap->format->Gshift); PRINTF(0)("Rmask: %i\n", this->colorMap->format->Rmask); PRINTF(0)("Gmask: %i\n", this->colorMap->format->Gmask); this->colors = (unsigned char *) colorMap->pixels; this->hasColourMap = true; } else { PRINTF(0)("oops! couldn't load colorMap for some reason.\n"); this->hasColourMap = false; } } /** * deconstructor */ HeightMap::~HeightMap() { if( heightMap) delete heightMap; if( colorMap) delete colorMap; if( this->tiles) { for( int i = 0; i < heightMap->h / HM_TILE_SIZE; i++) { for( int j = 0; j < heightMap->w / HM_TILE_SIZE; j++) { delete tiles [i][j]; } } for( int i = 0; i < heightMap->h / HM_TILE_SIZE; i++) delete[] tiles[i]; delete[] tiles; } if( this->normalVectorField) { for(int i = 0; i < heightMap->h; i++) delete[] normalVectorField[i]; delete[] normalVectorField; } } /** * this is the init function with stuff shared between all constructors */ void HeightMap::init(const std::string& heightMapName) { this->setClassID(CL_HEIGHT_MAP, "HeightMap"); this->shiftX = 0; this->shiftY = 0; this->shiftZ = 0; heightMap = IMG_Load(heightMapName.c_str()); if( heightMap != NULL) { /* WHAT about following checks: - image size (rectangular?) - image file type (bw?) */ PRINTF(1)("loading Image %s\n", heightMapName.c_str()); PRINTF(1)("width : %i\n", heightMap->w); PRINTF(1)("height : %i\n", heightMap->h); PRINTF(1)("%i Byte(s) per Pixel \n", heightMap->format->BytesPerPixel); PRINTF(1)("Rshift : %i\n", heightMap->format->Rshift); PRINTF(1)("Bshift: %i\n", heightMap->format->Bshift); PRINTF(1)("Gshift: %i\n", heightMap->format->Gshift); PRINTF(1)("Rmask: %i\n", heightMap->format->Rmask); PRINTF(1)("Gmask: %i\n", heightMap->format->Gmask); } else PRINTF(1)("oops! couldn't load %s for some reason.\n", heightMapName.c_str()); this->generateNormalVectorField(); this->heights = (unsigned char*)heightMap->pixels; } /** * this function loads the heightmap by creatin tiles */ void HeightMap::load() { // create a dynamicly sized 2D-array for tiles this->tiles = new Tile**[this->heightMap->h / HM_TILE_SIZE]; for( int i = 0;i < heightMap->h / HM_TILE_SIZE; i++) this->tiles [i]= new Tile*[this->heightMap->w / HM_TILE_SIZE]; // setup arrays for( int i = 0; i < this->heightMap->h / HM_TILE_SIZE; i++) { for( int j = 0; j < this->heightMap->w / HM_TILE_SIZE; j++) { this->tiles[i][j] = new Tile( i * HM_TILE_SIZE , j * HM_TILE_SIZE , (i+1) * HM_TILE_SIZE, (j+1) * HM_TILE_SIZE , this); } } } /** * this function draws the height map */ void HeightMap::draw() const { Vector v = State::getCameraNode()->getAbsCoor(); int i_max = (heightMap->h )/ HM_TILE_SIZE; int j_max= (heightMap->w ) / HM_TILE_SIZE; /* process the draw command to the tiles, FIXME: think of something more efficient*/ for( int i = 0; i < i_max; i++) { for( int j = 0; j < j_max; j++) { tiles[i][j]->draw(); } } } /** * this function generates the normal vector field */ void HeightMap::generateNormalVectorField() { int delta = 1; heights = (unsigned char*) heightMap->pixels; //Create a Dynamicly sized 2D-Array to store our normals normalVectorField = new Vector* [heightMap->h]; for(int i=0;ih;i++) normalVectorField [i]= new (Vector [heightMap->w]); // Initialize for(int i=0; i< heightMap->h; i++) { for(int j = 0; j> heightMap->w; j++) { Vector v = Vector(0.0, 1.0, 0.0); normalVectorField[i][j] = v; } } // !!! Does not yet calculate the normals of some border points!!!!! if(heightMap != NULL && heightMap->format->BitsPerPixel == 8 ) { SDL_LockSurface(heightMap); for(int i = 0 ; i < heightMap->h - 1 ; i ++) { for(int j = 0; j < heightMap->w - 1 ; j ++) { delta = (int)heights[j + (i+1)*(heightMap->w )] - (int) heights[j + i*(heightMap->w )]; Vector a = Vector(-scaleX,(float)delta*scaleY ,0.0f); delta = (int)heights[j+1 + i*(heightMap->w )] - (int)heights[j + i*(heightMap->w )]; Vector b = Vector(0.0f,(float) delta*scaleY ,scaleZ); normalVectorField[i][j] = b.cross(a); normalVectorField[i][j].normalize(); } } SDL_UnlockSurface(heightMap); } } /** * scales the height map about a vector * @param v scaling vector */ void HeightMap::scale(Vector v) { scaleX = v.x; scaleY = v.y; scaleZ = v.z; generateNormalVectorField(); } /** * sets the absolute coordinates of the height map * @param v the moving vector */ void HeightMap::setAbsCoor(Vector v) { offsetX = v.x; offsetY = v.y; offsetZ = v.z; } /** * returns the height at a given 2D coordinate * @param x x coordinate of the height map (world space) * @param y y coordinate of the height map (world space) * @return the height (z) */ float HeightMap::getHeight(float x, float y) { x -= offsetX; y -= offsetZ; int xInt = (int)( x / scaleX); x -= (float)((int)x); xInt = heightMap->h - xInt; int yInt = (int)( y / scaleZ); y -= (float) ((int) y); /*yInt = heightMap->w - yInt;*/ //PRINTF(0)("xInt: %i, yInt: %i, x: %f, y: %f\n", xInt, yInt, x, y); if(xInt <= 0 || xInt >= heightMap->h || yInt <= 0 || yInt >= heightMap->w ) return 0; if( y >= 0.5*x) { // Check for ... } float height = heights[yInt + (xInt)*heightMap->w]*scaleY; float a = normalVectorField[(xInt)][yInt].x; float b = normalVectorField [(xInt)][yInt].z; float c = normalVectorField [(xInt)][yInt].y; // PRINTF(0)("a: %f \n" ,a); // PRINTF(0)("b: %f \n" ,b); // PRINTF(0)("c: %f \n" ,c); height -= ( (a/c)*(x) + (b/c)*(y)); // PRINTF(0)("height: %f \n" ,height ); return (height + offsetZ); }