Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9088 was 8684, checked in by ponder, 19 years ago

Tried to do the collision detection for the terrain.

File size: 11.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 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 ( unsigned 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 < pagesZ-1    ? getPage( x+0, z+1 ) : NULL,
54                                z > 0                   ? 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                node = new TerrainQuad( this, _x0, _z0, _x1, _z1 );
73                node->setChildren( 
74                        createQuadTree( _x0, _z0, _x01, _z01, _depth+1 ),
75                        createQuadTree( _x01, _z0, _x1, _z01, _depth+1 ), 
76                        createQuadTree( _x0, _z01, _x01, _z1, _depth+1 ), 
77                        createQuadTree( _x01, _z01, _x1, _z1, _depth+1 ) );
78        }
79        node->calculateBounds();
80        return node;
81}
82
83pTerrainPage Terrain::createPage( int _xOffset, int _zOffset ) const
84{
85        pTerrainPage newPage = new TerrainPage( const_cast<Terrain*>( this ), _xOffset, _zOffset );
86        newPage->setScale( scale );     
87        newPage->setPosition( Triple( scale.x*_xOffset, 0.0f, scale.z*_zOffset ) );
88        newPage->calculateErrors();
89        return newPage;
90}
91
92void Terrain::addLevelFourPage( int _numVertices, Vertex *_vertices, 
93        int _numIndices, unsigned short *_indices )
94{
95        assert( indices ); assert( vertices );
96        BufferInfo bi = buffers[current];       
97        if ( ( MAX_VERTICES < _numVertices+bi.numVertices ) || 
98                ( MAX_INDICES < _numIndices+bi.numIndices+2 ) ) {
99                //So, we need the next vb and ib. Lets put the old into vram...
100                glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
101                glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ), 
102                        vertices, GL_DYNAMIC_DRAW_ARB );
103                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, bi.ibIdentifier );
104                glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ), 
105                        indices, GL_DYNAMIC_DRAW_ARB );
106                //printf( "uploaded %d verts and %d indices\n", bi.numIndices, bi.numVertices );
107                BufferInfo newInfo;
108                broker->acquire( newInfo.vbIdentifier, newInfo.ibIdentifier );                 
109                current++;     
110                buffers.push_back( newInfo );   
111                bi = newInfo;
112        }
113        //For the vertex data, a simple copy operation is sufficient...
114        memcpy( &vertices[bi.numVertices], _vertices, 
115                _numVertices*sizeof( Vertex ) );
116        bi.numVertices+=_numVertices;
117        //The indices need to be updated with an offset :(
118        unsigned short *end = _indices+_numIndices;
119        unsigned short *dst = indices+bi.numIndices;
120        int offset = bi.numIndices;
121        if ( bi.numIndices > 0 ) {
122                indices[bi.numIndices] = indices[bi.numIndices-1];
123                indices[bi.numIndices+1] = _indices[0]+offset;
124                dst+=2;
125                bi.numIndices+=2;
126        }
127        for ( unsigned short *i = _indices; i < end; ++i, ++dst ) {
128                *dst = *i+offset;
129        }
130        bi.numIndices+=_numIndices;
131        buffers[current] = bi;
132}
133
134void Terrain::determineVisiblePages( pTerrainQuad _node )
135{
136        switch( _node->cull() ) {
137                case Frustum::INTERSECT:
138                        //printf( "partially inside frustum\n" );
139                        if ( !_node->isChildless() ) {
140                                pTerrainQuad *children = _node->getChildren();
141                                for ( int i = 0; i < 4; ++i, ++children )
142                                        determineVisiblePages( *children );
143                        }
144                        else {
145                                showPages( _node->getXOffset(), 
146                                                   _node->getZOffset(), 1, 1 );
147                        }
148                        break;
149                case Frustum::INSIDE:
150                        //printf( "fully inside frustum\n" );                   
151                        showPages( _node->getXOffset(), 
152                                           _node->getZOffset(), 
153                                           _node->getWidth() , 
154                                           _node->getHeight() );
155                        break;
156                case Frustum::OUTSIDE:
157                        cullCount+= (_node->getWidth()-1)*(_node->getHeight()-1);
158                        break;
159        }
160}
161
162void Terrain::draw( )
163{
164        static float s = 0.0f;
165        glGetError();
166        pTerrainPage page = NULL;
167        frustum->extractPlanes();
168       
169        /**
170         * Enable texture and vertex arrays for the first and the second texture
171         * units and disable the normal arrays.
172         */
173        glClientActiveTextureARB( GL_TEXTURE0_ARB );   
174                glEnableClientState( GL_VERTEX_ARRAY );
175                glEnableClientState( GL_TEXTURE_COORD_ARRAY ); 
176                glDisableClientState( GL_NORMAL_ARRAY );
177                               
178        glClientActiveTextureARB( GL_TEXTURE1_ARB );   
179                glEnableClientState( GL_VERTEX_ARRAY );
180                glEnableClientState( GL_TEXTURE_COORD_ARRAY );
181                glDisableClientState( GL_NORMAL_ARRAY ); 
182        glDisable( GL_CULL_FACE );
183        glDisable( GL_LIGHTING );
184        glColor3f( 1.0f, 1.0f, 1.0f );
185        //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
186        cullCount = 0;
187       
188        // Lets see which pages are visible.
189        determineVisiblePages( root );
190        int wantedLeft, wantedRight, wantedBottom, wantedTop, minLOD;
191        pTerrainPage neighbor = NULL;
192        page = activePages;
193        bool dirty;
194        current = 0;
195        BufferInfo bi;
196        broker->acquire( bi.vbIdentifier, bi.ibIdentifier );
197        buffers.push_back( bi );
198        int dirtyRounds = 0;
199        do {
200                dirtyRounds++;
201                dirty = false;
202                page = activePages;
203                while ( page ) {
204                        if ( !page->isActive() ) {
205                                pTerrainPage tmp = page;
206                                page = tmp->getNext();
207                                tmp->setVisibility( false );
208                                continue;
209                        }
210                        wantedLeft = wantedRight = wantedBottom = wantedTop = page->getWantedLOD();
211                        if ( ( neighbor = page->getLeft() ) && ( neighbor->isActive() ) ) 
212                                wantedLeft = neighbor->getWantedLOD();
213                        if ( ( neighbor = page->getRight() ) && ( neighbor->isActive() ) ) 
214                                wantedRight = neighbor->getWantedLOD();
215                        if ( ( neighbor = page->getTop() ) && ( neighbor->isActive() ) ) 
216                                wantedTop = neighbor->getWantedLOD();
217                        if ( ( neighbor = page->getBottom() ) && ( neighbor->isActive() ) ) 
218                                wantedBottom = neighbor->getWantedLOD();                       
219               
220                        minLOD = std::min( std::min( wantedBottom, wantedTop ), 
221                                std::min( wantedLeft, wantedRight ) ); 
222                        if ( minLOD < page->getWantedLOD()-1 ) {
223                                page->setWantedLOD( minLOD+1 );
224                                dirty = true;
225                        }       
226                        page = page->getNext();
227                }
228        } while ( dirty );
229       
230        page = activePages;
231        while ( page ) {
232                page->updateTesselation();
233                page = page->getNext();
234        }
235        //Finish the last buffer
236        if ( buffers[current].numIndices != 0 ) {
237                BufferInfo bi = buffers[current];       
238                glBindBufferARB( GL_ARRAY_BUFFER_ARB, 
239                        bi.vbIdentifier );
240                glBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_VERTICES*sizeof( Vertex ), 
241                        vertices, GL_DYNAMIC_DRAW_ARB );
242                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 
243                        bi.ibIdentifier );
244                glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, MAX_INDICES*sizeof( short ), 
245                        indices, GL_DYNAMIC_DRAW_ARB );
246        }
247        s = 200.0f;
248        glPushAttrib( GL_COLOR_BUFFER_BIT );
249        for ( unsigned int i = 0; i < materials.size(); ++i ) {
250                page = activePages;     
251               
252                //This is a hack! Remove this as soon as possible
253                materials[i]->unselect();
254                materials[i]->select();
255               
256                glActiveTextureARB( GL_TEXTURE1_ARB );
257                glClientActiveTextureARB( GL_TEXTURE1_ARB );
258                glMatrixMode( GL_TEXTURE );
259                glLoadIdentity();
260                glScalef( s, s, s );
261
262                glClientActiveTextureARB( GL_TEXTURE0_ARB );
263                glActiveTextureARB( GL_TEXTURE0_ARB );
264                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );                         
265                glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
266                for ( unsigned j = 0; j < buffers.size(); ++j ) {
267                        BufferInfo bi = buffers[j];
268                        glBindBufferARB( GL_ARRAY_BUFFER_ARB, bi.vbIdentifier );
269                        glClientActiveTextureARB( GL_TEXTURE0_ARB );
270                        glInterleavedArrays( GL_T2F_V3F, 0, NULL );
271
272                        glClientActiveTextureARB( GL_TEXTURE1_ARB );
273                        glInterleavedArrays( GL_T2F_V3F, 0, NULL );
274
275                        glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 
276                                bi.ibIdentifier );     
277
278                        glDrawElements( GL_TRIANGLE_STRIP, bi.numIndices, 
279                                                        GL_UNSIGNED_SHORT, NULL );
280                }
281                while ( page ) {
282                        if ( page->hasMaterial( i ) )
283                                page->draw();
284                        page = page->getNext();
285                }
286                activatedCount = 0; deactivatedCount = 0;
287        }
288       
289        //Get rid of the buffers
290       
291        for ( unsigned int i = 0; i < buffers.size(); ++i )
292                broker->release( buffers[i].vbIdentifier, buffers[i].ibIdentifier );
293        buffers.clear();
294               
295        glClientActiveTextureARB( GL_TEXTURE1_ARB );   
296        glDisableClientState( GL_VERTEX_ARRAY );
297        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
298        glDisableClientState( GL_VERTEX_ARRAY );
299        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
300        materials[0]->unselect();
301        glActiveTextureARB( GL_TEXTURE0_ARB );
302        glClientActiveTextureARB( GL_TEXTURE0_ARB );   
303        glDisableClientState( GL_VERTEX_ARRAY );
304        glDisableClientState( GL_TEXTURE_COORD_ARRAY ); 
305        glEnable( GL_LIGHTING );
306        glMatrixMode( GL_TEXTURE );
307        glLoadIdentity();
308        glPopAttrib();
309}
310
311
312
313void Terrain::getAltitude( Triple& _alt, Triple& _normal )
314{
315        float xScaled = _alt.x / scale.x, zScaled = _alt.z / scale.z;
316        //The offset on the map
317        int xOff =  (int)xScaled, zOff = (int)zScaled;
318        //The interpolation values.
319        float u = xScaled-xOff, v = zScaled-zOff;
320       
321        float dX = scale.x / ( pageSize-1 );
322        float dZ = scale.z / ( pageSize-1 );
323       
324        //If u is bigger than v, we are on the lower triangle...
325        if ( u > v ) {
326               
327                float alt[] = {
328                        getAltitude( xOff+0, zOff+0 )*scale.y,
329                        getAltitude( xOff+1, zOff+0 )*scale.y,
330                        getAltitude( xOff+1, zOff+1 )*scale.y };
331                _alt.y = (1.0f-u-v)*alt[0]+u*alt[1]+v*alt[2];
332               
333                //Since we know about the directions of some x and z-coordinates,
334                //not the whole cross products needs to be calculated. Grab yourself
335                //pen and paper :)
336                _normal.x = -dZ*( alt[0] - alt[1] );                           
337                _normal.y = -dZ*dX;
338                _normal.z =  dX*( alt[2] - alt[1] );
339        }
340        else {
341                float alt[] = {
342                        getAltitude( xOff+0, zOff+0 )*scale.y,
343                        getAltitude( xOff+0, zOff+1 )*scale.y,
344                        getAltitude( xOff+1, zOff+1 )*scale.y };                       
345                _alt.y = (1.0f-u-v)*alt[0]+v*alt[1]+u*alt[2];
346                //Since we know about the directions of some x and z-coordinates,
347                //not the whole cross products needs to be calculated. Grab yourself
348                //pen and paper :)
349                _normal.x =  dZ*( alt[2] - alt[1] );                           
350                _normal.y = -dZ*dX;
351                _normal.z = -dX*( alt[0] - alt[1] );
352        }
353}
354
355void Terrain::showPages( int _x0, int _z0, int _width, int _height )
356{
357        for ( int x = 0; x < _width; ++x ) {
358                for ( int z = 0; z < _height; ++z ) {
359                        pTerrainPage page = getPage( _x0+x, _z0+z );
360                        page->setVisibility( true );                   
361                        page->chooseLOD();
362
363                }
364        }
365}
Note: See TracBrowser for help on using the repository browser.