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
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
14void Terrain::build()
15{
16        ResourceManager *MANAGER = ResourceManager::getInstance();
17        std::string full = MANAGER->getFullName( heightmapSource );
18        SDL_Surface *tmpData = IMG_Load( full.c_str() );
19        if ( !tmpData ) {
20                PRINTF(0)( "I' sorry, I can't load %s\n", full.c_str() );
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 );
31        //TODO: Perform some checks... size, bits and so on
32        pagesX = (heightfield.width/(pageSize-1) );
33        pagesZ = (heightfield.height/(pageSize-1) );
34        //TODO: Determine layer visibility!     
35        for ( unsigned int i = 0; i < materials.size(); ++i ) {
36               
37        }
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 );
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, 
48                                z < pagesZ-1    ? getPage( x+0, z+1 ) : NULL,
49                                z > 0                   ? getPage( x+0, z-1 ) : NULL );
50       
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        }
63        else { 
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
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 :(
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;
117        }
118        while ( src < end ) {
119                *dst= *src+offset;
120                dst++;
121                src++;
122        }
123        bi.numIndices+=_numIndices;
124        buffers[current] = bi;
125}
126
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{
157        static float s = 0.0f;
158        glGetError();
159        pTerrainPage page = NULL;
160        frustum->extractPlanes();
161       
162        /*
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 ); 
175        glDisable( GL_CULL_FACE );
176        glCullFace( GL_BACK );
177        glDisable( GL_LIGHTING );
178        glColor3f( 1.0f, 1.0f, 1.0f );
179        //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
180        cullCount = 0;
181       
182        // Lets see which pages are visible.
183        determineVisiblePages( root );
184        int wantedLeft, wantedRight, wantedBottom, wantedTop, minLOD;
185        pTerrainPage neighbor = NULL;
186        page = activePages;
187        bool dirty;
188        current = 0;
189        BufferInfo bi;
190        broker->acquire( bi.vbIdentifier, bi.ibIdentifier );
191        buffers.push_back( bi );
192        int dirtyRounds = 0;
193        do {
194                dirtyRounds++;
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();
205                        if ( ( neighbor = page->getLeft() ) && ( neighbor->isActive() ) ) 
206                                wantedLeft = neighbor->getWantedLOD();
207                        if ( ( neighbor = page->getRight() ) && ( neighbor->isActive() ) ) 
208                                wantedRight = neighbor->getWantedLOD();
209                        if ( ( neighbor = page->getTop() ) && ( neighbor->isActive() ) ) 
210                                wantedTop = neighbor->getWantedLOD();
211                        if ( ( neighbor = page->getBottom() ) && ( neighbor->isActive() ) ) 
212                                wantedBottom = neighbor->getWantedLOD();                       
213               
214                        minLOD = std::min( std::min( wantedBottom, wantedTop ), 
215                                std::min( wantedLeft, wantedRight ) ); 
216                        if ( minLOD < page->getWantedLOD()-1 ) {
217                                page->setWantedLOD( minLOD+1 );
218                                dirty = true;
219                        }       
220                        page = page->getNext();
221                }
222        } while ( dirty );
223       
224        page = activePages;
225        while ( page ) {
226                assert( page->isActive() );
227                page->updateTesselation();
228                page = page->getNext();
229        }
230        //Finish the last buffer
231        if ( buffers[current].numIndices != 0 ) {
232                BufferInfo bi = buffers[current];       
233                glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
234                glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ), 
235                        vertices, GL_DYNAMIC_DRAW_ARB );
236                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bi.ibIdentifier );
237                glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ), 
238                        indices, GL_DYNAMIC_DRAW_ARB );
239        }
240        glPushAttrib( GL_COLOR_BUFFER_BIT );
241        for ( unsigned int i = 0; i < materials.size(); ++i ) {
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();
252                glScalef( pagesX, pagesZ, 1.0f );
253
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 );
258                glEnable( GL_CULL_FACE );
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                }
274                while ( page ) {
275                        if ( page->hasMaterial( i ) )
276                                page->draw();
277                        page = page->getNext();
278                }
279                activatedCount = 0; deactivatedCount = 0;
280        }
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               
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 );
299        glMatrixMode( GL_TEXTURE );
300        glLoadIdentity();
301        glPopAttrib();
302}
303
304
305
306void Terrain::getAltitude( Triple& _alt, Triple& _normal )
307{
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;
313       
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 };
324                _alt.y = (1.0f-u-v)*alt[0]+u*alt[1]+v*alt[2];
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 };                       
338                _alt.y = (1.0f-u-v)*alt[0]+v*alt[1]+u*alt[2];
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        }
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 );
353                        page->setVisibility( true );                   
354                        page->chooseLOD();
355
356                }
357        }
358}
Note: See TracBrowser for help on using the repository browser.