/* 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 */ #include "height_map.h" #include "model.h" #include "texture.h" #include "vector.h" #include "material.h" #include "p_node.h" #include "state.h" #include "resource_manager.h" #include "debug.h" // INCLUDING SDL_Image #ifdef HAVE_SDL_IMAGE_H #include #else #include #endif HeightMap::HeightMap() { } HeightMap::HeightMap(const char* height_map_name = NULL) { this->setClassID(CL_HEIGHT_MAP, "HeightMap"); heightMap = IMG_Load(height_map_name); if(heightMap!=NULL) { PRINTF(0)("loading Image %s\n", height_map_name); PRINTF(0)("width : %i\n", heightMap->w); PRINTF(0)("hight : %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); generateNormalVectorField(); //Defines 2 Materials (for testing only!) this->tmp_mat = new Material(); tmp_mat->setTransparency(1.0); tmp_mat->setIllum(0.3); tmp_mat->setDiffuse(0.55,0.4,0.2); tmp_mat->setAmbient(0.6,0.4,0.2); tmp_mat->setSpecular(0.02,0.02,0.02); tmp_mat->setShininess(.1); tmp_mat->setTransparency(1.0); tmp_mat->diffuseTexture = NULL; tmp_mat->ambientTexture = NULL; tmp_mat->specularTexture = NULL; this->red_mat = new Material(); red_mat->setTransparency(1.0); red_mat->setIllum(0.3); red_mat->setDiffuse(0.55,0.1,0.1); red_mat->setAmbient(0.55,0.1,0.1); red_mat->setSpecular(0.02,0.02,0.02); red_mat->setShininess(.1); red_mat->setTransparency(1.0); red_mat->diffuseTexture = NULL; red_mat->ambientTexture = NULL; red_mat->specularTexture = NULL; } HeightMap::HeightMap(const char* height_map_name = NULL, const char* colour_map_name = NULL) : VertexArrayModel() { this->setClassID(CL_HEIGHT_MAP, "HeightMap"); heightMap = IMG_Load(height_map_name); if(heightMap!=NULL) { PRINTF(0)("loading Image %s\n", height_map_name); PRINTF(0)("width : %i\n", heightMap->w); PRINTF(0)("hight : %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); generateNormalVectorField(); //Defines 2 Materials (for testing only!) this->tmp_mat = new Material("tmp"); tmp_mat->setTransparency(1.0); tmp_mat->setIllum(0.3); tmp_mat->setDiffuse(1.0,1.0,1.0); tmp_mat->setAmbient(1.0,1.0,1.0); tmp_mat->setSpecular(0.0,0.00,0.00); tmp_mat->setShininess(1.0); this->red_mat = new Material("red"); red_mat->setTransparency(1.0); red_mat->setIllum(3); red_mat->setDiffuse(0.55,0.1,0.1); red_mat->setAmbient(0.55,0.1,0.1); red_mat->setSpecular(0.0,0.0,0.0); red_mat->setShininess(1.0); red_mat->setTransparency(1.0); // red_mat->diffuseTexture = NULL; // red_mat->ambientTexture = NULL; //red_mat->specularTexture = NULL; if(colour_map_name != NULL) { colourMap = IMG_Load(colour_map_name); if(colourMap != NULL) { PRINTF(0)("loading Image %s\n", colour_map_name); PRINTF(0)("width : %i\n", colourMap->w); PRINTF(0)("hight : %i\n", colourMap->h); PRINTF(0)("%i Byte(s) per Pixel \n", colourMap->format->BytesPerPixel); PRINTF(0)("Rshift : %i\n", colourMap->format->Rshift); PRINTF(0)("Bshift: %i\n", colourMap->format->Bshift); PRINTF(0)("Gshift: %i\n", colourMap->format->Gshift); PRINTF(0)("Rmask: %i\n", colourMap->format->Rmask); PRINTF(0)("Gmask: %i\n", colourMap->format->Gmask); } else PRINTF(4)("oops! couldn't load %s for some reason.\n", colour_map_name); const char* texture_name = "pictures/ground1.tga"; tmp_mat->setDiffuseMap(texture_name); if(colourMap != NULL) { colours = (unsigned char *) colourMap->pixels; hasColourMap = true; } else { hasColourMap = false; } // tmp_mat->setAmbientMap(texture_name); //tmp_mat->setSpecularMap(texture_name); // red_mat->setDiffuseMap(texture_name); // red_mat->setAmbientMap(texture_name); //red_mat->setSpecularMap(texture_name); } } HeightMap::~HeightMap() { delete heightMap; } void HeightMap::load() { this->camera = State::getCamera(); this->camCoords = this->camera->getAbsCoor(); float x = this->camCoords.x + 300; float y = this->camCoords.z + 100; tmp_mat->select(); unsigned char height = 0; int offset = 0; int g = 0; float old_r = 0.0f; float old_g = 0.0f; float old_b = 0.0f; heights = (unsigned char*) heightMap->pixels; bool colourChanged = true; /* if(heightMap != NULL && heightMap->format->BitsPerPixel == 8 ) {} SDL_LockSurface(heightMap); for(int i = 0 ; i < heightMap->h -sampleRate ; i +=sampleRate) { tmp_mat->select(); int j = 0; for(int j = 0 ; j < heightMap->w -sampleRate ; j += sampleRate) { if(true) { float r = (float)colours[3*j+2 + 3*i*(heightMap->w )]; float g = (float)colours[3*j+1 + 3*i*(heightMap->w)]; float b = (float)colours[3*j+0 + 3*i*(heightMap->w)]; colourChanged = old_r != r || old_g != g || old_b != b; old_r = r; old_g = g; old_b = b; if(colourChanged) { tmp_mat->setAmbient(r/255.0,g/255.0,b/255.0); tmp_mat->setDiffuse(r/255.0,g/255.0,b/255.0); tmp_mat->select(); } } height = heights[j+sampleRate + i*(heightMap->w )]; this->addNormal(normalVectorField[i][j+sampleRate].y,normalVectorField[i][j+sampleRate].z,normalVectorField[i][j+2].x); this->addTexCoor(((j/sampleRate)%4)/4.0,((i/sampleRate)%4)/4.0); this->addVertex(scaleX*(heightMap->h -i),(double)((double)(height)*scaleY),scaleZ*(j+sampleRate)); // Top Right } } SDL_UnlockSurface(heightMap); int cnt = 0; for(int i = 0 ; i < heightMap->h -sampleRate ; i +=sampleRate) { for(int j = 0 ; j < heightMap->w -sampleRate ; j += sampleRate) { this->addIndice(cnt); cnt ++; } if(i%2 == 1) { this->newStripe(); } } */ this->planeModel(); this->finalize(); } /* void HeightMap::draw() { this->camera = State::getCamera(); this->camCoords = this->camera->getAbsCoor(); float x = this->camCoords.x + 300; float y = this->camCoords.z + 100; // Draw a red rectangle to test getHeight red_mat->select(); glBegin(GL_TRIANGLE_STRIP); glNormal3f(0,1,0); glTexCoord2d(1.0,0.0); glVertex3f(x-10,getHeight(x-10,y+10)+5.0f ,y+10); // Top Left glNormal3f(0,1,0); glTexCoord2d(1.0,1.0); glVertex3f(x+10,getHeight(x+10,y+10)+5.0f ,y+10); // Top Left glNormal3f(0,1,0); glTexCoord2d(0.0,0.0); glVertex3f(x-10,getHeight(x-10,y-10)+5.0f ,y-10); // Top Left glNormal3f(0,1,0); glTexCoord2d(0.0,1.0); glVertex3f(x+10,getHeight(x+10,y-10)+5.0f ,y-10); // Top Left glEnd(); tmp_mat->select(); unsigned char height = 0; int offset = 0; int g = 0; float old_r = 0.0f; float old_g = 0.0f; float old_b = 0.0f; heights = (unsigned char*) heightMap->pixels; bool colourChanged = true; if(heightMap != NULL && heightMap->format->BitsPerPixel == 8 ) { SDL_LockSurface(heightMap); glBegin(GL_TRIANGLE_STRIP); for(int i = 0 ; i < heightMap->h -sampleRate ; i +=sampleRate) { int j = 0; /* height = heights[j + i*(heightMap->w )]; glNormal3f(normalVectorField[i][j].y,normalVectorField[i][j].z,normalVectorField[i][j].x); glVertex3f(20*(heightMap->h -(i))-1000,(double)((double)(height)/1-300),20*(j)-1000); // Top Left height = heights[j + (i+2)*(heightMap->w )]; glNormal3f(normalVectorField[i+2][j].y,normalVectorField[i+2][j].z,normalVectorField[i+2][j].x); glVertex3f(20*(heightMap->h -(i+2))-1000,(double)((double)(height)/1-300),20*(j)-1000); // Bottom Left */ /* for(int j = 0 ; j < heightMap->w -sampleRate ; j += sampleRate) { if(hasColourMap) { float r = (float)colours[3*j+2 + 3*i*(heightMap->w )]; float g = (float)colours[3*j+1 + 3*i*(heightMap->w)]; float b = (float)colours[3*j+0 + 3*i*(heightMap->w)]; colourChanged = old_r != r || old_g != g || old_b != b; old_r = r; old_g = g; old_b = b; if(colourChanged) { tmp_mat->setAmbient(r/255.0,g/255.0,b/255.0); tmp_mat->setDiffuse(r/255.0,g/255.0,b/255.0); tmp_mat->select(); } } */ //if(true/*(abs(-scaleX*i-x+5000) > 1100 || abs(scaleZ*j-y-2000) > 1100 )*/){ //subdivide?? /* height = heights[j+sampleRate + i*(heightMap->w )]; glNormal3f(normalVectorField[i][j+sampleRate].y,normalVectorField[i][j+sampleRate].z,normalVectorField[i][j+2].x); glTexCoord2f(((j/sampleRate)%4)/4.0,((i/sampleRate)%4)/4.0); glVertex3f(scaleX*(heightMap->h -i),(double)((double)(height)*scaleY),scaleZ*(j+sampleRate)); // Top Right height = heights[j+sampleRate + (i+sampleRate)*(heightMap->w )]; glNormal3f(normalVectorField[i+sampleRate][j+sampleRate].y,normalVectorField[i+sampleRate][j+sampleRate].z,normalVectorField[i+sampleRate][j+sampleRate].x); glTexCoord2f(((j/sampleRate)%4)/4.0,1/4.0+((i/sampleRate)%4)/4.0); //glTexCoord2f(0.0,0.0); glVertex3f(scaleX*(heightMap->h -(i+sampleRate)),(double)((double)(height)*scaleY),scaleZ*(j+sampleRate)); // Bottom Right } else { //red_mat->select(); //glEnd(); glBegin(GL_TRIANGLE_STRIP); drawRect(j,i+sampleRate/2,j+sampleRate/2,i); glEnd(); glBegin(GL_TRIANGLE_STRIP); drawRect(j+sampleRate/2,i+sampleRate/2,j+sampleRate,i); glEnd(); glBegin(GL_TRIANGLE_STRIP); drawRect(j,i+sampleRate,j+sampleRate/2,i+sampleRate/2); glEnd(); glBegin(GL_TRIANGLE_STRIP); drawRect(j+sampleRate/2,i+sampleRate,j+sampleRate,i+sampleRate/2); glEnd(); //subdivide } } j = heightMap->w -sampleRate; glNormal3f(normalVectorField[i+sampleRate][j+sampleRate].y,normalVectorField[i+sampleRate][j+sampleRate].z,normalVectorField[i+sampleRate][j+sampleRate].x); //glTexCoord2f(((j/sampleRate)%4)/4.0,1/4.0+((i/sampleRate)%4)/4.0); //glTexCoord2f(0.0,0.0); glTexCoord2f(((j/sampleRate)%4)/4.0,((i/sampleRate)%4)/4.0); glVertex3f(scaleX*(heightMap->h -i),(double)((double)-1000.0),scaleZ*(j+sampleRate)); // Top Right glNormal3f(normalVectorField[i+sampleRate][j+sampleRate].y,normalVectorField[i+sampleRate][j+sampleRate].z,normalVectorField[i+sampleRate][j+sampleRate].x); glTexCoord2f(((j/sampleRate)%4)/4.0,1/4.0+((i/sampleRate)%4)/4.0); glVertex3f(scaleX*(heightMap->h -(i+sampleRate)),(double)-1000.0,scaleZ*(j+sampleRate)); // Bottom Right //glEnd(); } SDL_UnlockSurface(heightMap); glEnd(); } } */ 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]); // !!! Does not yet calculate any normals for 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(-20.0,(float)delta ,0.0f); delta = (int)heights[j+1 + i*(heightMap->w )] - (int)heights[j + i*(heightMap->w )]; Vector b = Vector(0.0f,(float) delta ,20.0); normalVectorField[i][j] = b.cross(a); normalVectorField[i][j].normalize(); } } SDL_UnlockSurface(heightMap); } } void HeightMap::drawRect(int xBottom, int yBottom, int xTop, int yTop ) { int height = 0; if(true) { height = heights[xTop + yTop*(heightMap->w )]; glNormal3f(normalVectorField[yTop][xTop].y,normalVectorField[yTop][xTop].z,normalVectorField[yTop][xTop].x); glTexCoord2f(((yBottom/sampleRate)%8)/8.0+0.125,((xBottom/sampleRate)%8)/8.0+0.125); glVertex3f(scaleX*(heightMap->h - yTop),(double)((double)(height)*scaleY),scaleZ*(xTop)); // Top Right height = heights[xBottom + yTop*(heightMap->w )]; glNormal3f(normalVectorField[yTop][xBottom].y,normalVectorField[yTop][xBottom].z,normalVectorField[yTop][xBottom].x); glTexCoord2f(((yBottom/sampleRate)%8)/8.0,((xBottom/sampleRate)%8)/8.0+0.125); glVertex3f(scaleX*(heightMap->h -(yTop)),(double)((double)(height)*scaleY),scaleZ*(xBottom)); // Top Left height = heights[xTop + (yBottom)*(heightMap->w )]; glNormal3f(normalVectorField[yBottom][xTop].y,normalVectorField[yBottom][xTop].z,normalVectorField[yBottom][xTop].x); glTexCoord2f(((yBottom/sampleRate)%8)/8.0+0.125,((yBottom/sampleRate)%8)/8.0); glVertex3f(scaleX*(heightMap->h -(yBottom)),(double)((double)(height)*scaleY),scaleZ*(xTop)); // Bottom Right height = heights[xBottom + (yBottom)*(heightMap->w )]; glNormal3f(normalVectorField[yBottom][xBottom].y,normalVectorField[yBottom][xBottom].z,normalVectorField[yBottom][xBottom].x); glTexCoord2f(((yBottom/sampleRate)%8)/8.0,((yBottom/sampleRate)%8)/8.0); glVertex3f(scaleX*(heightMap->h -(yBottom)),(double)((double)(height)*scaleY),scaleZ*(xBottom)); // Bottom Left } else { // subdivide } } void HeightMap::fixBoarder(int xBottomLeft, int yBottomLeft, int xTopRight, int yTopRight) { int height = 0; for(int i= xTopRight; i < xBottomLeft ; i+= sampleRate) { glBegin(GL_TRIANGLES); height = heights[yBottomLeft + (i + sampleRate)*(heightMap->w )]; glNormal3f(0,1,0); glVertex3f(scaleX*(heightMap->h -i-sampleRate),scaleY*height,scaleZ*(yBottomLeft)); height = heights[yBottomLeft + i*(heightMap->w )]; glNormal3f(0,1,0); glVertex3f(scaleX*(heightMap->h -i),scaleY*height,scaleZ*(yBottomLeft)); height = heights[yBottomLeft + (i + sampleRate/2)*(heightMap->w )]; glNormal3f(0,1,0); glVertex3f(scaleX*(heightMap->h -i - sampleRate/2),scaleY*height,scaleZ*(yBottomLeft)); glEnd(); } for(int j= yBottomLeft; j < yTopRight; j+= sampleRate) { glBegin(GL_TRIANGLES); height = heights[j + (xBottomLeft+sampleRate)*(heightMap->w )]; glNormal3f(-1,0,0); glVertex3f(scaleX*(heightMap->h -xBottomLeft -sampleRate),scaleY*height,scaleZ*(j)); height = heights[j + sampleRate/2 + (xBottomLeft + sampleRate)*(heightMap->w )]; glNormal3f(-1,0,0); glVertex3f(scaleX*(heightMap->h -xBottomLeft - sampleRate),scaleY*height,scaleZ*(j+sampleRate/2)); height = heights[j + sampleRate + (xBottomLeft + sampleRate)*(heightMap->w )]; glNormal3f(-1,0,0); glVertex3f(scaleX*(heightMap->h -xBottomLeft-sampleRate),scaleY*height,scaleZ*(j+sampleRate)); glEnd(); } } void HeightMap::scale(Vector v) { scaleX = v.x; scaleY = v.y; scaleZ = v.z; } // Accepts Coordinates relative to HeightMap float HeightMap::getHeight(float x, float y) { int xInt = (int)x / scaleX; x -= (float)xInt*scaleX; xInt = heightMap->h - xInt; int yInt = (int)y / scaleZ; y -= (float)yInt*scaleZ; if(xInt <= 0 || xInt >= heightMap->h || yInt <= 0 || yInt >= heightMap->w ) return 0.0f; 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; height -= ( (a/c)*(x) + (b/c)*(y))*scaleY; return height; }