Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8748 was 8748, checked in by ponder, 18 years ago

Small changes to help debug

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