Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8741 was 8741, checked in by ponder, 18 years ago
  • Finally, I got the terrain working completly. What a hard work… It took me lots and lots of hours to remove all bugs in the tesselation routines.
File size: 10.9 KB
RevLine 
[8319]1
2#include "terrain.h"
3#include "terrain_page.h"
4#include "glincl.h"
[8328]5#include "util/loading/resource_manager.h"
6#include "debug.h"
[8548]7#include <math.h>
[8319]8#ifdef HAVE_SDL_SDL_IMAGE_H
9#include <SDL/SDL_image.h>
10#else
11#include <SDL_image.h>
12#endif
13
14void Terrain::build()
15{
[8328]16        ResourceManager *MANAGER = ResourceManager::getInstance();
17        std::string full = MANAGER->getFullName( heightmapSource );
18        SDL_Surface *tmpData = IMG_Load( full.c_str() );
[8319]19        if ( !tmpData ) {
[8328]20                PRINTF(0)( "I' sorry, I can't load %s\n", full.c_str() );
[8319]21                return;
22        }               
23       
24        heightfield.height = tmpData->h;
25        heightfield.width = tmpData->w;
26        heightfield.pitch = tmpData->pitch;
27        int dataSize = heightfield.pitch*heightfield.height;
28        heightfield.data = new UByte[dataSize];
29        memcpy( heightfield.data, tmpData->pixels, sizeof(UByte)*dataSize );
30        SDL_FreeSurface( tmpData );
[8741]31        //TODO: Perform some checks... size, bits and so on
[8319]32        pagesX = (heightfield.width/(pageSize-1) );
33        pagesZ = (heightfield.height/(pageSize-1) );
[8548]34        //TODO: Determine layer visibility!     
[8641]35        for ( unsigned int i = 0; i < materials.size(); ++i ) {
[8548]36               
37        }
[8319]38        pages = new pTerrainPage[pagesX*pagesZ];       
39        for ( int x = 0; x < pagesX; ++x )
40                for ( int z = 0; z < pagesZ; ++z )
41                        pages[z*pagesX+x] = createPage( x, z );
[8349]42        //Inform each page about its neighbors.
43        for ( int x = 0; x < pagesX; ++x )
44                for ( int z = 0; z < pagesZ; ++z )
45                        pages[z*pagesX+x]->setNeighbors(
46                                x > 0                   ? getPage( x-1, z+0 ) : NULL,
47                                x < pagesX-1    ? getPage( x+1, z+0 ) : NULL, 
[8648]48                                z < pagesZ-1    ? getPage( x+0, z+1 ) : NULL,
49                                z > 0                   ? getPage( x+0, z-1 ) : NULL );
[8349]50       
[8319]51        root = createQuadTree( 0, 0, pagesX, pagesZ );
52        activePages = NULL;
53}
54
55pTerrainQuad Terrain::createQuadTree( int _x0, int _z0, int _x1, int _z1, int _depth )
56{
57        int _x01 = (_x1+_x0)/2; int _z01 = (_z1+_z0)/2;
58        pTerrainQuad node;
59        if ( _x1-_x0 == 1 ) {
60                node = getPage( _x0, _z0 );
61                node->setChildren( NULL, NULL, NULL, NULL );
62        }
[8648]63        else { 
[8319]64                node = new TerrainQuad( this, _x0, _z0, _x1, _z1 );
65                node->setChildren( 
66                        createQuadTree( _x0, _z0, _x01, _z01, _depth+1 ),
67                        createQuadTree( _x01, _z0, _x1, _z01, _depth+1 ), 
68                        createQuadTree( _x0, _z01, _x01, _z1, _depth+1 ), 
69                        createQuadTree( _x01, _z01, _x1, _z1, _depth+1 ) );
70        }
71        node->calculateBounds();
72        return node;
73}
74
75pTerrainPage Terrain::createPage( int _xOffset, int _zOffset ) const
76{
77        pTerrainPage newPage = new TerrainPage( const_cast<Terrain*>( this ), _xOffset, _zOffset );
78        newPage->setScale( scale );     
79        newPage->setPosition( Triple( scale.x*_xOffset, 0.0f, scale.z*_zOffset ) );
80        newPage->calculateErrors();
81        return newPage;
82}
83
[8641]84void Terrain::addLevelFourPage( int _numVertices, Vertex *_vertices, 
85        int _numIndices, unsigned short *_indices )
86{
87        assert( indices ); assert( vertices );
88        BufferInfo bi = buffers[current];       
89        if ( ( MAX_VERTICES < _numVertices+bi.numVertices ) || 
90                ( MAX_INDICES < _numIndices+bi.numIndices+2 ) ) {
91                //So, we need the next vb and ib. Lets put the old into vram...
92                glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
93                glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ), 
94                        vertices, GL_DYNAMIC_DRAW_ARB );
95                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bi.ibIdentifier );
96                glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ), 
97                        indices, GL_DYNAMIC_DRAW_ARB );
98                BufferInfo newInfo;
99                broker->acquire( newInfo.vbIdentifier, newInfo.ibIdentifier );                 
100                current++;     
101                buffers.push_back( newInfo );   
102                bi = newInfo;
103        }
104        //For the vertex data, a simple copy operation is sufficient...
105        memcpy( &vertices[bi.numVertices], _vertices, 
106                _numVertices*sizeof( Vertex ) );
107        //The indices need to be updated with an offset :(
[8741]108        unsigned short *dst= &indices[bi.numIndices];
109        unsigned short offset = bi.numVertices;
110        unsigned short *src= _indices;
111        unsigned short *end= src+_numIndices;
112        bi.numVertices+=_numVertices;           
113        if ( bi.numIndices ) {
114                dst[0] = *(dst-1);
115                dst[1] = *src+offset;
116                dst+=2; bi.numIndices+=2;
[8641]117        }
[8741]118        while ( src < end ) {
119                *dst= *src+offset;
120                dst++;
121                src++;
[8641]122        }
123        bi.numIndices+=_numIndices;
124        buffers[current] = bi;
125}
126
[8319]127void Terrain::determineVisiblePages( pTerrainQuad _node )
128{
129        switch( _node->cull() ) {
130                case Frustum::INTERSECT:
131                        //printf( "partially inside frustum\n" );
132                        if ( !_node->isChildless() ) {
133                                pTerrainQuad *children = _node->getChildren();
134                                for ( int i = 0; i < 4; ++i, ++children )
135                                        determineVisiblePages( *children );
136                        }
137                        else {
138                                showPages( _node->getXOffset(), 
139                                                   _node->getZOffset(), 1, 1 );
140                        }
141                        break;
142                case Frustum::INSIDE:
143                        //printf( "fully inside frustum\n" );                   
144                        showPages( _node->getXOffset(), 
145                                           _node->getZOffset(), 
146                                           _node->getWidth() , 
147                                           _node->getHeight() );
148                        break;
149                case Frustum::OUTSIDE:
150                        cullCount+= (_node->getWidth()-1)*(_node->getHeight()-1);
151                        break;
152        }
153}
154
155void Terrain::draw( )
156{
[8569]157        static float s = 0.0f;
[8328]158        glGetError();
[8319]159        pTerrainPage page = NULL;
160        frustum->extractPlanes();
[8548]161       
[8741]162        /*
[8548]163         * Enable texture and vertex arrays for the first and the second texture
164         * units and disable the normal arrays.
165         */
166        glClientActiveTextureARB( GL_TEXTURE0_ARB );   
167                glEnableClientState( GL_VERTEX_ARRAY );
168                glEnableClientState( GL_TEXTURE_COORD_ARRAY ); 
169                glDisableClientState( GL_NORMAL_ARRAY );
170                               
171        glClientActiveTextureARB( GL_TEXTURE1_ARB );   
172                glEnableClientState( GL_VERTEX_ARRAY );
173                glEnableClientState( GL_TEXTURE_COORD_ARRAY );
174                glDisableClientState( GL_NORMAL_ARRAY ); 
[8642]175        glDisable( GL_CULL_FACE );
[8741]176        glCullFace( GL_BACK );
[8319]177        glDisable( GL_LIGHTING );
178        glColor3f( 1.0f, 1.0f, 1.0f );
[8548]179        //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
[8319]180        cullCount = 0;
[8548]181       
[8319]182        // Lets see which pages are visible.
183        determineVisiblePages( root );
[8548]184        int wantedLeft, wantedRight, wantedBottom, wantedTop, minLOD;
185        pTerrainPage neighbor = NULL;
186        page = activePages;
[8569]187        bool dirty;
[8641]188        current = 0;
189        BufferInfo bi;
190        broker->acquire( bi.vbIdentifier, bi.ibIdentifier );
191        buffers.push_back( bi );
[8648]192        int dirtyRounds = 0;
[8569]193        do {
[8648]194                dirtyRounds++;
[8569]195                dirty = false;
196                page = activePages;
197                while ( page ) {
198                        if ( !page->isActive() ) {
199                                pTerrainPage tmp = page;
200                                page = tmp->getNext();
201                                tmp->setVisibility( false );
202                                continue;
203                        }
204                        wantedLeft = wantedRight = wantedBottom = wantedTop = page->getWantedLOD();
[8648]205                        if ( ( neighbor = page->getLeft() ) && ( neighbor->isActive() ) ) 
[8569]206                                wantedLeft = neighbor->getWantedLOD();
[8648]207                        if ( ( neighbor = page->getRight() ) && ( neighbor->isActive() ) ) 
[8569]208                                wantedRight = neighbor->getWantedLOD();
[8648]209                        if ( ( neighbor = page->getTop() ) && ( neighbor->isActive() ) ) 
[8569]210                                wantedTop = neighbor->getWantedLOD();
[8648]211                        if ( ( neighbor = page->getBottom() ) && ( neighbor->isActive() ) ) 
[8569]212                                wantedBottom = neighbor->getWantedLOD();                       
213               
[8641]214                        minLOD = std::min( std::min( wantedBottom, wantedTop ), 
215                                std::min( wantedLeft, wantedRight ) ); 
[8569]216                        if ( minLOD < page->getWantedLOD()-1 ) {
217                                page->setWantedLOD( minLOD+1 );
[8648]218                                dirty = true;
[8569]219                        }       
220                        page = page->getNext();
221                }
222        } while ( dirty );
[8684]223       
[8569]224        page = activePages;
[8319]225        while ( page ) {
[8741]226                assert( page->isActive() );
[8569]227                page->updateTesselation();
[8319]228                page = page->getNext();
229        }
[8641]230        //Finish the last buffer
231        if ( buffers[current].numIndices != 0 ) {
232                BufferInfo bi = buffers[current];       
[8741]233                glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
[8641]234                glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ), 
235                        vertices, GL_DYNAMIC_DRAW_ARB );
[8741]236                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bi.ibIdentifier );
[8641]237                glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ), 
238                        indices, GL_DYNAMIC_DRAW_ARB );
239        }
[8648]240        glPushAttrib( GL_COLOR_BUFFER_BIT );
[8641]241        for ( unsigned int i = 0; i < materials.size(); ++i ) {
[8548]242                page = activePages;     
243               
244                //This is a hack! Remove this as soon as possible
245                materials[i]->unselect();
246                materials[i]->select();
247               
248                glActiveTextureARB( GL_TEXTURE1_ARB );
249                glClientActiveTextureARB( GL_TEXTURE1_ARB );
250                glMatrixMode( GL_TEXTURE );
251                glLoadIdentity();
[8741]252                glScalef( pagesX, pagesZ, 1.0f );
[8641]253
[8548]254                glClientActiveTextureARB( GL_TEXTURE0_ARB );
255                glActiveTextureARB( GL_TEXTURE0_ARB );
256                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );                         
257                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
[8741]258                glEnable( GL_CULL_FACE );
[8641]259                for ( unsigned j = 0; j < buffers.size(); ++j ) {
260                        BufferInfo bi = buffers[j];
261                        glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
262                        glClientActiveTextureARB( GL_TEXTURE0_ARB );
263                        glInterleavedArrays( GL_T2F_V3F, 0, NULL );
264
265                        glClientActiveTextureARB( GL_TEXTURE1_ARB );
266                        glInterleavedArrays( GL_T2F_V3F, 0, NULL );
267
268                        glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 
269                                bi.ibIdentifier );     
270
271                        glDrawElements( GL_TRIANGLE_STRIP, bi.numIndices, 
272                                                        GL_UNSIGNED_SHORT, NULL );
273                }
[8548]274                while ( page ) {
275                        if ( page->hasMaterial( i ) )
276                                page->draw();
277                        page = page->getNext();
278                }
279                activatedCount = 0; deactivatedCount = 0;
280        }
[8641]281       
282        //Get rid of the buffers
283       
284        for ( unsigned int i = 0; i < buffers.size(); ++i )
285                broker->release( buffers[i].vbIdentifier, buffers[i].ibIdentifier );
286        buffers.clear();
287               
[8569]288        glClientActiveTextureARB( GL_TEXTURE1_ARB );   
289        glDisableClientState( GL_VERTEX_ARRAY );
290        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
291        glDisableClientState( GL_VERTEX_ARRAY );
292        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
293        materials[0]->unselect();
294        glActiveTextureARB( GL_TEXTURE0_ARB );
295        glClientActiveTextureARB( GL_TEXTURE0_ARB );   
296        glDisableClientState( GL_VERTEX_ARRAY );
297        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
298        glEnable( GL_LIGHTING );
[8648]299        glMatrixMode( GL_TEXTURE );
300        glLoadIdentity();
301        glPopAttrib();
[8319]302}
303
[8321]304
305
[8319]306void Terrain::getAltitude( Triple& _alt, Triple& _normal )
307{
[8321]308        float xScaled = _alt.x / scale.x, zScaled = _alt.z / scale.z;
309        //The offset on the map
310        int xOff =  (int)xScaled, zOff = (int)zScaled;
311        //The interpolation values.
312        float u = xScaled-xOff, v = zScaled-zOff;
[8319]313       
[8321]314        float dX = scale.x / ( pageSize-1 );
315        float dZ = scale.z / ( pageSize-1 );
316       
317        //If u is bigger than v, we are on the lower triangle...
318        if ( u > v ) {
319               
320                float alt[] = {
321                        getAltitude( xOff+0, zOff+0 )*scale.y,
322                        getAltitude( xOff+1, zOff+0 )*scale.y,
323                        getAltitude( xOff+1, zOff+1 )*scale.y };
[8548]324                _alt.y = (1.0f-u-v)*alt[0]+u*alt[1]+v*alt[2];
[8321]325               
326                //Since we know about the directions of some x and z-coordinates,
327                //not the whole cross products needs to be calculated. Grab yourself
328                //pen and paper :)
329                _normal.x = -dZ*( alt[0] - alt[1] );                           
330                _normal.y = -dZ*dX;
331                _normal.z =  dX*( alt[2] - alt[1] );
332        }
333        else {
334                float alt[] = {
335                        getAltitude( xOff+0, zOff+0 )*scale.y,
336                        getAltitude( xOff+0, zOff+1 )*scale.y,
337                        getAltitude( xOff+1, zOff+1 )*scale.y };                       
[8548]338                _alt.y = (1.0f-u-v)*alt[0]+v*alt[1]+u*alt[2];
[8321]339                //Since we know about the directions of some x and z-coordinates,
340                //not the whole cross products needs to be calculated. Grab yourself
341                //pen and paper :)
342                _normal.x =  dZ*( alt[2] - alt[1] );                           
343                _normal.y = -dZ*dX;
344                _normal.z = -dX*( alt[0] - alt[1] );
345        }
[8319]346}
347
348void Terrain::showPages( int _x0, int _z0, int _width, int _height )
349{
350        for ( int x = 0; x < _width; ++x ) {
351                for ( int z = 0; z < _height; ++z ) {
352                        pTerrainPage page = getPage( _x0+x, _z0+z );
[8328]353                        page->setVisibility( true );                   
354                        page->chooseLOD();
355
[8319]356                }
357        }
358}
Note: See TracBrowser for help on using the repository browser.