Logo Search packages:      
Sourcecode: race version File versions

height_map.cpp

#include <ClanLib/gl.h>
#include <ClanLib/display.h>

#include "height_map.h"
#include "game_config.h"
#include "track.h"
#include "point_3d.h"
#include "texture.h"
#include "tile_enums.h"
#include "blitter.h"
#include "map.h"
#include "map_objects/house.h"

#define  CALCCOLOR(a) glColor4f( 0.25f + points[a].z/2, 0.25f + points[a].z/2, 0.25f + points[a].z/2, 1.0f );


CL_Surface *HeightMap::map_surface;
CL_SurfaceProvider *HeightMap::provider;

unsigned char *HeightMap::data = NULL;
unsigned short HeightMap::pitch = 0;
bool HeightMap::get_height_inited = false;

void HeightMap::init()
{
      // lock only once.
      provider = map_surface->get_provider();
      provider->lock();

      modify_map_object_bases();
      create_map();
}

void HeightMap::deinit()
{
      delete map_surface;
}


void HeightMap::create_map()
{
      std::cout << "HeightMap: create_map" << std::endl;

      get_height_inited = false;
      
      float x_dist = 500.0f / float(Config::terrain_resolution);
      float y_dist = 500.0f / float(Config::terrain_resolution);

      float tex_u_inc = 0.07f;
      float tex_v_inc = 0.07f;
      float tex_u = 0.0f, tex_v = 0.0f;
      
      std::vector<Point3D> points;
      
      for(int y1=0; y1 < Config::terrain_resolution ; y1++ )
      {
            tex_u = 0;
            
            for( int x=0; x < Config::terrain_resolution; x++ )
            {
                  float vx,vy,vz;
                  vx = x*x_dist;
                  vy = y1*y_dist;
                  
                  if( vx > 499 || vy > 499 ) 
                  {
                        std::cout << "HeightMap: Error: vx or vy too big" << std::endl;
                  }
                  
                  vz = get_height(vx, vy);
                  
                  points.push_back(Point3D(vx/x_dist, vy/y_dist, vz, tex_u, tex_v ));

                  tex_u += tex_u_inc;
                  // if( tex_u >= 1.0f ) tex_u = 0.0f;
            }
            tex_v += tex_v_inc;
            //if( tex_v > 1.0f ) tex_v = 0.0f;
      }

      scale_edges(points);
      
      Track::road_display_list = glGenLists(1);

/*    if( Config::road_texture_repeat )
            // create_road_repeat();
      else*/
      create_road_scaled(points);

      Track::terrain_display_list = glGenLists(16);
      create_terrain(points);
};




float HeightMap::get_height_tile_coord( int x, int y )
{
      int hx = x*Config::tile_size/2;
      int hy = y*Config::tile_size/2;

      return get_height( hx, hy );
}



float HeightMap::get_height( int x, int y )
{
      /* Heightmaps in Race are 24 bit images. Only the RED value is used. A higher value gives
      *  higher ground, so max red (255) is the highest position and no red (0)
      *  the lowest. Water level is 0.3 so values under 0.3*255 will be under water.
      *  For a map with no water make all values higher than (?).
      */

      if( get_height_inited == false )
      {
            data = (unsigned char *)provider->get_data();
            pitch = provider->get_pitch();
            get_height_inited = true;
      }

      if( data == NULL )
      {
            cout << "problems... data == NULL" << endl;
            return 1;
      }

      // out of map, return height at map edge.
      if( x < 0 ) x = 0;
      if( y < 0 ) y = 0;
      if( x > 499) x= 499;
      if( y > 499) y= 499;
      
      // rgb are the same in gray... check red only.
      float retval = float(data[(y*pitch)+(x*4)+1]) / float(128);
      
      return retval;
}



bool HeightMap::under_water(float x, float y, float z)
{
      if( z < 0.3f ) return true;
      return false;
}


void HeightMap::create_terrain(const std::vector<Point3D> &points)
{
      // terrain (ground) display lists
      for( char y=0; y<4; y++ )
      {
            for( char x=0; x<4; x++ )
            {
                  compile_list(x,y, points);
            }
      }
      
}


void HeightMap::compile_list( char _x, char _y, const std::vector<Point3D> &points )
{
      glNewList( Track::terrain_display_list+(_y*4+_x), GL_COMPILE );
      
      int map_width = Config::terrain_resolution;
      int vpp = map_width / 4; // vertices per part
      
      glPushMatrix();
      
      float scale = 40.0f / float(Config::terrain_resolution); // tiles_per_row / terrain_res
      
      glScalef( scale, scale, 1.0f );
      
      int final_x = (_x*vpp) + vpp;
      int final_y = (_y*vpp) + vpp;
      if( final_x > map_width-1 ) final_x = map_width-1;
      if( final_y > map_width-1 ) final_y = map_width-1;


      glBegin( GL_TRIANGLES );
            for( float y=(_y*vpp); y < final_y; y++ )
            {
                  //tex_x = tex_x_inc * (_x*vpp);
                  
                  for( float x=(_x*vpp); x < final_x; x++ )
                  {
                        int p = y*map_width+x;
                        
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 1
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        p = (y+1)*map_width +x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 2
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        p = (y+1)*map_width +x;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 3
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        // triangle 2
                        p = map_width*y+x;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 1
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        p = map_width*y+x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );  // 4
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        p = (y+1)*map_width +x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f ); // 2
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                  }
            }
      glEnd();

////////////////////////////////////////////////////////

/* somethings wrong here...

      glBegin( GL_TRIANGLE_STRIP );
            for( float y=(_y*vpp); y < (final_y); y++ )
            {
                  for( float x=(_x*vpp); x < (final_x); x++ )
                  {
                        int p = y*map_width+x;
                        
                        // 1 3
                        // 2 4

                        // 1
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );

                        // 2
                        p = (y+1) * map_width +x;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        // 3
                        p = y * map_width + x + 1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                        
                        
                        // 4
                        p = (y+1) * map_width + x + 1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( points[p].u, points[p].v );
                        glVertex3f( points[p].x, points[p].y, points[p].z );
                  }
            }
      glEnd();
*/

      glPopMatrix();
      glEndList();
}


void HeightMap::create_road_repeat()
{
      // todo:
      // figure out how to create a mesh based on the road canvas
      // and repeat a texture across it instead of scaling one texture
      // on the terrain mesh.
}

void HeightMap::create_road_scaled(const std::vector<Point3D> &points)
{
      int map_width = Config::terrain_resolution;
      
      float tex_x=0.0f, tex_y=0.0f;
      float tex_x_inc = 1.0f / map_width;
      float tex_y_inc = tex_x_inc;
      
      /////////////////////////////////////////////////////////////////7
      // Begin list....
      glNewList( Track::road_display_list, GL_COMPILE );
      
      glPushMatrix();

      float scale = 40.0f / map_width;

      glScalef( scale, scale, 1.0f );
      
      Track::road_texture->provider->lock();
      unsigned char *data = (unsigned char*)Track::road_texture->provider->get_data();
      
      float x,y;

      glBegin( GL_TRIANGLES );
            for( y=0.0f; y < map_width -1.0f; y++ )
            {
                  tex_x = 0.0f; // + tex_x_inc;
                  
                  for( x=0.0f; x < map_width -1.0f; x++ )
                  {
                        // If all corners are !road there's no need for
                        // triangles there.

                        float scale = 40.0f/map_width;

                        if( Track::track->get_tmp_map(scale*x,scale*y) != '#'
                              && Track::track->get_tmp_map(scale*(x+1),scale*y) != '#'
                              && Track::track->get_tmp_map(scale*x,scale*(y+1)) != '#'
                              && Track::track->get_tmp_map(scale*(x+1),scale*(y+1)) != '#' )
                        {
//                            cout << "skipping" << endl; 
                              tex_x += tex_x_inc;
//                            if( tex_x >= 1.0f )
//                                  tex_x = 0.0f;
                              continue;
                        }

      // GL_TRIANGLES
                        
                        int p = y*map_width+x;
                        
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 1
                        glTexCoord2f( tex_x, tex_y );
                        glVertex3f( x, y, points[p].z );
                        
                        p = (y+1)*map_width +x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 2
                        glTexCoord2f( tex_x + tex_x_inc, tex_y + tex_y_inc );
                        glVertex3f( x+1, y+1, points[p].z );
                        
                        p = (y+1)*map_width +x;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 3
                        glTexCoord2f( tex_x, tex_y+tex_y_inc );
                        glVertex3f( x, y+1, points[p].z );
                        
                        // triangle 2
                        p = map_width*y+x;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  ); // 1
                        glTexCoord2f( tex_x, tex_y );
                        glVertex3f( x, y, points[p].z );
                        
                        p = map_width*y+x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );  // 4
                        glTexCoord2f( tex_x+tex_x_inc, tex_y );
                        glVertex3f( x+1, y, points[p].z );
                        
                        p = (y+1)*map_width +x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f ); // 2
                        glTexCoord2f( tex_x + tex_x_inc, tex_y + tex_y_inc );
                        glVertex3f( x+1, y+1, points[p].z );

                        tex_x += tex_x_inc;
                        if( tex_x >= 1.0f ) tex_x = 0.0f;
                  }
                  tex_y += tex_y_inc;
                  if( tex_y > 1.0f ) tex_y = 0.0f;
            }
      glEnd();


/* somethings wrong here...

      glBegin( GL_TRIANGLE_STRIP );
            for( y=0.0f; y < map_width -1.0f; y++ )
            {
                  tex_x = 0.0f; // + tex_x_inc;
                  
                  for( x=0.0f; x < map_width -1.0f; x++ )
                  {
                        // If all corners are !road there's no need for
                        // triangles there.

                        float scale = 40.0f/map_width;

                        if( Track::track->get_tmp_map(scale*x,scale*y) != '#'
                              && Track::track->get_tmp_map(scale*(x+1),scale*y) != '#'
                              && Track::track->get_tmp_map(scale*x,scale*(y+1)) != '#'
                              && Track::track->get_tmp_map(scale*(x+1),scale*(y+1)) != '#' )
                        {
                              cout << "skipping" << endl; 
                              tex_x += tex_x_inc;
//                            if( tex_x >= 1.0f )
//                                  tex_x = 0.0f;
                              continue;
                        }
                        
                        int p = y*map_width+x;
                        
                        // 1--2
                        // | /|
                        // |/ |
                        // 3--4
                        
                        // 1
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( tex_x, tex_y );
                        glVertex3f( x, y, points[p].z );

                        // 2              
                        p = map_width*y+x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( tex_x+tex_x_inc, tex_y );
                        glVertex3f( x+1, y, points[p].z );
                        
                        // 3
                        p = (y+1)*map_width +x;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( tex_x, tex_y+tex_y_inc );
                        glVertex3f( x, y+1, points[p].z );
      
                        // 4
                        p = (y+1)*map_width +x+1;
                        CALCCOLOR(p);
                        glNormal3f( 0.0f, 0.0f, 1.0f  );
                        glTexCoord2f( tex_x + tex_x_inc, tex_y + tex_y_inc );
                        glVertex3f( x+1, y+1, points[p].z );
                        
                        tex_x += tex_x_inc;
                        if( tex_x >= 1.0f ) tex_x = 0.0f;
                  }
                  tex_y += tex_y_inc;
                  if( tex_y > 1.0f ) tex_y = 0.0f;
            }
      glEnd();
*/

      glPopMatrix();
      glEndList();

      Track::road_texture->provider->unlock();
}




void HeightMap::modify_map_object_bases()
{
      /* Fill base of map_object with the color of it's top-left pixel.
       * this makes the ground flat under i.e. a house. Otherwise the house
       * could be partly under the terrain etc.
       */
      
      CL_Canvas *canvas = Blitter::convert_to_32_bpp(provider);
      
      canvas->lock();
      
      for( char y=0; y < 40; y++ )
      {
            for( char x=0; x < 40; x++ )
            {
                  if( under_water( float(x), float(y), get_height_tile_coord(x,y) ) )
                        continue;
                  
                  Items item = Items(Track::track->get_data(x,y));
                  
                  int px, py;
                  px = int(x*12.5f);
                  py = int(y*12.5f);
                  
                  float r,g,b,a;
                  provider->get_pixel( x, y, &r, &g, &b, &a );
                  
                  House::modify_base( x, y, item, r, canvas );
            }
      }
      
      canvas->unlock();
      
      delete map_surface;
      
      map_surface = CL_Surface::create( canvas );
      provider = map_surface->get_provider();
}


void HeightMap::scale_edges(std::vector<Point3D> &points)
{
      int x, y;

      // scale west edge
      for( y=0; y < Config::terrain_resolution; y++ )
      {
            int index = y*Config::terrain_resolution;
            points[index].x -= 20.0f;
            points[index].u -= 1.0f;
            if( points[index].z < 0.3f )
                  points[index].z = 0.6f+(float(rand()%70)/100);
      }

      // scale east edge
      for( y=0; y < Config::terrain_resolution; y++ )
      {
            int index = y*Config::terrain_resolution+(Config::terrain_resolution-1); 
            points[index].x += 20.0f;
            points[index].u += 0.25f;
            if( points[index].z < 0.3f )
                  points[index].z = 0.6f+(float(rand()%70)/100.0f);
      }

      // scale north (s?) edge
      for( x=0; x < Config::terrain_resolution; x++ )
      {
            int index = (Config::terrain_resolution-1)*Config::terrain_resolution + x;
            points[index].y += 20.0f;
            points[index].v += 0.5f;
            if( points[index].z < 0.3f )
                  points[index].z = 0.6f+(float(rand()%70)/100.0f);
      }

      // scale south (n?) edge
      for( x=0; x < Config::terrain_resolution; x++ )
      {
            points[x].y -= 20.0f;
            points[x].v -= 2.0f;
            if( points[x].z < 0.3f )
                  points[x].z = 0.6f+(float(rand()%70)/100.0f);
      }

}


Generated by  Doxygen 1.6.0   Back to index