/* 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 i1 */ Tile::Tile(int i1, int j1, int i2, int j2, HeightMap* heightMapReference ) { PRINTF(4)("Tile Constructor\n"); this->highResModel = new VertexArrayModel(); this->lowResModel = new VertexArrayModel(); this->heightMapReference = heightMapReference; // create high res model this->load(i1, j1, i2, j2, this->highResModel, 4); // create low res model this->load(i1, j1, 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 i1, int j1, 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 - ((i1 + i2) / 2)) * scaleX; this->z = this->heightMapReference->offsetZ + ((j1 + j2 ) / 2 ) * scaleZ; //NEW: this->setAbsCoor(this->heightMapReference->offsetX + ( this->heightMapReference->heightMap->h - ((i1 + i2) / 2)) * scaleX, 0, this->heightMapReference->offsetZ + ((j1 + j2 ) / 2 ) * scaleZ); float height = 0; int offset = 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 = i1 ; 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 = j1; // 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)(j1-sampleRate) /(texRate), (float)(i %this->heightMapReference->heightMap->h)/(texRate)); model->addColor(r/255.0f,g/255.0f,b/255.0f); for(int j = j1; 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) /(texRate), (float)(i %this->heightMapReference->heightMap->h)/(texRate)); //PRINTF(0)("TexCoord: %f %f \n",(float)j / 100.0, (float)(i %this->heightMapReference->h)/100.0); model->addColor(r/255.0,g/255.0,b/255.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) /(texRate), (float)(i %this->heightMapReference->heightMap->h)/(texRate)); model->addColor(r/255.0,g/255.0,b/255.0); } SDL_UnlockSurface(this->heightMapReference->heightMap); int cnt = 0; for(int i = i1 ; i < i2 ; i +=sampleRate) { for(int j = j1-sampleRate ; j < j2 + 2*sampleRate ; j += sampleRate) { model->addIndice(cnt); model->addIndice(cnt + (j2 -j1 + 3* sampleRate )/ sampleRate ); cnt++; } model->newStripe(); } cnt += (j2 -j1 + 3* sampleRate)/ sampleRate; for(int j = j1 ; j <= j2 ; j += sampleRate) { int i = i1; // 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 /(texRate), (float)((i - sampleRate) %this->heightMapReference->heightMap->h)/(texRate)); model->addColor(r/255.0,g/255.0,b/255.0); } for(int j = j1 ; j <= j2 ; j += sampleRate) { int i = i1; 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 /(texRate), (float)(i %this->heightMapReference->heightMap->h)/(texRate)); model->addColor(r/255.0,g/255.0,b/255.0); } for(int j = j1 ; 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 /(texRate), (float)((i+ sampleRate) %this->heightMapReference->heightMap->h)/(texRate)); model->addColor(r/255.0,g/255.0,b/255.0); } for(int j = j1 ; 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=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 /(texRate), (float)(i %this->heightMapReference->heightMap->h)/(texRate)); model->addColor(r/255.0,g/255.0,b/255.0); } // link Boarder Stripe for(int j = j1-sampleRate ; j < j2 ; j += sampleRate) { model->addIndice(cnt); model->addIndice(cnt + (j2 -j1 + sampleRate )/ sampleRate ); cnt++; } cnt++; model->newStripe(); cnt += (j2-j1)/ sampleRate; // link 2nd BoarderStripe for(int j = j1-sampleRate ; j < j2 ; j += sampleRate) { model->addIndice(cnt); model->addIndice(cnt + (j2 -j1 + 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 } HeightMap::HeightMap() { } HeightMap::HeightMap(const std::string& height_map_name = "") : VertexArrayModel() { this->setClassID(CL_HEIGHT_MAP, "HeightMap"); heightMap = IMG_Load(height_map_name.c_str()); if(heightMap!=NULL) { /* WHAT about following checks: - image size (rectangular?) - image file type (bw?) */ PRINTF(0)("loading Image %s\n", height_map_name.c_str()); PRINTF(0)("width : %i\n", heightMap->w); PRINTF(0)("height : %i\n", heightMap->h); PRINTF(0)("%i Byte(s) per Pixel \n", heightMap->format->BytesPerPixel); PRINTF(0)("Rshift : %i\n", heightMap->format->Rshift); PRINTF(0)("Bshift: %i\n", heightMap->format->Bshift); PRINTF(0)("Gshift: %i\n", heightMap->format->Gshift); PRINTF(0)("Rmask: %i\n", heightMap->format->Rmask); PRINTF(0)("Gmask: %i\n", heightMap->format->Gmask); } else PRINTF(4)("oops! couldn't load %s for some reason.\n", height_map_name.c_str()); generateNormalVectorField(); shiftX = 0; shiftY = 0; shiftZ = 0; } HeightMap::HeightMap(const std::string& height_map_name = NULL, const std::string& color_map_name = NULL) : VertexArrayModel() { this->setClassID(CL_HEIGHT_MAP, "HeightMap"); heightMap = IMG_Load(height_map_name.c_str()); if(heightMap!=NULL) { PRINTF(0)("loading Image %s\n", height_map_name.c_str()); PRINTF(0)("width : %i\n", heightMap->w); PRINTF(0)("height : %i\n", heightMap->h); PRINTF(0)("%i Byte(s) per Pixel \n", heightMap->format->BytesPerPixel); PRINTF(0)("Rshift : %i\n", heightMap->format->Rshift); PRINTF(0)("Bshift: %i\n", heightMap->format->Bshift); PRINTF(0)("Gshift: %i\n", heightMap->format->Gshift); PRINTF(0)("Rmask: %i\n", heightMap->format->Rmask); PRINTF(0)("Gmask: %i\n", heightMap->format->Gmask); } else PRINTF(4)("oops! couldn't load %s for some reason.\n", height_map_name.c_str()); generateNormalVectorField(); colorMap=NULL; if(color_map_name != "") { colorMap = IMG_Load(color_map_name.c_str()); } if(colorMap != NULL) { PRINTF(0)("loading Image %s\n", color_map_name.c_str()); PRINTF(0)("width : %i\n", colorMap->w); PRINTF(0)("height : %i\n", colorMap->h); PRINTF(0)("%i Byte(s) per Pixel \n", colorMap->format->BytesPerPixel); PRINTF(0)("Rshift : %i\n", colorMap->format->Rshift); PRINTF(0)("Bshift: %i\n", colorMap->format->Bshift); PRINTF(0)("Gshift: %i\n", colorMap->format->Gshift); PRINTF(0)("Rmask: %i\n", colorMap->format->Rmask); PRINTF(0)("Gmask: %i\n", colorMap->format->Gmask); } else PRINTF(0)("oops! couldn't load colorMap for some reason.\n"); if(colorMap != NULL) { colors = (unsigned char *) colorMap->pixels; hasColourMap = true; } else hasColourMap = false; heights = (unsigned char*) heightMap->pixels; shiftX = 0; shiftY = 0; shiftZ = 0; } HeightMap::~HeightMap() { delete heightMap; delete colorMap; for(int i=0;i < heightMap->h/tileSize ; i++) { for(int j = 0; j < heightMap->w/ tileSize; j++) { delete tiles [i][j]; } } for(int i=0;i < heightMap->h/tileSize ; i++) delete[] tiles[i]; delete[] tiles; for(int i=0;ih;i++) delete[] normalVectorField [i]; delete[] normalVectorField; } void HeightMap::load() { //Create a Dynamicly sized 2D-Array for Tiles tiles = new Tile** [heightMap->h/tileSize]; for(int i=0;i < heightMap->h/tileSize ; i++) tiles [i]= new (Tile* [heightMap->w /tileSize ]); //SetUp Arrays for(int i = 0; i < (heightMap->h )/ tileSize; i ++) { for(int j = 0; j < (heightMap->w )/ tileSize; j ++) { tiles[i][j] = new Tile( i*tileSize , j*tileSize , (i+1)*tileSize, (j+1)*tileSize , this ) ; } } } void HeightMap::draw() { const PNode* camera = State::getCameraNode(); Vector v = camera->getAbsCoor(); int i_min = 0; int i_max = (heightMap->h )/ tileSize; int j_min = 0; int j_max= (heightMap->w ) / tileSize; for(int i = 0; i < i_max ; i ++) { for(int j = 0; j < j_max ; j++) { tiles[i][j]->draw(); } } } 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); } } void HeightMap::scale(Vector v) { scaleX = v.x; scaleY = v.y; scaleZ = v.z; generateNormalVectorField(); } void HeightMap::setAbsCoor(Vector v) { offsetX = v.x; offsetY = v.y; offsetZ = v.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); }