Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8593 was 8593, checked in by ponder, 18 years ago
File size: 17.1 KB
Line 
1/*
2        orxonox - the future of 3D-vertical-scrollers
3 
4        Copyright (C) 2006 orx
5 
6        This program is free software; you can redistribute it and/or modify
7        it under the terms of the GNU General Public License as published by
8        the Free Software Foundation; either version 2, or (at your option)
9        any later version.
10 
11        ### File Specific:
12        main-programmer: Marco Biasini
13 
14 */
15#include "terrain_page.h"
16#include "terrain.h"
17#include "glincl.h"
18#include <stdio.h>
19#include <math.h>
20#define USE_VBO
21
22#define CHECK_GL_ERROR( _d ) do { \
23        GLenum __err = glGetError(); \
24        if ( __err != GL_NO_ERROR ) \
25                printf( "check%s: %s\n", _d, (char*)gluErrorString( __err ) );\
26        }\
27        while ( 0 )
28
29TerrainPage::TerrainPage( Terrain *_owner, int _xOffset, int _zOffset )
30: TerrainQuad( _owner, _xOffset, _zOffset )
31{
32        scale = owner->getScale();
33        numVertices = numIndices = 0;
34        errors = new LODError[TerrainPage::MAX_LODS];
35        vertices = NULL; indices = NULL;
36        position = Triple( scale.x*_xOffset, 0.0f, scale.z*_zOffset );
37        isVisible = false;
38        next = NULL;
39        active = false;
40        previous = NULL;
41        currentLOD = -1;
42        forceTesselation = true;
43}
44
45void TerrainPage::tesselateRow( int _z, int _xStride, int _zStride, bool _adaptLeft, bool _adaptRight )
46{
47       
48        int xStart = 0, xEnd = owner->getPageSize();   
49        int halfStride = _zStride >> 1;
50        assert( _xStride > 0 );         assert( _zStride > 0 );
51        if ( _z ) {
52                addAgain( );
53                addIndex( getIndex( 0, _z ) );
54        }
55        if ( _adaptLeft ) {
56                assert( halfStride > 0 );               
57                addIndex( getIndex( 0, _z ) );
58                addIndex( getIndex( 0, _z+halfStride ) );
59                addIndex( getIndex( _xStride, _z ) );
60                addIndex( getIndex( 0, _z+_zStride ) );
61                addIndex( getIndex( _xStride, _z+_zStride ) );
62                addAgain();
63                xStart = _xStride;
64        }
65       
66        if ( _adaptRight )
67                xEnd-=_xStride;
68               
69        for ( int x = xStart; x < xEnd; x+=_xStride ) {
70                addIndex( getIndex( x, _z) );
71                addIndex( getIndex( x, _z+_zStride ) );
72        }
73       
74        int w = owner->getPageSize()-1;
75       
76        if ( _adaptRight ) {
77                assert( halfStride > 0 );               
78                addIndex( getIndex( w-_xStride, _z ) );
79                addAgain();
80                addIndex( getIndex( w, _z ) );
81                addIndex( getIndex( w-_xStride, _z+_zStride ) );
82                addIndex( getIndex( w, _z+halfStride ) );
83                addIndex( getIndex( w, _z+_zStride ) );
84        }
85}
86
87//TODO: Perform benchmark to measure if the isVisible test should be included
88//in this method.
89void TerrainPage::determineBorderAdaption( bool _adapt[] )
90{
91        _adapt[0] = _adapt[1] = _adapt[2] = _adapt[3] = false;
92       
93        if ( left  && left->isVisible ) 
94                _adapt[TP_LEFT] = ( wantedLOD - left->getWantedLOD() ) > 0;
95               
96        if ( right && right->isVisible ) 
97                _adapt[TP_RIGHT] = ( wantedLOD - right->getWantedLOD() ) > 0;
98               
99        if ( top && top->isVisible) 
100                _adapt[TP_TOP] = ( wantedLOD - top->getWantedLOD() ) > 0;                               
101               
102        if ( bottom && bottom->isVisible ) 
103                _adapt[TP_BOTTOM] = ( wantedLOD - bottom->getWantedLOD() ) > 0;         
104}
105
106int TerrainPage::chooseLOD()
107{
108        wantedLOD = -1;
109        Triple cam( owner->getCameraPosition() );
110       
111        for ( int i = TerrainPage::MAX_LODS-1; i >= 0; --i ) {
112                Triple distance( cam.x-errors[i].correct.x,
113                                                 cam.y-errors[i].correct.y,
114                                                 cam.z-errors[i].correct.z );
115               
116                float d = distance.length();
117               
118                assert( d > 0.000001f );
119                float err =  errors[i].diff / d ;
120               
121                if ( err*scale.y < owner->getDetail() ) {
122                        wantedLOD = i;
123                        break;
124                }       
125        }
126        if ( wantedLOD < 0 ) {
127                wantedLOD = TerrainPage::MAX_LODS-1;
128        }       
129        // Calculate the tween factor. The calculation is different if LOD is 0
130        //
131        if ( wantedLOD > 0 ) {
132               
133        }
134        else {
135               
136        }
137        return wantedLOD;
138}
139
140void TerrainPage::activate()
141{
142       
143        pTerrainPage list = owner->getActiveList();
144        next = list;
145        if ( list )
146                list->previous = this;
147        owner->setActiveList( this );
148}
149
150void TerrainPage::deactivate()
151{
152        pTerrainPage list = owner->getActiveList();
153       
154        if ( previous ) {
155                previous->next = next;
156        }
157        if ( next ) {
158                next->previous = previous;
159        }
160        if ( list == this )
161                owner->setActiveList( next );
162        next = NULL;
163        previous = NULL;
164       
165}
166
167void TerrainPage::calculateError( int _lod )
168{
169        float   sumError = 0.0f;
170        int             numErrors = 0;
171        int size = owner->getPageSize();
172        if( _lod!=0 )
173        {
174                int stride = 1 << _lod, x0, y0, xi, yi;
175                // Altough these four nested loops look very scary, they're not
176                // that bad and require only about O(n^2).
177                for( y0 = 0 ; y0 < size-stride; y0 += stride ) {
178                        for( x0 = 0; x0 < size-stride; x0 += stride ) {
179                                for( yi = 1; yi < stride; yi++ ) {
180                                        for( xi = 1; xi < stride; xi++ )
181                                        {
182                                                int     x = x0+xi,
183                                                y = y0+yi;
184                                                float   fx0 = ( float )xi/( float )stride, fx1 = 1.0f-fx0,
185                                                                fy0 = ( float )yi/( float )stride, fy1 = 1.0f-fy0;
186                                               
187                                                float   height00 = getAltitude( x0, y0 ),
188                                                                height10 = getAltitude( x0+stride,y0 ),
189                                                                height01 = getAltitude( x0,y0+stride ),
190                                                                height11 = getAltitude( x0+stride, y0+stride );
191                                               
192                                                float   paintHeight =   fx1*fy1 * height00 +
193                                                        fx0*fy1 * height10 +
194                                                        fx1*fy0 * height01 +
195                                                        fx0*fy0 * height11,
196                                                        correctHeight =  getAltitude( x, y );
197                                               
198                                                float   er = ( float )fabs( correctHeight - paintHeight );
199                                               
200                                                numErrors++;
201                                                sumError += er;
202                                        }
203                                }
204                        }
205                }
206                float error = sumError / numErrors;
207                getVertex(size/2, size/2, errors[_lod].correct);
208                errors[_lod].real = errors[_lod].correct;
209                errors[_lod].real.y += error;
210                errors[_lod].diff = error;
211        }
212}
213
214void TerrainPage::calculateBounds()
215{
216        int size = owner->getPageSize();
217        float alt = 0.0f;
218       
219        Triple  min( xOffset*scale.x ,0.0f, zOffset*scale.z ), 
220                        max( (xOffset+1)*scale.x, 0.0f, (zOffset+1)*scale.z);
221       
222        min.y = max.y = getAltitude( 0, 0 );
223        for ( int x = 0; x < size; ++x ) {
224                for ( int z = 0; z < size; ++z ) {
225                        alt = getAltitude( x, z );
226                        min.y = fmin( min.y, alt );
227                        max.y = fmax( max.y, alt );
228                }
229        }
230        bounds.set( min, max );
231}
232
233float TerrainPage::getAltitude( int _x, int _z ) const
234{
235        assert( _x >= 0 && _x < 17 );
236        assert( _z >= 0 && _z < 17 );
237        return position.y+scale.y*owner->getAltitude( 
238                        _x+(owner->getPageSize()-1)*xOffset, 
239                        _z+(owner->getPageSize()-1)*zOffset );
240}
241
242bool TerrainPage::needsRetesselation()
243{
244       
245        bool    leftChanged     = ( left && left->isVisible ) && ( left->wantedLOD != left->currentLOD ),
246                        rightChanged    = ( right && right->isVisible ) && ( right->wantedLOD != right->currentLOD ),
247                        topChanged              = ( top && top->isVisible ) && ( top->wantedLOD != currentLOD ),
248                        bottomChanged   = ( bottom && bottom->isVisible ) && ( bottom->wantedLOD != bottom->currentLOD ),
249                        iChanged                =  wantedLOD != currentLOD;
250                               
251        return ( leftChanged || rightChanged || topChanged || bottomChanged || forceTesselation || iChanged );
252}
253
254void TerrainPage::updateTesselation( )
255{
256
257        if ( needsRetesselation() ) {
258                tesselate( wantedLOD );
259        }       
260        currentLOD = wantedLOD;
261        forceTesselation = false;
262}
263
264void TerrainPage::tesselateLevelFourPatch( bool _adapt[] )
265{
266        const int       halfStride = 8, stride = 16;
267       
268        enum { ADAPT_L = 1, ADAPT_R = 2, ADAPT_B = 4, ADAPT_T = 8,
269                ADAPT_LR = 3, ADAPT_LB = 5, ADAPT_LT = 9, ADAPT_RB = 6, 
270                ADAPT_RT = 10, ADAPT_BT = 12, ADAPT_LRB = 7, ADAPT_LBT = 13, ADAPT_LRT = 11, 
271                ADAPT_RBT = 14, ADAPT_LRBT = 15, ADAPT_NONE = 0 };
272               
273        int                     code =  ( _adapt[TP_LEFT]       ? ADAPT_L : 0 ) | 
274                                                ( _adapt[TP_RIGHT]      ? ADAPT_R : 0 ) | 
275                                                ( _adapt[TP_BOTTOM] ? ADAPT_B : 0 ) | 
276                                                ( _adapt[TP_TOP]        ? ADAPT_T : 0 );
277        switch( code ) {
278                case ADAPT_NONE:
279                        addIndex( getIndex( 0, 0 ) );
280                        addIndex( getIndex( 0, stride ) );
281                        addIndex( getIndex( stride, 0 ) );
282                        addIndex( getIndex( stride, stride ) );
283                        break;
284                       
285                case ADAPT_L:
286                        addIndex( getIndex( 0, 0 ) );
287                        addIndex( getIndex( 0, halfStride ) );
288                        addIndex( getIndex( stride, 0 ) );
289                        addIndex( getIndex( 0, stride ) );
290                        addIndex( getIndex( stride, stride ) );
291                        addAgain(  );
292                        break;
293               
294                case ADAPT_R:
295                        addIndex( getIndex( stride, stride ) );
296                        addIndex( getIndex( stride, halfStride ) );
297                        addIndex( getIndex( 0, stride ) );
298                        addIndex( getIndex( stride, 0 ) );
299                        addIndex( getIndex( 0, 0 ) );
300                        addAgain(  );
301                        break;
302
303                case ADAPT_LR:
304                        addIndex( getIndex( 0, 0 ) );
305                        addIndex( getIndex( 0, halfStride ) );
306                        addIndex( getIndex( stride, 0 ) );
307                        addIndex( getIndex( 0, stride ) );
308                        addIndex( getIndex( stride, halfStride ) );
309                        addIndex( getIndex( stride, stride ) );
310                        break;
311
312                case ADAPT_B:
313                        addIndex( getIndex( 0, 0 ) );
314                        addAgain(  );
315                        addIndex( getIndex( halfStride, 0 ) );
316                        addIndex( getIndex( 0, stride ) );
317                        addIndex( getIndex( stride, 0 ) );
318                        addIndex( getIndex( stride, stride ) );
319                        break;
320
321                case ADAPT_LB:
322                        addIndex( getIndex( 0, 0 ) );
323                        addIndex( getIndex( 0, halfStride ) );
324                        addIndex( getIndex( halfStride, 0 ) );
325                        addIndex( getIndex( 0, stride ) );
326                        addIndex( getIndex( stride, 0 ) );
327                        addIndex( getIndex( stride, stride ) );
328                        break;
329
330                case ADAPT_RB:
331                        addIndex( getIndex( 0, 0 ) );
332                        addIndex( getIndex( 0, stride ) );
333                        addIndex( getIndex( halfStride, 0 ) );
334                        addIndex( getIndex( stride, 0 ) );
335                        addAgain(  );
336                        addIndex( getIndex( 0, stride ) );
337                        addIndex( getIndex( stride, halfStride ) );
338                        addIndex( getIndex( stride, stride ) );
339                        break;
340
341                case ADAPT_LRB:
342                        addIndex( getIndex( stride, stride ) );
343                        addIndex( getIndex( stride, halfStride ) );
344                        addIndex( getIndex( 0, stride ) );
345                        addIndex( getIndex( stride, 0 ) );
346                        addIndex( getIndex( 0, halfStride ) );
347                        addIndex( getIndex( halfStride, 0 ) );
348                        addIndex( getIndex( 0, 0 ) );
349                        addAgain(  );
350                        break;
351
352                case ADAPT_T:
353                        addIndex( getIndex( stride, stride ) );
354                        addAgain(  );
355                        addIndex( getIndex( halfStride, stride ) );
356                        addIndex( getIndex( stride, 0 ) );
357                        addIndex( getIndex( 0, stride ) );
358                        addIndex( getIndex( 0, 0 ) );
359                        break;
360
361                case ADAPT_LT:
362                        addIndex( getIndex( stride, stride ) );
363                        addIndex( getIndex( stride, 0 ) );
364                        addIndex( getIndex( halfStride, stride ) );
365                        addIndex( getIndex( 0, stride ) );
366                        addAgain(  );
367                        addIndex( getIndex( stride, 0 ) );
368                        addIndex( getIndex( 0, halfStride ) );
369                        addIndex( getIndex( 0, 0 ) );
370                        break;
371
372                case ADAPT_RT:
373                        addIndex( getIndex( stride, stride ) );
374                        addIndex( getIndex( stride, halfStride ) );
375                        addIndex( getIndex( halfStride, stride ) );
376                        addIndex( getIndex( stride, 0 ) );
377                        addIndex( getIndex( 0, stride ) );
378                        addIndex( getIndex( 0, 0 ) );
379                        break;
380
381                case ADAPT_LRT:
382                        addIndex( getIndex( 0, 0 ) );
383                        addIndex( getIndex( 0, halfStride ) );
384                        addIndex( getIndex( stride, 0 ) );
385                        addIndex( getIndex( 0, stride ) );
386                        addIndex( getIndex( stride, halfStride ) );
387                        addIndex( getIndex( halfStride, stride ) );
388                        addIndex( getIndex( stride, stride ) );
389                        addAgain(  );
390                        break;
391
392                case ADAPT_BT:
393                        addIndex( getIndex( 0, 0 ) );
394                        addAgain(  );
395                        addIndex( getIndex( halfStride, 0 ) );
396                        addIndex( getIndex( 0, stride ) );
397                        addIndex( getIndex( stride, 0 ) );
398                        addIndex( getIndex( halfStride, stride ) );
399                        addIndex( getIndex( stride, stride ) );
400                        addAgain(  );
401                        break;
402
403                case ADAPT_LBT:
404                        addIndex( getIndex( 0, 0 ) );
405                        addIndex( getIndex( 0, halfStride ) );
406                        addIndex( getIndex( halfStride, 0 ) );
407                        addIndex( getIndex( 0, stride ) );
408                        addIndex( getIndex( stride, 0 ) );
409                        addIndex( getIndex( halfStride, stride ) );
410                        addIndex( getIndex( stride, stride ) );
411                        addAgain(  );
412                        break;
413
414                case ADAPT_RBT:
415                        addIndex( getIndex( stride, stride ) );
416                        addIndex( getIndex( stride, halfStride ) );
417                        addIndex( getIndex( halfStride, stride ) );
418                        addIndex( getIndex( stride, 0 ) );
419                        addIndex( getIndex( 0, stride ) );
420                        addIndex( getIndex( halfStride, 0 ) );
421                        addIndex( getIndex( 0, 0 ) );
422                        addAgain(  );
423                        break;
424
425                case ADAPT_LRBT:
426                        addIndex( getIndex( 0, 0 ) );
427                        addIndex( getIndex( 0, halfStride ) );
428                        addIndex( getIndex( halfStride, 0 ) );
429                        addIndex( getIndex( 0, stride ) );
430                        addIndex( getIndex( stride, 0 ) );
431                        addIndex( getIndex( halfStride, stride ) );
432                        addIndex( getIndex( stride, halfStride ) );
433                        addIndex( getIndex( stride, stride ) );
434                        break;
435        }
436}
437
438
439void TerrainPage::tesselate( int _lod )
440{
441
442        int count = owner->getPageSize()*owner->getPageSize(); 
443
444        memset( indexHash, 0xffff, 
445                        sizeof(unsigned short)*count );
446       
447        numVertices = 0; numIndices = 0;
448       
449        //Calculate the pace, based on the lod.
450        int stride = 1 << _lod;
451               
452        bool adapt[4];
453        determineBorderAdaption( adapt );
454        assert( isVisible );
455#ifdef USE_VBO
456       
457        glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbIdentifier );
458       
459        // The call to glBufferDataARB with a null argument for data is to tell the GPU, that the
460        // old data is invalid. Then calling call glMapBuffer() tells the driver that the previous
461        // data aren’t valid. As a consequence, if the GPU is still working on them, there won’t
462        // be a conflict because we invalidated these data. The function glMapBuffer() returns a
463        // new pointer that we can use while the GPU is working on the previous set of data..
464       
465        glBufferDataARB( GL_ARRAY_BUFFER_ARB, count*sizeof( Vertex ), NULL, GL_DYNAMIC_DRAW_ARB );
466       
467        vertices = (Vertex*)glMapBufferARB( GL_ARRAY_BUFFER_ARB, 
468                GL_WRITE_ONLY_ARB );
469       
470        glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, ibIdentifier );
471       
472        glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 
473                count*3*sizeof( short ), NULL, GL_DYNAMIC_DRAW_ARB );   
474               
475        indices = (unsigned short*)glMapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 
476                GL_WRITE_ONLY_ARB );
477       
478        assert( indices ); 
479        assert( vertices );
480       
481#endif 
482        if ( _lod == TerrainPage::MAX_LODS-1 ) {
483                tesselateLevelFourPatch( adapt );
484                return;
485        }
486       
487        int zStart = 0, zEnd = owner->getPageSize()-stride;
488       
489        if ( adapt[TP_TOP] ) {
490                tesselateRow( 0, stride / 2, stride, adapt[TP_LEFT], adapt[TP_RIGHT] );
491                zStart+= stride;
492        }
493       
494        if ( adapt[TP_BOTTOM] )
495                zEnd-= stride;
496               
497        for ( int z = zStart; z < zEnd; z+=stride )
498                tesselateRow( z, stride, stride, adapt[TP_LEFT], adapt[TP_RIGHT] );
499       
500
501        if ( adapt[TP_BOTTOM] ) {
502               
503        addAgain( );
504        addIndex( getIndex( 0, owner->getPageSize()-1-stride ) );
505       
506        tesselateRow( owner->getPageSize()-1-stride, stride / 2, stride, adapt[TP_LEFT], adapt[TP_RIGHT] );
507        }
508       
509#ifdef USE_VBO
510        glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
511        glUnmapBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB );
512#endif
513
514}
515
516
517void TerrainPage::show( )
518{
519        int count = owner->getPageSize()*owner->getPageSize();
520       
521#ifdef USE_VBO 
522        owner->getBufferBroker()->acquire( vbIdentifier, ibIdentifier );
523        vertices = NULL;
524        indices = NULL;
525#else
526        vertices = new Vertex[count];
527        // Not the economical way, but we just want to have space for all indices.
528        indices = new unsigned short[count*3];
529#endif 
530
531        indexHash = new unsigned short[count]; 
532        forceTesselation = true;
533        activate();
534        active = true;
535       
536}
537
538void TerrainPage::hide( )
539{
540#ifdef USE_VBO
541        owner->getBufferBroker()->release( vbIdentifier, ibIdentifier );
542#else   
543        if ( vertices ) {
544                delete[] vertices;
545                vertices = NULL;
546        }
547        if ( indices ) {
548                delete[] indices;
549                indices = NULL;
550                numIndices = 0;
551        }
552#endif
553        deactivate();
554}
555
556void TerrainPage::drawBox()
557{
558        glMatrixMode( GL_MODELVIEW );
559        glPushMatrix();
560        glTranslatef( bounds.corner.x, bounds.corner.y, bounds.corner.z );
561        glBegin( GL_QUADS );
562                glVertex3f( 0.0f, 0.0f, 0.0f );
563                glVertex3f(  bounds.x, 0.0f, 0.0f );
564                glVertex3f( bounds.x, bounds.y, 0.0f );
565                glVertex3f( 0.0f, bounds.y, 0.0f );
566               
567                glVertex3f( 0.0f, 0.0f, bounds.z );
568                glVertex3f(  bounds.x, 0.0f, bounds.z );
569                glVertex3f( bounds.x, bounds.y, bounds.z );
570                glVertex3f( 0.0f, bounds.y, bounds.z );         
571               
572                glVertex3f( 0.0f, 0.0f, 0.0 );
573                glVertex3f(  0.0, 0.0f, bounds.z );
574                glVertex3f( 0.0f, bounds.y, bounds.z );
575                glVertex3f( 0.0f, bounds.y, 0.0f );                             
576               
577                glVertex3f( bounds.x, 0.0f, 0.0 );
578                glVertex3f(  bounds.x, 0.0f, bounds.z );
579                glVertex3f( bounds.x, bounds.y, bounds.z );
580                glVertex3f( bounds.x, bounds.y, 0.0f );                                         
581        glEnd();
582        glPopMatrix();
583}
584
585void TerrainPage::draw( )
586{
587        assert( glIsEnabled( GL_VERTEX_ARRAY ) );
588        assert( !glIsEnabled( GL_NORMAL_ARRAY ) );
589       
590        assert( isVisible ); assert( numIndices > 0 );
591        assert( active );
592        active = false;
593        CHECK_GL_ERROR( "1" ); 
594       
595#ifdef USE_VBO
596       
597        glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbIdentifier );
598        glClientActiveTextureARB( GL_TEXTURE0_ARB );
599        glInterleavedArrays( GL_T2F_V3F, 0, NULL );
600       
601        glClientActiveTextureARB( GL_TEXTURE1_ARB );
602        glInterleavedArrays( GL_T2F_V3F, 0, NULL );
603       
604        glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, ibIdentifier );   
605       
606        glDrawElements( GL_TRIANGLE_STRIP, numIndices, 
607                                        GL_UNSIGNED_SHORT, NULL );     
608#else   
609        glClientActiveTextureARB( GL_TEXTURE0_ARB );
610        glInterleavedArrays( GL_T2F_V3F, 0, vertices );
611       
612        glClientActiveTextureARB( GL_TEXTURE1_ARB );
613        glInterleavedArrays( GL_T2F_V3F, 0, vertices );
614       
615        glDrawElements( GL_TRIANGLE_STRIP, numIndices, 
616                                        GL_UNSIGNED_SHORT, indices );   
617#endif
618       
619
620       
621        if ( owner->debug() )
622                drawBox( );
623               
624        CHECK_GL_ERROR( "2" ); 
625}
626
627short TerrainPage::getIndex( int _x, int _z )
628{
629        unsigned short index = _z*owner->getPageSize()+_x;
630        if ( indexHash[index] == 0xffff ) {
631                //The vertex didn't exists before, lets create it.
632                indexHash[index] = numVertices;
633                getVertex( _x, _z, vertices[numVertices].p );
634                getCoord( _x, _z, vertices[numVertices].t );
635                numVertices++;
636        }
637        return indexHash[index];
638}
639
640void TerrainPage::getCoord( int _x, int _z, TexCoord& _coord ) const 
641{
642        owner->getCoord( _x+xOffset*(owner->getPageSize()-1 ), 
643                                         _z+zOffset*(owner->getPageSize()-1 ), _coord );
644}
645
646void TerrainPage::getVertex( int _x, int _z, Triple& _vertex ) const
647{
648        _vertex.x = position.x+scale.x*_x/
649                ( owner->getPageSize()-1 );
650        _vertex.y = getAltitude( _x, _z );
651        _vertex.z = position.z+scale.z*_z/( owner->getPageSize()-1 );
652}
653
654void TerrainPage::calculateErrors()
655{
656        for ( int i = 0; i < TerrainPage::MAX_LODS; ++i )
657                calculateError( i );
658}
Note: See TracBrowser for help on using the repository browser.