source: trunk/VUT/work/ogre_changes/Plugins/OctreeSceneManager/src/OgreTerrainRenderable.cpp @ 159

Revision 159, 53.8 KB checked in by mattausch, 19 years ago (diff)

added flags for switching on/off transparents for item buffer and vertex programs for depth pass / item buffer

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25/***************************************************************************
26terrainrenderable.cpp  -  description
27-------------------
28begin                : Sat Oct 5 2002
29copyright            : (C) 2002 by Jon Anderson
30email                : janders@users.sf.net
31
32Enhancements 2003 - 2004 (C) The OGRE Team
33
34***************************************************************************/
35
36#include "OgreTerrainRenderable.h"
37#include "OgreSceneNode.h"
38#include "OgreRenderQueue.h"
39#include "OgreRenderOperation.h"
40#include "OgreCamera.h"
41#include "OgreRoot.h"
42#include "OgreTerrainSceneManager.h"
43#include "OgreLogManager.h"
44#include "OgreStringConverter.h"
45#include "OgreViewport.h"
46#include "OgreException.h"
47
48namespace Ogre
49{
50    //-----------------------------------------------------------------------
51    #define MAIN_BINDING 0
52    #define DELTA_BINDING 1
53    //-----------------------------------------------------------------------
54    //-----------------------------------------------------------------------
55    TerrainBufferCache TerrainRenderable::msIndexCache;
56    String TerrainRenderable::mType = "TerrainMipMap";
57    LevelArray TerrainRenderable::mLevelIndex;
58    bool TerrainRenderable::mLevelInit = false;
59    const TerrainOptions* TerrainRenderable::msOptions = 0;
60
61#ifdef GTP_VISIBILITY_MODIFIED_OGRE
62        int TerrainRenderable::msCurrentRenderLevelIndex = 0;
63#endif // GTP_VISIBILITY_MODIFIED_OGRE
64    //-----------------------------------------------------------------------
65    //-----------------------------------------------------------------------
66
67    //-----------------------------------------------------------------------
68    TerrainRenderable::TerrainRenderable(const String& name)
69        : mTerrain(0), mName(name),  mDeltaBuffers(0), mPositionBuffer(0)
70    {
71        mForcedRenderLevel = -1;
72        mLastNextLevel = -1;
73        // Default query flags to top bit so users can exclude it if they wish
74        mQueryFlags = SceneManager::WORLD_GEOMETRY_QUERY_MASK;
75
76        mMinLevelDistSqr = 0;
77
78        mInit = false;
79                MovableObject::mCastShadows = false;
80
81        for ( int i = 0; i < 4; i++ )
82        {
83            mNeighbors[ i ] = 0;
84        }
85
86                _initLevelIndexes();
87
88    }
89    //-----------------------------------------------------------------------
90    TerrainRenderable::~TerrainRenderable()
91    {
92
93        deleteGeometry();
94        _destroyLevelIndexes();
95    }
96    //-----------------------------------------------------------------------
97    void TerrainRenderable::deleteGeometry()
98    {
99        if(mTerrain)
100            delete mTerrain;
101
102        if (mPositionBuffer)
103            delete [] mPositionBuffer;
104
105        if (mDeltaBuffers)
106            delete [] mDeltaBuffers;
107
108        if ( mMinLevelDistSqr != 0 )
109            delete [] mMinLevelDistSqr;
110    }
111    //-----------------------------------------------------------------------
112    void TerrainRenderable::initialise(int startx, int startz, 
113        Real* pageHeightData)
114    {
115        if (!msOptions)
116            msOptions = &(TerrainSceneManager::getOptions());
117
118        if ( msOptions->maxGeoMipMapLevel != 0 )
119        {
120            int i = ( int ) 1 << ( msOptions->maxGeoMipMapLevel - 1 ) ;
121
122            if ( ( i + 1 ) > msOptions->tileSize )
123            {
124                printf( "Invalid maximum mipmap specifed, must be n, such that 2^(n-1)+1 < tileSize \n" );
125                return ;
126            }
127        }
128
129        deleteGeometry();
130
131        //calculate min and max heights;
132        Real min = 256000, max = 0;
133
134        mTerrain = new VertexData;
135        mTerrain->vertexStart = 0;
136        mTerrain->vertexCount = msOptions->tileSize * msOptions->tileSize;
137
138        VertexDeclaration* decl = mTerrain->vertexDeclaration;
139        VertexBufferBinding* bind = mTerrain->vertexBufferBinding;
140
141        // positions
142        size_t offset = 0;
143        decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_POSITION);
144        offset += VertexElement::getTypeSize(VET_FLOAT3);
145        if (TerrainSceneManager::getOptions().lit)
146        {
147            decl->addElement(MAIN_BINDING, offset, VET_FLOAT3, VES_NORMAL);
148            offset += VertexElement::getTypeSize(VET_FLOAT3);
149        }
150        // texture coord sets
151        decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
152        offset += VertexElement::getTypeSize(VET_FLOAT2);
153        decl->addElement(MAIN_BINDING, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
154        offset += VertexElement::getTypeSize(VET_FLOAT2);
155        if (TerrainSceneManager::getOptions().coloured)
156        {
157            decl->addElement(MAIN_BINDING, offset, VET_COLOUR, VES_DIFFUSE);
158            offset += VertexElement::getTypeSize(VET_COLOUR);
159        }
160
161        // Create shared vertex buffer
162        mMainBuffer =
163            HardwareBufferManager::getSingleton().createVertexBuffer(
164            decl->getVertexSize(MAIN_BINDING),
165            mTerrain->vertexCount,
166            HardwareBuffer::HBU_STATIC_WRITE_ONLY);
167        // Create system memory copy with just positions in it, for use in simple reads
168        mPositionBuffer = new float[mTerrain->vertexCount * 3];
169
170        bind->setBinding(MAIN_BINDING, mMainBuffer);
171
172        if (msOptions->lodMorph)
173        {
174            // Create additional element for delta
175            decl->addElement(DELTA_BINDING, 0, VET_FLOAT1, VES_BLEND_WEIGHTS);
176            // NB binding is not set here, it is set when deriving the LOD
177        }
178
179
180        mInit = true;
181
182#ifdef GTP_VISIBILITY_MODIFIED_OGRE
183                for (int i = 0; i < MAX_RENDERLEVEL_INDEX; ++i)
184                {
185                        mRenderLevel[i] = 1;
186                }
187#else
188                mRenderLevel = 1;
189#endif // GTP_VISIBILITY_MODIFIED_OGRE
190
191        mMinLevelDistSqr = new Real[ msOptions->maxGeoMipMapLevel ];
192
193        int endx = startx + msOptions->tileSize;
194
195        int endz = startz + msOptions->tileSize;
196
197        Vector3 left, down, here;
198
199        const VertexElement* poselem = decl->findElementBySemantic(VES_POSITION);
200        const VertexElement* texelem0 = decl->findElementBySemantic(VES_TEXTURE_COORDINATES, 0);
201        const VertexElement* texelem1 = decl->findElementBySemantic(VES_TEXTURE_COORDINATES, 1);
202        float* pSysPos = mPositionBuffer;
203
204        unsigned char* pBase = static_cast<unsigned char*>(mMainBuffer->lock(HardwareBuffer::HBL_DISCARD));
205
206        for ( int j = startz; j < endz; j++ )
207        {
208            for ( int i = startx; i < endx; i++ )
209            {
210                float *pPos, *pTex0, *pTex1;
211                poselem->baseVertexPointerToElement(pBase, &pPos);
212                texelem0->baseVertexPointerToElement(pBase, &pTex0);
213                texelem1->baseVertexPointerToElement(pBase, &pTex1);
214   
215                Real height = pageHeightData[j * msOptions->pageSize + i];
216                height = height * msOptions->scale.y; // scale height
217
218                *pSysPos++ = *pPos++ = ( float ) i * msOptions->scale.x; //x
219                *pSysPos++ = *pPos++ = height; // y
220                *pSysPos++ = *pPos++ = ( float ) j * msOptions->scale.z; //z
221
222                *pTex0++ = ( float ) i / ( float ) msOptions->pageSize;
223                *pTex0++ = ( float ) ( float ) j / ( float ) msOptions->pageSize;
224
225                *pTex1++ = ( ( float ) i / ( float ) msOptions->tileSize ) * msOptions->detailTile;
226                *pTex1++ = ( ( float ) ( float ) j / ( float ) msOptions->tileSize ) * msOptions->detailTile;
227
228                if ( height < min )
229                    min = ( Real ) height;
230
231                if ( height > max )
232                    max = ( Real ) height;
233
234                pBase += mMainBuffer->getVertexSize();
235            }
236        }
237
238        mMainBuffer->unlock();
239
240        mBounds.setExtents(
241            ( Real ) startx * msOptions->scale.x,
242            min,
243            ( Real ) startz * msOptions->scale.z,
244            ( Real ) ( endx - 1 ) * msOptions->scale.x,
245            max,
246            ( Real ) ( endz - 1 ) * msOptions->scale.z );
247
248
249        mCenter = Vector3( ( startx * msOptions->scale.x + (endx - 1) * msOptions->scale.x ) / 2,
250            ( min + max ) / 2,
251            ( startz * msOptions->scale.z + (endz - 1) * msOptions->scale.z ) / 2 );
252
253        // Create delta buffer list if required to morph
254        if (msOptions->lodMorph)
255        {
256            // Create delta buffer for all except the lowest mip
257            mDeltaBuffers = new HardwareVertexBufferSharedPtr[msOptions->maxGeoMipMapLevel - 1];
258        }
259
260        Real C = _calculateCFactor();
261
262        _calculateMinLevelDist2( C );
263        if (msOptions->lit)
264            _calculateNormals();
265
266    }
267    //-----------------------------------------------------------------------
268    void TerrainRenderable::_getNormalAt( float x, float z, Vector3 * result )
269    {
270
271        assert(msOptions->lit && "No normals present");
272
273        Vector3 here, left, down;
274        here.x = x;
275        here.y = getHeightAt( x, z );
276        here.z = z;
277
278        left.x = x - 1;
279        left.y = getHeightAt( x - 1, z );
280        left.z = z;
281
282        down.x = x;
283        down.y = getHeightAt( x, z + 1 );
284        down.z = z + 1;
285
286        left = left - here;
287
288        down = down - here;
289
290        left.normalise();
291        down.normalise();
292
293        *result = left.crossProduct( down );
294        result -> normalise();
295
296        // result->x = - result->x;
297        // result->y = - result->y;
298        // result->z = - result->z;
299    }
300    //-----------------------------------------------------------------------
301    void TerrainRenderable::_calculateNormals()
302    {
303        Vector3 norm;
304
305        assert (msOptions->lit && "No normals present");
306
307        HardwareVertexBufferSharedPtr vbuf =
308            mTerrain->vertexBufferBinding->getBuffer(MAIN_BINDING);
309        const VertexElement* elem = mTerrain->vertexDeclaration->findElementBySemantic(VES_NORMAL);
310        unsigned char* pBase = static_cast<unsigned char*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) );
311        float* pNorm;
312
313        for ( size_t j = 0; j < msOptions->tileSize; j++ )
314        {
315            for ( size_t i = 0; i < msOptions->tileSize; i++ )
316            {
317
318                _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &norm );
319
320                //  printf( "Normal = %5f,%5f,%5f\n", norm.x, norm.y, norm.z );
321                elem->baseVertexPointerToElement(pBase, &pNorm);
322                *pNorm++ = norm.x;
323                *pNorm++ = norm.y;
324                *pNorm++ = norm.z;
325                pBase += vbuf->getVertexSize();
326            }
327
328        }
329        vbuf->unlock();
330    }
331    //-----------------------------------------------------------------------
332    void TerrainRenderable::_notifyCurrentCamera( Camera* cam )
333    {
334
335        if ( mForcedRenderLevel >= 0 )
336        {
337#ifdef GTP_VISIBILITY_MODIFIED_OGRE
338            mRenderLevel[msCurrentRenderLevelIndex] = mForcedRenderLevel;
339#else
340                        mRenderLevel = mForcedRenderLevel;
341#endif // GTP_VISIBILITY_MODIFIED_OGRE
342            return ;
343        }
344
345                Vector3 cpos = cam -> getDerivedPosition();
346        Vector3 diff = mCenter - cpos;
347
348        Real L = diff.squaredLength();
349
350#ifdef GTP_VISIBILITY_MODIFIED_OGRE
351            mRenderLevel[msCurrentRenderLevelIndex] = -1;;
352#else
353                        mRenderLevel = -1;
354#endif // GTP_VISIBILITY_MODIFIED_OGRE
355
356        for ( int i = 0; i < msOptions->maxGeoMipMapLevel; i++ )
357        {
358            if ( mMinLevelDistSqr[ i ] > L )
359            {
360#ifdef GTP_VISIBILITY_MODIFIED_OGRE
361                mRenderLevel[msCurrentRenderLevelIndex] = i - 1;
362#else
363                        mRenderLevel = i - 1;
364#endif // GTP_VISIBILITY_MODIFIED_OGRE
365                break;
366            }
367        }
368
369#ifdef GTP_VISIBILITY_MODIFIED_OGRE
370        if ( getRenderLevel() < 0 )
371            mRenderLevel[msCurrentRenderLevelIndex] = msOptions->maxGeoMipMapLevel - 1;
372#else
373                if ( mRenderLevel < 0 )
374            mRenderLevel = msOptions->maxGeoMipMapLevel - 1;
375#endif // GTP_VISIBILITY_MODIFIED_OGRE
376
377        if (msOptions->lodMorph)
378        {
379            // Get the next LOD level down
380#ifdef GTP_VISIBILITY_MODIFIED_OGRE
381            int nextLevel = mNextLevelDown[getRenderLevel()];
382#else
383                        int nextLevel = mNextLevelDown;
384#endif // GTP_VISIBILITY_MODIFIED_OGRE
385           
386            if (nextLevel == 0)
387            {
388                // No next level, so never morph
389                mLODMorphFactor = 0;
390            }
391            else
392            {
393                // Set the morph such that the morph happens in the last 0.25 of
394                // the distance range
395                Real range = mMinLevelDistSqr[nextLevel] - mMinLevelDistSqr[getRenderLevel()];
396                if (range)
397                {
398                    Real percent = (L - mMinLevelDistSqr[getRenderLevel()]) / range;
399                    // scale result so that msLODMorphStart == 0, 1 == 1, clamp to 0 below that
400                    Real rescale = 1.0f / (1.0f - msOptions->lodMorphStart);
401                    mLODMorphFactor = std::max((percent - msOptions->lodMorphStart) * rescale,
402                                                static_cast<Real>(0.0));
403                }
404                else
405                {
406                    // Identical ranges
407                    mLODMorphFactor = 0.0f;
408                }
409
410                assert(mLODMorphFactor >= 0 && mLODMorphFactor <= 1);
411            }
412
413            // Bind the correct delta buffer if it has changed
414            // nextLevel - 1 since the first entry is for LOD 1 (since LOD 0 never needs it)
415            if (mLastNextLevel != nextLevel)
416            {
417                                if (nextLevel > 0)
418                {
419                                        mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING,
420                        mDeltaBuffers[nextLevel - 1]);
421                }
422                else
423                {                               
424                    // bind dummy (incase bindings checked)
425                    mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING,
426                        mDeltaBuffers[0]);
427                }
428            }
429            mLastNextLevel = nextLevel;
430
431        }
432    }
433    //-----------------------------------------------------------------------
434    void TerrainRenderable::_updateRenderQueue( RenderQueue* queue )
435    {
436        queue->addRenderable( this );
437    }
438    //-----------------------------------------------------------------------
439    void TerrainRenderable::getRenderOperation( RenderOperation& op )
440    {
441        //setup indexes for vertices and uvs...
442
443        assert( mInit && "Uninitialized" );
444
445        op.useIndexes = true;
446        op.operationType = msOptions->useTriStrips ?
447            RenderOperation::OT_TRIANGLE_STRIP : RenderOperation::OT_TRIANGLE_LIST;
448        op.vertexData = mTerrain;
449        op.indexData = getIndexData();
450
451
452    }
453    //-----------------------------------------------------------------------
454    void TerrainRenderable::getWorldTransforms( Matrix4* xform ) const
455    {
456        *xform = mParentNode->_getFullTransform();
457    }
458    //-----------------------------------------------------------------------
459    const Quaternion& TerrainRenderable::getWorldOrientation(void) const
460    {
461        return mParentNode->_getDerivedOrientation();
462    }
463    //-----------------------------------------------------------------------
464    const Vector3& TerrainRenderable::getWorldPosition(void) const
465    {
466        return mParentNode->_getDerivedPosition();
467    }
468    //-----------------------------------------------------------------------
469    bool TerrainRenderable::_checkSize( int n )
470    {
471        for ( int i = 0; i < 10; i++ )
472        {
473            if ( ( ( 1 << i ) + 1 ) == n )
474                return true;
475        }
476
477        return false;
478    }
479    //-----------------------------------------------------------------------
480    void TerrainRenderable::_calculateMinLevelDist2( Real C )
481    {
482        //level 0 has no delta.
483        mMinLevelDistSqr[ 0 ] = 0;
484
485        int i, j;
486
487        for ( int level = 1; level < msOptions->maxGeoMipMapLevel; level++ )
488        {
489            mMinLevelDistSqr[ level ] = 0;
490
491            int step = 1 << level;
492            // The step of the next higher LOD
493            int higherstep = step >> 1;
494
495            float* pDeltas = 0;
496            if (msOptions->lodMorph)
497            {
498                // Create a set of delta values (store at index - 1 since 0 has none)
499                mDeltaBuffers[level - 1]  = createDeltaBuffer();
500                // Lock, but don't discard (we want the pre-initialised zeros)
501                pDeltas = static_cast<float*>(
502                    mDeltaBuffers[level - 1]->lock(HardwareBuffer::HBL_NORMAL));
503            }
504
505            for ( j = 0; j < msOptions->tileSize - step; j += step )
506            {
507                for ( i = 0; i < msOptions->tileSize - step; i += step )
508                {
509                    /* Form planes relating to the lower detail tris to be produced
510                    For tri lists and even tri strip rows, they are this shape:
511                    x---x
512                    | / |
513                    x---x
514                    For odd tri strip rows, they are this shape:
515                    x---x
516                    | \ |
517                    x---x
518                    */
519
520                    Vector3 v1(_vertex( i, j, 0 ), _vertex( i, j, 1 ), _vertex( i, j, 2 ));
521                    Vector3 v2(_vertex( i + step, j, 0 ), _vertex( i + step, j, 1 ), _vertex( i + step, j, 2 ));
522                    Vector3 v3(_vertex( i, j + step, 0 ), _vertex( i, j + step, 1 ), _vertex( i, j + step, 2 ));
523                    Vector3 v4(_vertex( i + step, j + step, 0 ), _vertex( i + step, j + step, 1 ), _vertex( i + step, j + step, 2 ));
524
525                    Plane t1, t2;
526                    bool backwardTri = false;
527                    if (!msOptions->useTriStrips || j % 2 == 0)
528                    {
529                        t1.redefine(v1, v3, v2);
530                        t2.redefine(v2, v3, v4);
531                    }
532                    else
533                    {
534                        t1.redefine(v1, v3, v4);
535                        t2.redefine(v1, v4, v2);
536                        backwardTri = true;
537                    }
538
539                    // include the bottommost row of vertices if this is the last row
540                    int zubound = (j == (msOptions->tileSize - step)? step : step - 1);
541                    for ( int z = 0; z <= zubound; z++ )
542                    {
543                        // include the rightmost col of vertices if this is the last col
544                        int xubound = (i == (msOptions->tileSize - step)? step : step - 1);
545                        for ( int x = 0; x <= xubound; x++ )
546                        {
547                            int fulldetailx = i + x;
548                            int fulldetailz = j + z;
549                            if ( fulldetailx % step == 0 &&
550                                fulldetailz % step == 0 )
551                            {
552                                // Skip, this one is a vertex at this level
553                                continue;
554                            }
555
556                            Real zpct = (Real)z / (Real)step;
557                            Real xpct = (Real)x / (Real)step;
558
559                            //interpolated height
560                            Vector3 actualPos(
561                                _vertex( fulldetailx, fulldetailz, 0 ),
562                                _vertex( fulldetailx, fulldetailz, 1 ),
563                                _vertex( fulldetailx, fulldetailz, 2 ));
564                            Real interp_h;
565                            // Determine which tri we're on
566                            if ((xpct + zpct <= 1.0f && !backwardTri) ||
567                                (xpct + (1-zpct) <= 1.0f && backwardTri))
568                            {
569                                // Solve for x/z
570                                interp_h =
571                                    (-(t1.normal.x * actualPos.x)
572                                    - t1.normal.z * actualPos.z
573                                    - t1.d) / t1.normal.y;
574                            }
575                            else
576                            {
577                                // Second tri
578                                interp_h =
579                                    (-(t2.normal.x * actualPos.x)
580                                    - t2.normal.z * actualPos.z
581                                    - t2.d) / t2.normal.y;
582                            }
583
584                            Real actual_h = _vertex( fulldetailx, fulldetailz, 1 );
585                            Real delta = fabs( interp_h - actual_h );
586
587                            Real D2 = delta * delta * C * C;
588
589                            if ( mMinLevelDistSqr[ level ] < D2 )
590                                mMinLevelDistSqr[ level ] = D2;
591
592                            // Should be save height difference?
593                            // Don't morph along edges
594                            if (msOptions->lodMorph &&
595                                fulldetailx != 0  && fulldetailx != (msOptions->tileSize - 1) &&
596                                fulldetailz != 0  && fulldetailz != (msOptions->tileSize - 1) )
597                            {
598                                // Save height difference
599                                pDeltas[fulldetailx + (fulldetailz * msOptions->tileSize)] =
600                                    interp_h - actual_h;
601                            }
602
603                        }
604
605                    }
606                }
607            }
608
609            // Unlock morph deltas if required
610            if (msOptions->lodMorph)
611            {
612                mDeltaBuffers[level - 1]->unlock();
613            }
614        }
615
616
617
618        // Post validate the whole set
619        for ( i = 1; i < msOptions->maxGeoMipMapLevel; i++ )
620        {
621
622            // Make sure no LOD transition within the tile
623            // This is especially a problem when using large tiles with flat areas
624            /* Hmm, this can look bad on some areas, disable for now
625            Vector3 delta(_vertex(0,0,0), mCenter.y, _vertex(0,0,2));
626            delta = delta - mCenter;
627            Real minDist = delta.squaredLength();
628            mMinLevelDistSqr[ i ] = std::max(mMinLevelDistSqr[ i ], minDist);
629            */
630
631            //make sure the levels are increasing...
632            if ( mMinLevelDistSqr[ i ] < mMinLevelDistSqr[ i - 1 ] )
633            {
634                mMinLevelDistSqr[ i ] = mMinLevelDistSqr[ i - 1 ];
635            }
636        }
637
638        // Now reverse traverse the list setting the 'next level down'
639        Real lastDist = -1;
640        int lastIndex = 0;
641        for (i = msOptions->maxGeoMipMapLevel - 1; i >= 0; --i)
642        {
643            if (i == msOptions->maxGeoMipMapLevel - 1)
644            {
645                // Last one is always 0
646                lastIndex = i;
647                lastDist = mMinLevelDistSqr[i];
648                mNextLevelDown[i] = 0;
649            }
650            else
651            {
652                mNextLevelDown[i] = lastIndex;
653                if (mMinLevelDistSqr[i] != lastDist)
654                {
655                    lastIndex = i;
656                    lastDist = mMinLevelDistSqr[i];
657                }
658            }
659
660        }
661
662
663    }
664    //-----------------------------------------------------------------------
665    void TerrainRenderable::_initLevelIndexes()
666    {
667        if ( mLevelInit )
668            return ;
669
670            if ( mLevelIndex.size() == 0 )
671        {
672            for ( int i = 0; i < 16; i++ )
673            {
674                                mLevelIndex.push_back( new IndexMap() );
675            }
676
677        }
678       
679        mLevelInit = true;
680    }
681    //-----------------------------------------------------------------------
682    void TerrainRenderable::_destroyLevelIndexes()
683    {
684        if ( mLevelInit )
685        {
686            for ( int i = 0; i < 16; i++ )
687            {
688                delete mLevelIndex[i];
689            }
690            mLevelIndex.clear();
691            mLevelInit = false;
692        }
693    }
694    //-----------------------------------------------------------------------
695    void TerrainRenderable::_adjustRenderLevel( int i )
696    {
697#ifdef GTP_VISIBILITY_MODIFIED_OGRE
698        mRenderLevel[msCurrentRenderLevelIndex] = i;
699#else
700                mRenderLevel = i;
701#endif // GTP_VISIBILITY_MODIFIED_OGRE
702    }
703    //-----------------------------------------------------------------------
704    Real TerrainRenderable::_calculateCFactor()
705    {
706        Real A, T;
707
708        const TerrainOptions& opts = TerrainSceneManager::getOptions();
709        if (!opts.primaryCamera)
710        {
711            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
712                "You have not created a camera yet!",
713                "TerrainRenderable::_calculateCFactor");
714        }
715
716        //A = 1 / Math::Tan(Math::AngleUnitsToRadians(opts.primaryCamera->getFOVy()));
717        // Turn off detail compression at higher FOVs
718        A = 1.0f;
719
720        int vertRes = opts.primaryCamera->getViewport()->getActualHeight();
721
722        T = 2 * ( Real ) opts.maxPixelError / ( Real ) vertRes;
723
724        return A / T;
725    }
726    //-----------------------------------------------------------------------
727    float TerrainRenderable::getHeightAt( float x, float z )
728    {
729        Vector3 start;
730        Vector3 end;
731
732        start.x = _vertex( 0, 0, 0 );
733        start.y = _vertex( 0, 0, 1 );
734        start.z = _vertex( 0, 0, 2 );
735
736        end.x = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 0 );
737        end.y = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 1 );
738        end.z = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 2 );
739
740        /* Safety catch, if the point asked for is outside
741        * of this tile, it will ask the appropriate tile
742        */
743
744        if ( x < start.x )
745        {
746            if ( mNeighbors[ WEST ] != 0 )
747                return mNeighbors[ WEST ] ->getHeightAt( x, z );
748            else
749                x = start.x;
750        }
751
752        if ( x > end.x )
753        {
754            if ( mNeighbors[ EAST ] != 0 )
755                return mNeighbors[ EAST ] ->getHeightAt( x, z );
756            else
757                x = end.x;
758        }
759
760        if ( z < start.z )
761        {
762            if ( mNeighbors[ NORTH ] != 0 )
763                return mNeighbors[ NORTH ] ->getHeightAt( x, z );
764            else
765                z = start.z;
766        }
767
768        if ( z > end.z )
769        {
770            if ( mNeighbors[ SOUTH ] != 0 )
771                return mNeighbors[ SOUTH ] ->getHeightAt( x, z );
772            else
773                z = end.z;
774        }
775
776
777
778        float x_pct = ( x - start.x ) / ( end.x - start.x );
779        float z_pct = ( z - start.z ) / ( end.z - start.z );
780
781        float x_pt = x_pct * ( float ) ( msOptions->tileSize - 1 );
782        float z_pt = z_pct * ( float ) ( msOptions->tileSize - 1 );
783
784        int x_index = ( int ) x_pt;
785        int z_index = ( int ) z_pt;
786
787        // If we got to the far right / bottom edge, move one back
788        if (x_index == msOptions->tileSize - 1)
789        {
790            --x_index;
791            x_pct = 1.0f;
792        }
793        else
794        {
795            // get remainder
796            x_pct = x_pt - x_index;
797        }
798        if (z_index == msOptions->tileSize - 1)
799        {
800            --z_index;
801            z_pct = 1.0f;
802        }
803        else
804        {
805            z_pct = z_pt - z_index;
806        }
807
808        //bilinear interpolate to find the height.
809
810        float t1 = _vertex( x_index, z_index, 1 );
811        float t2 = _vertex( x_index + 1, z_index, 1 );
812        float b1 = _vertex( x_index, z_index + 1, 1 );
813        float b2 = _vertex( x_index + 1, z_index + 1, 1 );
814
815        float midpoint = (b1 + t2) / 2.0;
816
817        if (x_pct + z_pct <= 1) {
818            b2 = midpoint + (midpoint - t1);
819        } else {
820            t1 = midpoint + (midpoint - b2);
821        }
822
823        float t = ( t1 * ( 1 - x_pct ) ) + ( t2 * ( x_pct ) );
824        float b = ( b1 * ( 1 - x_pct ) ) + ( b2 * ( x_pct ) );
825
826        float h = ( t * ( 1 - z_pct ) ) + ( b * ( z_pct ) );
827
828        return h;
829    }
830    //-----------------------------------------------------------------------
831    bool TerrainRenderable::intersectSegment( const Vector3 & start, const Vector3 & end, Vector3 * result )
832    {
833        Vector3 dir = end - start;
834        Vector3 ray = start;
835
836        //special case...
837        if ( dir.x == 0 && dir.z == 0 )
838        {
839            if ( ray.y <= getHeightAt( ray.x, ray.z ) )
840            {
841                if ( result != 0 )
842                    * result = start;
843
844                return true;
845            }
846        }
847
848        dir.normalise();
849
850        //dir.x *= mScale.x;
851        //dir.y *= mScale.y;
852        //dir.z *= mScale.z;
853
854        const Vector3 * corners = getBoundingBox().getAllCorners();
855
856        //start with the next one...
857        ray += dir;
858
859
860        while ( ! ( ( ray.x < corners[ 0 ].x ) ||
861            ( ray.x > corners[ 4 ].x ) ||
862            ( ray.z < corners[ 0 ].z ) ||
863            ( ray.z > corners[ 4 ].z ) ) )
864        {
865
866
867            float h = getHeightAt( ray.x, ray.z );
868
869            if ( ray.y <= h )
870            {
871                if ( result != 0 )
872                    * result = ray;
873
874                return true;
875            }
876
877            else
878            {
879                ray += dir;
880            }
881
882        }
883
884        if ( ray.x < corners[ 0 ].x && mNeighbors[ WEST ] != 0 )
885            return mNeighbors[ WEST ] ->intersectSegment( ray, end, result );
886        else if ( ray.z < corners[ 0 ].z && mNeighbors[ NORTH ] != 0 )
887            return mNeighbors[ NORTH ] ->intersectSegment( ray, end, result );
888        else if ( ray.x > corners[ 4 ].x && mNeighbors[ EAST ] != 0 )
889            return mNeighbors[ EAST ] ->intersectSegment( ray, end, result );
890        else if ( ray.z > corners[ 4 ].z && mNeighbors[ SOUTH ] != 0 )
891            return mNeighbors[ SOUTH ] ->intersectSegment( ray, end, result );
892        else
893        {
894            if ( result != 0 )
895                * result = Vector3( -1, -1, -1 );
896
897            return false;
898        }
899    }
900    //-----------------------------------------------------------------------
901    void TerrainRenderable::_generateVertexLighting( const Vector3 &sun, ColourValue ambient )
902    {
903
904        Vector3 pt;
905        Vector3 normal;
906        Vector3 light;
907
908        HardwareVertexBufferSharedPtr vbuf =
909            mTerrain->vertexBufferBinding->getBuffer(MAIN_BINDING);
910        const VertexElement* elem = mTerrain->vertexDeclaration->findElementBySemantic(VES_DIFFUSE);
911        //for each point in the terrain, see if it's in the line of sight for the sun.
912        for ( size_t i = 0; i < msOptions->tileSize; i++ )
913        {
914            for ( size_t j = 0; j < msOptions->tileSize; j++ )
915            {
916                //  printf( "Checking %f,%f,%f ", pt.x, pt.y, pt.z );
917                pt.x = _vertex( i, j, 0 );
918                pt.y = _vertex( i, j, 1 );
919                pt.z = _vertex( i, j, 2 );
920
921                light = sun - pt;
922
923                light.normalise();
924
925                if ( ! intersectSegment( pt, sun, 0 ) )
926                {
927                    //
928                    _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &normal );
929
930                    float l = light.dotProduct( normal );
931
932                    ColourValue v;
933                    v.r = ambient.r + l;
934                    v.g = ambient.g + l;
935                    v.b = ambient.b + l;
936
937                    if ( v.r > 1 ) v.r = 1;
938
939                    if ( v.g > 1 ) v.g = 1;
940
941                    if ( v.b > 1 ) v.b = 1;
942
943                    if ( v.r < 0 ) v.r = 0;
944
945                    if ( v.g < 0 ) v.g = 0;
946
947                    if ( v.b < 0 ) v.b = 0;
948
949                    RGBA colour;
950                    Root::getSingleton().convertColourValue( v, &colour );
951                    vbuf->writeData(
952                        (_index( i, j ) * vbuf->getVertexSize()) + elem->getOffset(),
953                        sizeof(RGBA), &colour);
954                }
955
956                else
957                {
958                    RGBA colour;
959                    Root::getSingleton().convertColourValue( ambient, &colour );
960
961                    vbuf->writeData(
962                        (_index( i, j ) * vbuf->getVertexSize()) + elem->getOffset(),
963                        sizeof(RGBA), &colour);
964                }
965
966            }
967
968        }
969
970        printf( "." );
971    }
972    //-----------------------------------------------------------------------
973    Real TerrainRenderable::getSquaredViewDepth(const Camera* cam) const
974    {
975        Vector3 diff = mCenter - cam->getDerivedPosition();
976        // Use squared length to avoid square root
977        return diff.squaredLength();
978    }
979
980    //-----------------------------------------------------------------------
981    const LightList& TerrainRenderable::getLights(void) const
982    {
983        return getParentSceneNode()->findLights(this->getBoundingRadius());
984    }
985    //-----------------------------------------------------------------------
986    IndexData* TerrainRenderable::getIndexData(void)
987    {
988        unsigned int stitchFlags = 0;
989
990        if ( mNeighbors[ EAST ] != 0 && mNeighbors[ EAST ] -> getRenderLevel() > getRenderLevel() )
991        {
992            stitchFlags |= STITCH_EAST;
993            stitchFlags |=
994                (mNeighbors[ EAST ] -> getRenderLevel() - getRenderLevel()) << STITCH_EAST_SHIFT;
995        }
996
997        if ( mNeighbors[ WEST ] != 0 && mNeighbors[ WEST ] -> getRenderLevel() > getRenderLevel() )
998        {
999            stitchFlags |= STITCH_WEST;
1000            stitchFlags |=
1001                (mNeighbors[ WEST ] -> getRenderLevel() - getRenderLevel()) << STITCH_WEST_SHIFT;
1002        }
1003
1004        if ( mNeighbors[ NORTH ] != 0 && mNeighbors[ NORTH ] -> getRenderLevel() > getRenderLevel() )
1005        {
1006            stitchFlags |= STITCH_NORTH;
1007            stitchFlags |=
1008                (mNeighbors[ NORTH ] -> getRenderLevel() - getRenderLevel()) << STITCH_NORTH_SHIFT;
1009        }
1010
1011        if ( mNeighbors[ SOUTH ] != 0 && mNeighbors[ SOUTH ] -> getRenderLevel() > getRenderLevel() )
1012        {
1013            stitchFlags |= STITCH_SOUTH;
1014            stitchFlags |=
1015                (mNeighbors[ SOUTH ] -> getRenderLevel() - getRenderLevel()) << STITCH_SOUTH_SHIFT;
1016        }
1017
1018        // Check preexisting
1019        IndexMap::iterator ii = mLevelIndex[ getRenderLevel() ]->find( stitchFlags );
1020        IndexData* indexData;
1021        if ( ii == mLevelIndex[ getRenderLevel() ]->end())
1022        {
1023            // Create
1024            if (msOptions->useTriStrips)
1025            {
1026                indexData = generateTriStripIndexes(stitchFlags);
1027            }
1028            else
1029            {
1030                indexData = generateTriListIndexes(stitchFlags);
1031            }
1032            mLevelIndex[ getRenderLevel() ]->insert(
1033                IndexMap::value_type(stitchFlags, indexData));
1034        }
1035        else
1036        {
1037            indexData = ii->second;
1038        }
1039
1040
1041        return indexData;
1042
1043
1044    }
1045    //-----------------------------------------------------------------------
1046    IndexData* TerrainRenderable::generateTriStripIndexes(unsigned int stitchFlags)
1047    {
1048        // The step used for the current level
1049        int step = 1 << getRenderLevel();
1050        // The step used for the lower level
1051        int lowstep = 1 << (getRenderLevel() + 1);
1052
1053        int numIndexes = 0;
1054
1055        // Calculate the number of indexes required
1056        // This is the number of 'cells' at this detail level x 2
1057        // plus 3 degenerates to turn corners
1058        int numTrisAcross = (((msOptions->tileSize-1) / step) * 2) + 3;
1059        // Num indexes is number of tris + 2
1060        int new_length = numTrisAcross * ((msOptions->tileSize-1) / step) + 2;
1061        //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
1062
1063        IndexData* indexData = new IndexData;
1064        indexData->indexBuffer =
1065            HardwareBufferManager::getSingleton().createIndexBuffer(
1066            HardwareIndexBuffer::IT_16BIT,
1067            new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
1068
1069        msIndexCache.mCache.push_back( indexData );
1070
1071        unsigned short* pIdx = static_cast<unsigned short*>(
1072            indexData->indexBuffer->lock(0,
1073            indexData->indexBuffer->getSizeInBytes(),
1074            HardwareBuffer::HBL_DISCARD));
1075
1076        // Stripified mesh
1077        for ( int j = 0; j < msOptions->tileSize - 1; j += step )
1078        {
1079            int i;
1080            // Forward strip
1081            // We just do the |/ here, final | done after
1082            for ( i = 0; i < msOptions->tileSize - 1; i += step )
1083            {
1084                int x[4], y[4];
1085                x[0] = x[1] = i;
1086                x[2] = x[3] = i + step;
1087                y[0] = y[2] = j;
1088                y[1] = y[3] = j + step;
1089
1090                if (j == 0  && (stitchFlags & STITCH_NORTH))
1091                {
1092                    // North reduction means rounding x[0] and x[2]
1093                    if (x[0] % lowstep != 0)
1094                    {
1095                        // Since we know we only drop down one level of LOD,
1096                        // removing 1 step of higher LOD should return to lower
1097                        x[0] -= step;
1098                    }
1099                    if (x[2] % lowstep != 0)
1100                    {
1101                        x[2] -= step;
1102                    }
1103                }
1104
1105                // Never get a south tiling on a forward strip (always finish on
1106                // a backward strip)
1107
1108                if (i == 0  && (stitchFlags & STITCH_WEST))
1109                {
1110                    // West reduction means rounding y[0] / y[1]
1111                    if (y[0] % lowstep != 0)
1112                    {
1113                        y[0] -= step;
1114                    }
1115                    if (y[1] % lowstep != 0)
1116                    {
1117                        y[1] -= step;
1118                    }
1119                }
1120                if (i == (msOptions->tileSize - 1 - step) && (stitchFlags & STITCH_EAST))
1121                {
1122                    // East tiling means rounding y[2] & y[3]
1123                    if (y[2] % lowstep != 0)
1124                    {
1125                        y[2] -= step;
1126                    }
1127                    if (y[3] % lowstep != 0)
1128                    {
1129                        y[3] -= step;
1130                    }
1131                }
1132
1133                //triangles
1134                if (i == 0)
1135                {
1136                    // Starter
1137                    *pIdx++ = _index( x[0], y[0] ); numIndexes++;
1138                }
1139                *pIdx++ = _index( x[1], y[1] ); numIndexes++;
1140                *pIdx++ = _index( x[2], y[2] ); numIndexes++;
1141
1142                if (i == msOptions->tileSize - 1 - step)
1143                {
1144                    // Emit extra index to finish row
1145                    *pIdx++ = _index( x[3], y[3] ); numIndexes++;
1146                    if (j < msOptions->tileSize - 1 - step)
1147                    {
1148                        // Emit this index twice more (this is to turn around without
1149                        // artefacts)
1150                        // ** Hmm, looks like we can drop this and it's unnoticeable
1151                        //*pIdx++ = _index( x[3], y[3] ); numIndexes++;
1152                        //*pIdx++ = _index( x[3], y[3] ); numIndexes++;
1153                    }
1154                }
1155
1156            }
1157            // Increment row
1158            j += step;
1159            // Backward strip
1160            for ( i = msOptions->tileSize - 1; i > 0 ; i -= step )
1161            {
1162                int x[4], y[4];
1163                x[0] = x[1] = i;
1164                x[2] = x[3] = i - step;
1165                y[0] = y[2] = j;
1166                y[1] = y[3] = j + step;
1167
1168                // Never get a north tiling on a backward strip (always
1169                // start on a forward strip)
1170                if (j == (msOptions->tileSize - 1 - step) && (stitchFlags & STITCH_SOUTH))
1171                {
1172                    // South reduction means rounding x[1] / x[3]
1173                    if (x[1] % lowstep != 0)
1174                    {
1175                        x[1] -= step;
1176                    }
1177                    if (x[3] % lowstep != 0)
1178                    {
1179                        x[3] -= step;
1180                    }
1181                }
1182
1183                if (i == step  && (stitchFlags & STITCH_WEST))
1184                {
1185                    // West tiling on backward strip is rounding of y[2] / y[3]
1186                    if (y[2] % lowstep != 0)
1187                    {
1188                        y[2] -= step;
1189                    }
1190                    if (y[3] % lowstep != 0)
1191                    {
1192                        y[3] -= step;
1193                    }
1194                }
1195                if (i == msOptions->tileSize - 1 && (stitchFlags & STITCH_EAST))
1196                {
1197                    // East tiling means rounding y[0] and y[1] on backward strip
1198                    if (y[0] % lowstep != 0)
1199                    {
1200                        y[0] -= step;
1201                    }
1202                    if (y[1] % lowstep != 0)
1203                    {
1204                        y[1] -= step;
1205                    }
1206                }
1207
1208                //triangles
1209                if (i == msOptions->tileSize)
1210                {
1211                    // Starter
1212                    *pIdx++ = _index( x[0], y[0] ); numIndexes++;
1213                }
1214                *pIdx++ = _index( x[1], y[1] ); numIndexes++;
1215                *pIdx++ = _index( x[2], y[2] ); numIndexes++;
1216
1217                if (i == step)
1218                {
1219                    // Emit extra index to finish row
1220                    *pIdx++ = _index( x[3], y[3] ); numIndexes++;
1221                    if (j < msOptions->tileSize - 1 - step)
1222                    {
1223                        // Emit this index once more (this is to turn around)
1224                        *pIdx++ = _index( x[3], y[3] ); numIndexes++;
1225                    }
1226                }
1227            }
1228        }
1229
1230
1231        indexData->indexBuffer->unlock();
1232        indexData->indexCount = numIndexes;
1233        indexData->indexStart = 0;
1234
1235        return indexData;
1236
1237    }
1238    //-----------------------------------------------------------------------
1239    IndexData* TerrainRenderable::generateTriListIndexes(unsigned int stitchFlags)
1240    {
1241
1242        int numIndexes = 0;
1243        int step = 1 << getRenderLevel();
1244
1245        IndexData* indexData = 0;
1246
1247        int north = stitchFlags & STITCH_NORTH ? step : 0;
1248        int south = stitchFlags & STITCH_SOUTH ? step : 0;
1249        int east = stitchFlags & STITCH_EAST ? step : 0;
1250        int west = stitchFlags & STITCH_WEST ? step : 0;
1251
1252        int new_length = ( msOptions->tileSize / step ) * ( msOptions->tileSize / step ) * 2 * 2 * 2 ;
1253        //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
1254
1255        indexData = new IndexData;
1256        indexData->indexBuffer =
1257            HardwareBufferManager::getSingleton().createIndexBuffer(
1258            HardwareIndexBuffer::IT_16BIT,
1259            new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
1260
1261        msIndexCache.mCache.push_back( indexData );
1262
1263        unsigned short* pIdx = static_cast<unsigned short*>(
1264            indexData->indexBuffer->lock(0,
1265            indexData->indexBuffer->getSizeInBytes(),
1266            HardwareBuffer::HBL_DISCARD));
1267
1268        // Do the core vertices, minus stitches
1269        for ( int j = north; j < msOptions->tileSize - 1 - south; j += step )
1270        {
1271            for ( int i = west; i < msOptions->tileSize - 1 - east; i += step )
1272            {
1273                //triangles
1274                *pIdx++ = _index( i, j ); numIndexes++;
1275                *pIdx++ = _index( i, j + step ); numIndexes++;
1276                *pIdx++ = _index( i + step, j ); numIndexes++;
1277
1278                *pIdx++ = _index( i, j + step ); numIndexes++;
1279                *pIdx++ = _index( i + step, j + step ); numIndexes++;
1280                *pIdx++ = _index( i + step, j ); numIndexes++;
1281            }
1282        }
1283
1284        // North stitching
1285        if ( north > 0 )
1286        {
1287            numIndexes += stitchEdge(NORTH, getRenderLevel(), mNeighbors[NORTH]->getRenderLevel(),
1288                west > 0, east > 0, &pIdx);
1289        }
1290        // East stitching
1291        if ( east > 0 )
1292        {
1293            numIndexes += stitchEdge(EAST, getRenderLevel(), mNeighbors[EAST]->getRenderLevel(),
1294                north > 0, south > 0, &pIdx);
1295        }
1296        // South stitching
1297        if ( south > 0 )
1298        {
1299            numIndexes += stitchEdge(SOUTH, getRenderLevel(), mNeighbors[SOUTH]->getRenderLevel(),
1300                east > 0, west > 0, &pIdx);
1301        }
1302        // West stitching
1303        if ( west > 0 )
1304        {
1305            numIndexes += stitchEdge(WEST, getRenderLevel(), mNeighbors[WEST]->getRenderLevel(),
1306                south > 0, north > 0, &pIdx);
1307        }
1308
1309
1310        indexData->indexBuffer->unlock();
1311        indexData->indexCount = numIndexes;
1312        indexData->indexStart = 0;
1313
1314        return indexData;
1315    }
1316    //-----------------------------------------------------------------------
1317    HardwareVertexBufferSharedPtr TerrainRenderable::createDeltaBuffer(void)
1318    {
1319        // Delta buffer is a 1D float buffer of height offsets
1320        HardwareVertexBufferSharedPtr buf =
1321            HardwareBufferManager::getSingleton().createVertexBuffer(
1322            VertexElement::getTypeSize(VET_FLOAT1),
1323            msOptions->tileSize * msOptions->tileSize,
1324            HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1325        // Fill the buffer with zeros, we will only fill in delta
1326        void* pVoid = buf->lock(HardwareBuffer::HBL_DISCARD);
1327        memset(pVoid, 0, msOptions->tileSize * msOptions->tileSize * sizeof(float));
1328        buf->unlock();
1329
1330        return buf;
1331
1332    }
1333    //-----------------------------------------------------------------------
1334    void TerrainRenderable::_updateCustomGpuParameter(
1335        const GpuProgramParameters::AutoConstantEntry& constantEntry,
1336        GpuProgramParameters* params) const
1337    {
1338        if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
1339        {
1340            // Update morph LOD factor
1341            params->setConstant(constantEntry.index, mLODMorphFactor);
1342        }
1343        else
1344        {
1345            Renderable::_updateCustomGpuParameter(constantEntry, params);
1346        }
1347
1348    }
1349    //-----------------------------------------------------------------------
1350    int TerrainRenderable::stitchEdge(Neighbor neighbor, int hiLOD, int loLOD,
1351        bool omitFirstTri, bool omitLastTri, unsigned short** ppIdx)
1352    {
1353        assert(loLOD > hiLOD);
1354        /*
1355        Now do the stitching; we can stitch from any level to any level.
1356        The stitch pattern is like this for each pair of vertices in the lower LOD
1357        (excuse the poor ascii art):
1358
1359        lower LOD
1360        *-----------*
1361        |\  \ 3 /  /|
1362        |1\2 \ / 4/5|
1363        *--*--*--*--*
1364        higher LOD
1365
1366        The algorithm is, for each pair of lower LOD vertices:
1367        1. Iterate over the higher LOD vertices, generating tris connected to the
1368        first lower LOD vertex, up to and including 1/2 the span of the lower LOD
1369        over the higher LOD (tris 1-2). Skip the first tri if it is on the edge
1370        of the tile and that edge is to be stitched itself.
1371        2. Generate a single tri for the middle using the 2 lower LOD vertices and
1372        the middle vertex of the higher LOD (tri 3).
1373        3. Iterate over the higher LOD vertices from 1/2 the span of the lower LOD
1374        to the end, generating tris connected to the second lower LOD vertex
1375        (tris 4-5). Skip the last tri if it is on the edge of a tile and that
1376        edge is to be stitched itself.
1377
1378        The same algorithm works for all edges of the patch; stitching is done
1379        clockwise so that the origin and steps used change, but the general
1380        approach does not.
1381        */
1382
1383        // Get pointer to be updated
1384        unsigned short* pIdx = *ppIdx;
1385
1386        // Work out the steps ie how to increment indexes
1387        // Step from one vertex to another in the high detail version
1388        int step = 1 << hiLOD;
1389        // Step from one vertex to another in the low detail version
1390        int superstep = 1 << loLOD;
1391        // Step half way between low detail steps
1392        int halfsuperstep = superstep >> 1;
1393
1394        // Work out the starting points and sign of increments
1395        // We always work the strip clockwise
1396        int startx, starty, endx, rowstep;
1397        bool horizontal;
1398        switch(neighbor)
1399        {
1400        case NORTH:
1401            startx = starty = 0;
1402            endx = msOptions->tileSize - 1;
1403            rowstep = step;
1404            horizontal = true;
1405            break;
1406        case SOUTH:
1407            // invert x AND y direction, helps to keep same winding
1408            startx = starty = msOptions->tileSize - 1;
1409            endx = 0;
1410            rowstep = -step;
1411            step = -step;
1412            superstep = -superstep;
1413            halfsuperstep = -halfsuperstep;
1414            horizontal = true;
1415            break;
1416        case EAST:
1417            startx = 0;
1418            endx = msOptions->tileSize - 1;
1419            starty = msOptions->tileSize - 1;
1420            rowstep = -step;
1421            horizontal = false;
1422            break;
1423        case WEST:
1424            startx = msOptions->tileSize - 1;
1425            endx = 0;
1426            starty = 0;
1427            rowstep = step;
1428            step = -step;
1429            superstep = -superstep;
1430            halfsuperstep = -halfsuperstep;
1431            horizontal = false;
1432            break;
1433        };
1434
1435        int numIndexes = 0;
1436
1437        for ( int j = startx; j != endx; j += superstep )
1438        {
1439            int k;
1440            for (k = 0; k != halfsuperstep; k += step)
1441            {
1442                int jk = j + k;
1443                //skip the first bit of the corner?
1444                if ( j != startx || k != 0 || !omitFirstTri )
1445                {
1446                    if (horizontal)
1447                    {
1448                        *pIdx++ = _index( j , starty ); numIndexes++;
1449                        *pIdx++ = _index( jk, starty + rowstep ); numIndexes++;
1450                        *pIdx++ = _index( jk + step, starty + rowstep ); numIndexes++;
1451                    }
1452                    else
1453                    {
1454                        *pIdx++ = _index( starty, j ); numIndexes++;
1455                        *pIdx++ = _index( starty + rowstep, jk ); numIndexes++;
1456                        *pIdx++ = _index( starty + rowstep, jk + step); numIndexes++;
1457                    }
1458                }
1459            }
1460
1461            // Middle tri
1462            if (horizontal)
1463            {
1464                *pIdx++ = _index( j, starty ); numIndexes++;
1465                *pIdx++ = _index( j + halfsuperstep, starty + rowstep); numIndexes++;
1466                *pIdx++ = _index( j + superstep, starty ); numIndexes++;
1467            }
1468            else
1469            {
1470                *pIdx++ = _index( starty, j ); numIndexes++;
1471                *pIdx++ = _index( starty + rowstep, j + halfsuperstep ); numIndexes++;
1472                *pIdx++ = _index( starty, j + superstep ); numIndexes++;
1473            }
1474
1475            for (k = halfsuperstep; k != superstep; k += step)
1476            {
1477                int jk = j + k;
1478                if ( j != endx - superstep || k != superstep - step || !omitLastTri )
1479                {
1480                    if (horizontal)
1481                    {
1482                        *pIdx++ = _index( j + superstep, starty ); numIndexes++;
1483                        *pIdx++ = _index( jk, starty + rowstep ); numIndexes++;
1484                        *pIdx++ = _index( jk + step, starty + rowstep ); numIndexes++;
1485                    }
1486                    else
1487                    {
1488                        *pIdx++ = _index( starty, j + superstep ); numIndexes++;
1489                        *pIdx++ = _index( starty + rowstep, jk ); numIndexes++;
1490                        *pIdx++ = _index( starty + rowstep, jk + step ); numIndexes++;
1491                    }
1492                }
1493            }
1494        }
1495
1496        *ppIdx = pIdx;
1497
1498        return numIndexes;
1499
1500    }
1501#ifdef GTP_VISIBILITY_MODIFIED_OGRE
1502        //-----------------------------------------------------------------------
1503        void TerrainRenderable::ResetRenderLevelIndex()
1504        {
1505                msCurrentRenderLevelIndex = 0;
1506        }
1507        //-----------------------------------------------------------------------
1508        void TerrainRenderable::NextRenderLevelIndex()
1509        {
1510                if ((++ msCurrentRenderLevelIndex) > MAX_RENDERLEVEL_INDEX)
1511                        msCurrentRenderLevelIndex = 0;
1512        }
1513#endif // GTP_VISIBILITY_MODIFIED_OGRE
1514
1515} //namespace
Note: See TracBrowser for help on using the repository browser.