Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8593 was 8593, checked in by ponder, 18 years ago
File size: 8.7 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...
32        pagesX = (heightfield.width/(pageSize-1) );
33        pagesZ = (heightfield.height/(pageSize-1) );
34        //tex = (Texture*)MANAGER->load( lightmapSource );
35        //TODO: Determine layer visibility!     
36        for ( int i = 0; i < materials.size(); ++i ) {
37               
38        }
39
40        printf( " * creating terrain pages ( %d, %d )...", pagesX, pagesZ );
41        pages = new pTerrainPage[pagesX*pagesZ];       
42        for ( int x = 0; x < pagesX; ++x )
43                for ( int z = 0; z < pagesZ; ++z )
44                        pages[z*pagesX+x] = createPage( x, z );
45        printf( "looks good\n" );
46        printf( " * inform pages about the adjacent pages..." );                       
47        //Inform each page about its neighbors.
48        for ( int x = 0; x < pagesX; ++x )
49                for ( int z = 0; z < pagesZ; ++z )
50                        pages[z*pagesX+x]->setNeighbors(
51                                x > 0                   ? getPage( x-1, z+0 ) : NULL,
52                                x < pagesX-1    ? getPage( x+1, z+0 ) : NULL, 
53                                z > 0                   ? getPage( x+0, z-1 ) : NULL,
54                                z < pagesZ-1    ? getPage( x+0, z+1 ) : NULL );
55       
56        printf( "looks good\n" );
57        printf( " * creating quad_tree data structure..." );
58        root = createQuadTree( 0, 0, pagesX, pagesZ );
59        activePages = NULL;
60        printf( "looks good\n" );
61}
62
63pTerrainQuad Terrain::createQuadTree( int _x0, int _z0, int _x1, int _z1, int _depth )
64{
65        int _x01 = (_x1+_x0)/2; int _z01 = (_z1+_z0)/2;
66        pTerrainQuad node;
67        if ( _x1-_x0 == 1 ) {
68                node = getPage( _x0, _z0 );
69                node->setChildren( NULL, NULL, NULL, NULL );
70        }
71        else {
72                assert( ( _x0 % 2 ) == 0 ); 
73                assert( ( _x1 % 2 ) == 0 ); 
74                assert( ( _z0 % 2 ) == 0 ); 
75                assert( ( _z1 % 2 ) == 0 );             
76                node = new TerrainQuad( this, _x0, _z0, _x1, _z1 );
77                node->setChildren( 
78                        createQuadTree( _x0, _z0, _x01, _z01, _depth+1 ),
79                        createQuadTree( _x01, _z0, _x1, _z01, _depth+1 ), 
80                        createQuadTree( _x0, _z01, _x01, _z1, _depth+1 ), 
81                        createQuadTree( _x01, _z01, _x1, _z1, _depth+1 ) );
82        }
83        node->calculateBounds();
84        return node;
85}
86
87pTerrainPage Terrain::createPage( int _xOffset, int _zOffset ) const
88{
89        pTerrainPage newPage = new TerrainPage( const_cast<Terrain*>( this ), _xOffset, _zOffset );
90        newPage->setScale( scale );     
91        newPage->setPosition( Triple( scale.x*_xOffset, 0.0f, scale.z*_zOffset ) );
92        newPage->calculateErrors();
93        return newPage;
94}
95
96void Terrain::determineVisiblePages( pTerrainQuad _node )
97{
98        switch( _node->cull() ) {
99                case Frustum::INTERSECT:
100                        //printf( "partially inside frustum\n" );
101                        if ( !_node->isChildless() ) {
102                                pTerrainQuad *children = _node->getChildren();
103                                for ( int i = 0; i < 4; ++i, ++children )
104                                        determineVisiblePages( *children );
105                        }
106                        else {
107                                showPages( _node->getXOffset(), 
108                                                   _node->getZOffset(), 1, 1 );
109                        }
110                        break;
111                case Frustum::INSIDE:
112                        //printf( "fully inside frustum\n" );                   
113                        showPages( _node->getXOffset(), 
114                                           _node->getZOffset(), 
115                                           _node->getWidth() , 
116                                           _node->getHeight() );
117                        break;
118                case Frustum::OUTSIDE:
119                        cullCount+= (_node->getWidth()-1)*(_node->getHeight()-1);
120                        break;
121        }
122}
123
124void Terrain::draw( )
125{
126        static float s = 0.0f;
127        glGetError();
128        pTerrainPage page = NULL;
129        frustum->extractPlanes();
130       
131        /**
132         * Enable texture and vertex arrays for the first and the second texture
133         * units and disable the normal arrays.
134         */
135        glClientActiveTextureARB( GL_TEXTURE0_ARB );   
136                glEnableClientState( GL_VERTEX_ARRAY );
137                glEnableClientState( GL_TEXTURE_COORD_ARRAY ); 
138                glDisableClientState( GL_NORMAL_ARRAY );
139                               
140        glClientActiveTextureARB( GL_TEXTURE1_ARB );   
141                glEnableClientState( GL_VERTEX_ARRAY );
142                glEnableClientState( GL_TEXTURE_COORD_ARRAY );
143                glDisableClientState( GL_NORMAL_ARRAY ); 
144               
145        glDisable( GL_LIGHTING );
146        glColor3f( 1.0f, 1.0f, 1.0f );
147        //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
148        cullCount = 0;
149       
150        // Lets see which pages are visible.
151        determineVisiblePages( root );
152        int wantedLeft, wantedRight, wantedBottom, wantedTop, minLOD;
153        pTerrainPage neighbor = NULL;
154        page = activePages;
155        bool dirty;
156        do {
157                dirty = false;
158                page = activePages;
159                while ( page ) {
160                        if ( !page->isActive() ) {
161                                pTerrainPage tmp = page;
162                                page = tmp->getNext();
163                                tmp->setVisibility( false );
164                                continue;
165                        }
166                        wantedLeft = wantedRight = wantedBottom = wantedTop = page->getWantedLOD();
167                        if ( ( neighbor = page->getLeft() ) ) 
168                                wantedLeft = neighbor->getWantedLOD();
169                        if ( ( neighbor = page->getRight() ) ) 
170                                wantedRight = neighbor->getWantedLOD();
171                        if ( ( neighbor = page->getTop() ) ) 
172                                wantedTop = neighbor->getWantedLOD();
173                        if ( ( neighbor = page->getBottom() ) ) 
174                                wantedBottom = neighbor->getWantedLOD();                       
175               
176                        minLOD = std::min( std::min( wantedBottom, wantedTop ), std::min( wantedLeft, wantedRight ) ); 
177                        if ( minLOD < page->getWantedLOD()-1 ) {
178                                page->setWantedLOD( minLOD+1 );
179                                //dirty = true;
180                        }       
181                        page = page->getNext();
182                }
183        } while ( dirty );
184        page = activePages;
185       
186        while ( page ) {
187                page->updateTesselation();
188                page = page->getNext();
189        }
190       
191        s = 500.0f;
192        for ( int i = 0; i < materials.size(); ++i ) {
193                page = activePages;     
194               
195                //This is a hack! Remove this as soon as possible
196                materials[i]->unselect();
197                materials[i]->select();
198               
199                glActiveTextureARB( GL_TEXTURE1_ARB );
200                glClientActiveTextureARB( GL_TEXTURE1_ARB );
201                glMatrixMode( GL_TEXTURE );
202                glLoadIdentity();
203                glScalef( s, s, s );
204               
205                glClientActiveTextureARB( GL_TEXTURE0_ARB );
206                glActiveTextureARB( GL_TEXTURE0_ARB );
207                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );                         
208                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
209                while ( page ) {
210                        //Draw the page. TODO: It would be nice if all the pages with an LOD of 4 could be merged
211                        //in one index buffer. This would give us a speed boost for sure...
212                        if ( page->hasMaterial( i ) )
213                                page->draw();
214                        page = page->getNext();
215                }
216                activatedCount = 0; deactivatedCount = 0;
217                //printf( "%d of %d pages drawn\n", pagesX*pagesZ-cullCount, pagesX*pagesZ );
218                //float percentage = (float)cullCount/(float)(pagesX*pagesZ)*100.0f;
219                //printf( "culled %f%% terrain pages away\n",  percentage );
220        }
221        glClientActiveTextureARB( GL_TEXTURE1_ARB );   
222        glDisableClientState( GL_VERTEX_ARRAY );
223        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
224        glDisableClientState( GL_VERTEX_ARRAY );
225        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
226        materials[0]->unselect();
227        glActiveTextureARB( GL_TEXTURE0_ARB );
228        glClientActiveTextureARB( GL_TEXTURE0_ARB );   
229        glDisableClientState( GL_VERTEX_ARRAY );
230        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
231        glEnable( GL_LIGHTING );
232}
233
234
235
236void Terrain::getAltitude( Triple& _alt, Triple& _normal )
237{
238        float xScaled = _alt.x / scale.x, zScaled = _alt.z / scale.z;
239        //The offset on the map
240        int xOff =  (int)xScaled, zOff = (int)zScaled;
241        //The interpolation values.
242        float u = xScaled-xOff, v = zScaled-zOff;
243       
244        float dX = scale.x / ( pageSize-1 );
245        float dZ = scale.z / ( pageSize-1 );
246       
247        //If u is bigger than v, we are on the lower triangle...
248        if ( u > v ) {
249               
250                float alt[] = {
251                        getAltitude( xOff+0, zOff+0 )*scale.y,
252                        getAltitude( xOff+1, zOff+0 )*scale.y,
253                        getAltitude( xOff+1, zOff+1 )*scale.y };
254                _alt.y = (1.0f-u-v)*alt[0]+u*alt[1]+v*alt[2];
255               
256                //Since we know about the directions of some x and z-coordinates,
257                //not the whole cross products needs to be calculated. Grab yourself
258                //pen and paper :)
259                _normal.x = -dZ*( alt[0] - alt[1] );                           
260                _normal.y = -dZ*dX;
261                _normal.z =  dX*( alt[2] - alt[1] );
262        }
263        else {
264                float alt[] = {
265                        getAltitude( xOff+0, zOff+0 )*scale.y,
266                        getAltitude( xOff+0, zOff+1 )*scale.y,
267                        getAltitude( xOff+1, zOff+1 )*scale.y };                       
268                _alt.y = (1.0f-u-v)*alt[0]+v*alt[1]+u*alt[2];
269                //Since we know about the directions of some x and z-coordinates,
270                //not the whole cross products needs to be calculated. Grab yourself
271                //pen and paper :)
272                _normal.x =  dZ*( alt[2] - alt[1] );                           
273                _normal.y = -dZ*dX;
274                _normal.z = -dX*( alt[0] - alt[1] );
275        }
276}
277
278void Terrain::showPages( int _x0, int _z0, int _width, int _height )
279{
280        for ( int x = 0; x < _width; ++x ) {
281                for ( int z = 0; z < _height; ++z ) {
282                        pTerrainPage page = getPage( _x0+x, _z0+z );
283                        page->setVisibility( true );                   
284                        page->chooseLOD();
285
286                }
287        }
288}
Note: See TracBrowser for help on using the repository browser.