Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/terrain/src/lib/graphics/importer/terrain/terrain.cc @ 9421

Last change on this file since 9421 was 9421, checked in by bensch, 18 years ago

renamings

File size: 14.9 KB
Line 
1
2#include "terrain.h"
3#include "terrain_page.h"
4#include "glincl.h"
5#include "util/loading/resource_manager.h"
6#include "debug.h"
7#include <math.h>
8#ifdef HAVE_SDL_SDL_IMAGE_H
9#include <SDL/SDL_image.h>
10#else
11#include <SDL_image.h>
12#endif
13
14bool validateSize( int _s )
15{
16  _s-=1;
17  int s = 16;
18  while ( s <= _s )
19  {
20    if (s == _s )
21      return true;
22    s*=2;
23  }
24  return false;
25}
26void Terrain::build()
27{
28
29  printf("SHOULD GET LOADED :)\n");
30
31  ResourceManager *MANAGER = ResourceManager::getInstance();
32  std::string full = MANAGER->getFullName( heightmapSource );
33  SDL_Surface *tmpData = IMG_Load( full.c_str() );
34  if ( !tmpData )
35  {
36    PRINT(0)( "I' sorry, I can't load %s\n", full.c_str() );
37    return;
38  }
39  if ( !validateSize( tmpData->h ) || !validateSize( tmpData->w ) )
40  {
41    PRINT(0)( "The size of the elevation map must be 2^n+1x2^m+1. and at least 17x17" );
42    return;
43  }
44  if ( tmpData->format->BytesPerPixel != 1 )
45  {
46    PRINT(0)( "The elevetation map must be an 8bit image not %d",
47              tmpData->format->BytesPerPixel*8 );
48    return;
49  }
50  PRINTF(2)( "Loaded the elevation map\n" );
51  heightfield.height = tmpData->h;
52  heightfield.width = tmpData->w;
53  heightfield.pitch = tmpData->pitch;
54  int dataSize = heightfield.pitch*heightfield.height;
55  heightfield.data = new Uint8[dataSize];
56  memcpy( heightfield.data, tmpData->pixels, sizeof(Uint8)*dataSize );
57  SDL_FreeSurface( tmpData );
58  pagesX = (heightfield.width/(pageSize-1) );
59  pagesZ = (heightfield.height/(pageSize-1) );
60
61
62  pages = new pTerrainPage[pagesX*pagesZ];
63  for ( int x = 0; x < pagesX; ++x )
64    for ( int z = 0; z < pagesZ; ++z )
65      pages[z*pagesX+x] = createPage( x, z );
66  //Inform each page about its neighbors.
67  for ( int x = 0; x < pagesX; ++x )
68    for ( int z = 0; z < pagesZ; ++z )
69      pages[z*pagesX+x]->setNeighbors(
70        x > 0                   ? getPage( x-1, z+0 ) : NULL,
71        x < pagesX-1    ? getPage( x+1, z+0 ) : NULL,
72        z < pagesZ-1    ? getPage( x+0, z+1 ) : NULL,
73        z > 0                   ? getPage( x+0, z-1 ) : NULL );
74
75  root = createQuadTree( 0, 0, pagesX, pagesZ );
76
77  for ( unsigned int i = 0; i < layers.size(); ++i )
78  {
79    determineLayerVisibility( i );
80  }
81  activePages = NULL;
82}
83
84pTerrainQuad Terrain::createQuadTree( int _x0, int _z0, int _x1, int _z1, int _depth )
85{
86  int _x01 = (_x1+_x0)/2; int _z01 = (_z1+_z0)/2;
87  pTerrainQuad node;
88  if ( _x1-_x0 == 1 )
89  {
90    node = getPage( _x0, _z0 );
91    node->setChildren( NULL, NULL, NULL, NULL );
92  }
93  else
94  {
95    node = new TerrainQuad( this, _x0, _z0, _x1, _z1 );
96    node->setChildren(
97      createQuadTree( _x0, _z0, _x01, _z01, _depth+1 ),
98      createQuadTree( _x01, _z0, _x1, _z01, _depth+1 ),
99      createQuadTree( _x0, _z01, _x01, _z1, _depth+1 ),
100      createQuadTree( _x01, _z01, _x1, _z1, _depth+1 ) );
101  }
102  node->calculateBounds();
103  return node;
104}
105
106pTerrainPage Terrain::createPage( int _xOffset, int _zOffset ) const
107{
108  pTerrainPage newPage = new TerrainPage( const_cast<Terrain*>( this ), _xOffset, _zOffset );
109  newPage->setScale( scale );
110  newPage->setPosition( Vector( scale.x*_xOffset, 0.0f, scale.z*_zOffset ) );
111  newPage->calculateErrors();
112  return newPage;
113}
114
115void Terrain::addLevelFourPage( int _numVertices, Vertex *_vertices,
116                                int _numIndices, unsigned short *_indices )
117{
118  assert( indices ); assert( vertices );
119  BufferInfo bi = buffers[current];
120  if ( ( MAX_VERTICES < _numVertices+bi.numVertices ) ||
121       ( MAX_INDICES < _numIndices+bi.numIndices+2 ) )
122  {
123    //So, we need the next vb and ib. Lets put the old into vram...
124    glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
125    glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ),
126                     vertices, GL_DYNAMIC_DRAW_ARB );
127    glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bi.ibIdentifier );
128    glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ),
129                     indices, GL_DYNAMIC_DRAW_ARB );
130    BufferInfo newInfo;
131    broker->acquire( newInfo.vbIdentifier, newInfo.ibIdentifier );
132    current++;
133    buffers.push_back( newInfo );
134    bi = newInfo;
135  }
136  //For the vertex data, a simple copy operation is sufficient...
137  memcpy( &vertices[bi.numVertices], _vertices,
138          _numVertices*sizeof( Vertex ) );
139  //The indices need to be updated with an offset :(
140  unsigned short *dst= &indices[bi.numIndices];
141  unsigned short offset = bi.numVertices;
142  unsigned short *src= _indices;
143  unsigned short *end= src+_numIndices;
144  bi.numVertices+=_numVertices;
145  if ( bi.numIndices )
146  {
147    dst[0] = *(dst-1);
148    dst[1] = *src+offset;
149    dst+=2; bi.numIndices+=2;
150  }
151  while ( src < end )
152  {
153    *dst= *src+offset;
154    dst++;
155    src++;
156  }
157  bi.numIndices+=_numIndices;
158  buffers[current] = bi;
159}
160
161void Terrain::determineVisiblePages( pTerrainQuad _node )
162{
163  switch( _node->cull() )
164  {
165    case Frustum::INTERSECT:
166      if ( !_node->isChildless() )
167      {
168        pTerrainQuad *children = _node->getChildren();
169        for ( int i = 0; i < 4; ++i, ++children )
170          determineVisiblePages( *children );
171      }
172      else
173      {
174        showPages( _node->getXOffset(),
175                   _node->getZOffset(), 1, 1 );
176      }
177      break;
178    case Frustum::INSIDE:
179      showPages( _node->getXOffset(),
180                 _node->getZOffset(),
181                 _node->getWidth() ,
182                 _node->getHeight() );
183      break;
184    case Frustum::OUTSIDE:
185      break;
186  }
187}
188
189void Terrain::tick( float _dt )
190{
191  for ( unsigned int i = 0; i < buffers.size(); ++i )
192    broker->release( buffers[i].vbIdentifier, buffers[i].ibIdentifier );
193  buffers.clear();
194  pTerrainPage page = NULL;
195  //Extract the frustum planes out of the modelview matrix.
196  frustum->extractPlanes();
197  // Lets see which pages are visible.
198  determineVisiblePages( root );
199  int wantedLeft, wantedRight, wantedBottom, wantedTop, minLOD;
200  pTerrainPage neighbor = NULL;
201  page = activePages;
202  bool dirty;
203  current = 0;
204  BufferInfo bi;
205  broker->acquire( bi.vbIdentifier, bi.ibIdentifier );
206  buffers.push_back( bi );
207  int dirtyRounds = 0;
208  do
209  {
210    dirtyRounds++;
211    dirty = false;
212    page = activePages;
213    while ( page )
214    {
215      if ( !page->isActive() )
216      {
217        pTerrainPage tmp = page;
218        page = tmp->getNext();
219        tmp->setVisibility( false );
220        continue;
221      }
222      wantedLeft = wantedRight = wantedBottom = wantedTop = page->getWantedLOD();
223      if ( ( neighbor = page->getLeft() ) && ( neighbor->isActive() ) )
224        wantedLeft = neighbor->getWantedLOD();
225      if ( ( neighbor = page->getRight() ) && ( neighbor->isActive() ) )
226        wantedRight = neighbor->getWantedLOD();
227      if ( ( neighbor = page->getTop() ) && ( neighbor->isActive() ) )
228        wantedTop = neighbor->getWantedLOD();
229      if ( ( neighbor = page->getBottom() ) && ( neighbor->isActive() ) )
230        wantedBottom = neighbor->getWantedLOD();
231
232      minLOD = std::min( std::min( wantedBottom, wantedTop ),
233                         std::min( wantedLeft, wantedRight ) );
234      if ( minLOD < page->getWantedLOD()-1 )
235      {
236        page->setWantedLOD( minLOD+1 );
237        dirty = true;
238      }
239      page = page->getNext();
240    }
241  }
242  while ( dirty );
243
244  page = activePages;
245  while ( page )
246  {
247    assert( page->isActive() );
248    page->updateTesselation();
249    page = page->getNext();
250  }
251  //If there is some data in the buffer, we need to upload the data
252  //into the vram...
253  if ( buffers[current].numIndices != 0 )
254  {
255    BufferInfo bi = buffers[current];
256    glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
257    glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ),
258                     vertices, GL_DYNAMIC_DRAW_ARB );
259    glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bi.ibIdentifier );
260    glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ),
261                     indices, GL_DYNAMIC_DRAW_ARB );
262  }
263}
264
265void Terrain::draw( )
266{
267  pTerrainPage page = NULL;
268  glGetError();
269  /*pTerrainPage page = NULL;
270  frustum->extractPlanes();*/
271  Plane far = frustum->getPlane( Frustum::FAR );
272  //Due to some reason, the OpenGL implementors chose the plane equation
273  //to an array of doubles. So we will make them happy.
274  double farPlane[] = { far.n.x, far.n.y, far.n.z, far.k };
275  glEnable( GL_CLIP_PLANE0 );
276  glClipPlane( GL_CLIP_PLANE0, farPlane );
277  glPushAttrib( GL_ALL_ATTRIB_BITS );
278  glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
279  /*
280   * Enable texture and vertex arrays for the first and the second texture
281   * units and disable the normal arrays.
282   */
283  glClientActiveTextureARB( GL_TEXTURE0_ARB );
284  glEnableClientState( GL_VERTEX_ARRAY );
285  glEnableClientState( GL_TEXTURE_COORD_ARRAY );
286  glDisableClientState( GL_NORMAL_ARRAY );
287
288  glClientActiveTextureARB( GL_TEXTURE1_ARB );
289  glEnableClientState( GL_VERTEX_ARRAY );
290  glEnableClientState( GL_TEXTURE_COORD_ARRAY );
291  glDisableClientState( GL_NORMAL_ARRAY );
292  glDisable( GL_CULL_FACE );
293  glDisable( GL_LIGHTING );
294  glColor3f( 1.0f, 1.0f, 1.0f );
295  //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
296  cullCount = 0;
297  glEnable( GL_BLEND );
298  glDepthFunc( GL_LEQUAL );
299  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
300  for ( unsigned int i = 0; i < layers.size(); ++i )
301  {
302    LayerInfo* layer= layers[i];
303    page = activePages;
304
305    glActiveTextureARB( GL_TEXTURE1_ARB );
306    glClientActiveTextureARB( GL_TEXTURE1_ARB );
307    if ( layer->detail )
308    {
309      //glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND );
310      glEnable( GL_TEXTURE_2D );
311      glBindTexture( GL_TEXTURE_2D, layer->detail->getTexture() );
312      glMatrixMode( GL_TEXTURE );
313      glLoadIdentity();
314      glScalef( layer->repeatX, layer->repeatZ, 1.0f );
315    }
316    else
317    {
318      glDisable( GL_TEXTURE_2D );
319    }
320    glEnable( GL_CULL_FACE );
321    glCullFace( GL_BACK );
322    glClientActiveTextureARB( GL_TEXTURE0_ARB );
323    glActiveTextureARB( GL_TEXTURE0_ARB );
324    glEnable( GL_TEXTURE_2D );
325    if ( layer->alpha )
326    {
327      //glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND );
328      glBindTexture( GL_TEXTURE_2D, layer->alpha->getTexture() );
329    }
330    else
331    {
332
333      glBindTexture( GL_TEXTURE_2D, lightmap->getTexture() );
334    }
335    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
336    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
337
338    for ( unsigned j = 0; j < buffers.size(); ++j )
339    {
340      BufferInfo bi = buffers[j];
341      glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
342      glClientActiveTextureARB( GL_TEXTURE0_ARB );
343      glInterleavedArrays( GL_T2F_V3F, 0, NULL );
344
345      glClientActiveTextureARB( GL_TEXTURE1_ARB );
346      glInterleavedArrays( GL_T2F_V3F, 0, NULL );
347
348      glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB,
349                       bi.ibIdentifier );
350
351      glDrawElements( GL_TRIANGLE_STRIP, bi.numIndices,
352                      GL_UNSIGNED_SHORT, NULL );
353    }
354    while ( page )
355    {
356      if ( page->hasMaterial( i ) )
357        page->draw();
358      page = page->getNext();
359    }
360  }
361  glClientActiveTextureARB( GL_TEXTURE1_ARB );
362  glActiveTextureARB( GL_TEXTURE1_ARB );
363  glDisable( GL_TEXTURE_2D );
364  glActiveTextureARB( GL_TEXTURE0_ARB );
365  glEnable( GL_LIGHTING );
366  glMatrixMode( GL_TEXTURE );
367  glLoadIdentity();
368  glPopAttrib();
369  glPopClientAttrib();
370  glCullFace( GL_FRONT );
371  glDisable( GL_CLIP_PLANE0 );
372}
373
374inline Uint8 getAlpha( const SDL_Surface *_s, int _x, int _y )
375{
376  int bpp = _s->format->BytesPerPixel;
377  Uint8 *p = (Uint8 *)_s->pixels + _y*_s->pitch + _x * bpp;
378  Uint32 pixel = 0;
379  switch( bpp )
380  {
381    case 1:
382      pixel = *p;
383      break;
384    case 2:
385      if ( SDL_BYTEORDER == SDL_BIG_ENDIAN )
386        pixel = p[0] << 8 | p[1];
387      else
388        pixel = *(Uint16 *)p;
389      break;
390    case 3:
391      if( SDL_BYTEORDER == SDL_BIG_ENDIAN )
392        pixel = p[0] << 16 | p[1] << 8 | p[2];
393      else
394        pixel = p[0] | p[1] << 8 | p[2] << 16;
395      break;
396    case 4:
397      pixel = *(Uint32 *)p;
398      break;
399    default:
400      return 255; /* shouldn't happen, but avoids warnings */
401  }
402  Uint8 r,g,b,a;
403  SDL_GetRGBA( pixel, _s->format, &r, &g, &b, &a );
404  return a;
405}
406
407void Terrain::determineLayerVisibility( int _layer )
408{
409  LayerInfo * layer = layers[_layer];
410  if ( !layer->alpha )
411  {
412    int numPages = pagesX*pagesZ;
413    for ( int i = 0; i < numPages; ++i )
414      pages[i]->setLayerVisibility( _layer, LV_FULL );
415
416    return;
417  }
418  SDL_Surface *alpha = const_cast<SDL_Surface*>( layer->alpha->getStoredImage() );
419  SDL_LockSurface( alpha );
420  float du = ( (float)alpha->w)/pagesX;
421  float dv = ( (float)alpha->h)/pagesZ;
422  float u = 0.0f, v = 0.0f;
423  for ( int pageX = 0; pageX < pagesX; ++pageX )
424  {
425    v = 0.0f;
426    for ( int pageZ = 0; pageZ < pagesZ; ++pageZ )
427    {
428      bool full = true; bool has = false;
429      for ( int x = 0; x < (int)PAGE_SIZE; ++x )
430      {
431        for ( int z = 0; z < (int)PAGE_SIZE; ++z )
432        {
433          Uint8 a = getAlpha( alpha, (int)u, (int)v );
434          if ( a )
435            has = true;
436          if ( a < 255 )
437            full = false;
438        }
439      }
440      LayerVisibility lv;
441      if ( has )
442      {
443        if ( full )
444          lv = LV_FULL;
445        else
446          lv = LV_PARTIAL;
447      }
448      else
449      {
450        lv = LV_NO;
451      }
452      getPage( pageX, pageZ )->setLayerVisibility( _layer, lv );
453      v+= dv;
454    }
455    u+= du;
456  }
457  SDL_UnlockSurface( alpha );
458}
459
460void Terrain::getAltitude( Vector& _alt, Vector& _normal )
461{
462  float xScaled = _alt.x / scale.x, zScaled = _alt.z / scale.z;
463  //The offset on the map
464  int xOff =  (int)xScaled, zOff = (int)zScaled;
465  //The interpolation values.
466  float u = xScaled-xOff, v = zScaled-zOff;
467
468  float dX = scale.x / ( pageSize-1 );
469  float dZ = scale.z / ( pageSize-1 );
470
471  //If u is bigger than v, we are on the lower triangle...
472  if ( u > v )
473  {
474
475    float alt[] = {
476                    getAltitude( xOff+0, zOff+0 )*scale.y,
477                    getAltitude( xOff+1, zOff+0 )*scale.y,
478                    getAltitude( xOff+1, zOff+1 )*scale.y };
479    _alt.y = (1.0f-u-v)*alt[0]+u*alt[1]+v*alt[2];
480
481    //Since we know about the directions of some x and z-coordinates,
482    //not the whole cross products needs to be calculated. Grab yourself
483    //pen and paper :)
484    _normal.x =  dZ*( alt[0] - alt[1] );
485    _normal.y =  dZ*dX;
486    _normal.z = -dX*( alt[2] - alt[1] );
487  }
488  else
489  {
490    float alt[] = {
491                    getAltitude( xOff+0, zOff+0 )*scale.y,
492                    getAltitude( xOff+0, zOff+1 )*scale.y,
493                    getAltitude( xOff+1, zOff+1 )*scale.y };
494    _alt.y = (1.0f-u-v)*alt[0]+v*alt[1]+u*alt[2];
495    //Since we know about the directions of some x and z-coordinates,
496    //not the whole cross products needs to be calculated. Grab yourself
497    //pen and paper :)
498    _normal.x = -dZ*( alt[2] - alt[1] );
499    _normal.y =  dZ*dX;
500    _normal.z =  dX*( alt[0] - alt[1] );
501  }
502}
503
504void Terrain::showPages( int _x0, int _z0, int _width, int _height )
505{
506  for ( int x = 0; x < _width; ++x )
507  {
508    for ( int z = 0; z < _height; ++z )
509    {
510      pTerrainPage page = getPage( _x0+x, _z0+z );
511      page->setVisibility( true );
512      page->chooseLOD();
513
514    }
515  }
516}
Note: See TracBrowser for help on using the repository browser.