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

Revision 193, 54.1 KB checked in by mattausch, 19 years ago (diff)

changed to ogre 103
added readme

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        : Renderable(), 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 - 1 );
223                *pTex0++ = ( float ) j / ( float ) ( msOptions->pageSize - 1 );
224
225                *pTex1++ = ( ( float ) i / ( float ) ( msOptions->tileSize - 1 ) ) * msOptions->detailTile;
226                *pTex1++ = ( ( float ) j / ( float ) ( msOptions->tileSize - 1 ) ) * 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
264    }
265    //-----------------------------------------------------------------------
266    void TerrainRenderable::_getNormalAt( float x, float z, Vector3 * result )
267    {
268
269        assert(msOptions->lit && "No normals present");
270
271        Vector3 here, left, down;
272        here.x = x;
273        here.y = getHeightAt( x, z );
274        here.z = z;
275
276        left.x = x - 1;
277        left.y = getHeightAt( x - 1, z );
278        left.z = z;
279
280        down.x = x;
281        down.y = getHeightAt( x, z + 1 );
282        down.z = z + 1;
283
284        left = left - here;
285
286        down = down - here;
287
288        left.normalise();
289        down.normalise();
290
291        *result = left.crossProduct( down );
292        result -> normalise();
293
294        // result->x = - result->x;
295        // result->y = - result->y;
296        // result->z = - result->z;
297    }
298    //-----------------------------------------------------------------------
299    void TerrainRenderable::_calculateNormals()
300    {
301
302        Vector3 norm;
303
304        assert (msOptions->lit && "No normals present");
305
306        HardwareVertexBufferSharedPtr vbuf =
307            mTerrain->vertexBufferBinding->getBuffer(MAIN_BINDING);
308        const VertexElement* elem = mTerrain->vertexDeclaration->findElementBySemantic(VES_NORMAL);
309        unsigned char* pBase = static_cast<unsigned char*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) );
310        float* pNorm;
311
312        for ( size_t j = 0; j < msOptions->tileSize; j++ )
313        {
314            for ( size_t i = 0; i < msOptions->tileSize; i++ )
315            {
316
317                _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &norm );
318
319                //  printf( "Normal = %5f,%5f,%5f\n", norm.x, norm.y, norm.z );
320                elem->baseVertexPointerToElement(pBase, &pNorm);
321                *pNorm++ = norm.x;
322                *pNorm++ = norm.y;
323                *pNorm++ = norm.z;
324                pBase += vbuf->getVertexSize();
325            }
326
327        }
328        vbuf->unlock();
329    }
330    //-----------------------------------------------------------------------
331    void TerrainRenderable::_notifyCurrentCamera( Camera* cam )
332    {
333
334        if ( mForcedRenderLevel >= 0 )
335        {
336#ifdef GTP_VISIBILITY_MODIFIED_OGRE
337            mRenderLevel[msCurrentRenderLevelIndex] = mForcedRenderLevel;
338#else
339                        mRenderLevel = mForcedRenderLevel;
340#endif // GTP_VISIBILITY_MODIFIED_OGRE
341            return ;
342        }
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[mRenderLevel];
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 #ifdef GTP_VISIBILITY_MODIFIED_OGRE
396Real range = mMinLevelDistSqr[nextLevel] - mMinLevelDistSqr[getRenderLevel()];
397#else
398                Real range = mMinLevelDistSqr[nextLevel] - mMinLevelDistSqr[mRenderLevel];
399#endif // GTP_VISIBILITY_MODIFIED_OGRE               
400                if (range)
401                {
402#ifdef GTP_VISIBILITY_MODIFIED_OGRE
403Real percent = (L - mMinLevelDistSqr[getRenderLevel()]) / range;
404#else
405                    Real percent = (L - mMinLevelDistSqr[mRenderLevel]) / range;
406#endif // GTP_VISIBILITY_MODIFIED_OGRE
407                    // scale result so that msLODMorphStart == 0, 1 == 1, clamp to 0 below that
408                    Real rescale = 1.0f / (1.0f - msOptions->lodMorphStart);
409                    mLODMorphFactor = std::max((percent - msOptions->lodMorphStart) * rescale,
410                                                static_cast<Real>(0.0));
411                }
412                else
413                {
414                    // Identical ranges
415                    mLODMorphFactor = 0.0f;
416                }
417
418                assert(mLODMorphFactor >= 0 && mLODMorphFactor <= 1);
419            }
420
421            // Bind the correct delta buffer if it has changed
422            // nextLevel - 1 since the first entry is for LOD 1 (since LOD 0 never needs it)
423            if (mLastNextLevel != nextLevel)
424            {
425                                if (nextLevel > 0)
426                {
427                                        mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING,
428                        mDeltaBuffers[nextLevel - 1]);
429                }
430                else
431                {                               
432                    // bind dummy (incase bindings checked)
433                    mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING,
434                        mDeltaBuffers[0]);
435                }
436            }
437            mLastNextLevel = nextLevel;
438
439        }
440
441    }
442    //-----------------------------------------------------------------------
443    void TerrainRenderable::_updateRenderQueue( RenderQueue* queue )
444    {
445        queue->addRenderable( this );
446    }
447    //-----------------------------------------------------------------------
448    void TerrainRenderable::getRenderOperation( RenderOperation& op )
449    {
450        //setup indexes for vertices and uvs...
451
452        assert( mInit && "Uninitialized" );
453
454        op.useIndexes = true;
455        op.operationType = msOptions->useTriStrips ?
456            RenderOperation::OT_TRIANGLE_STRIP : RenderOperation::OT_TRIANGLE_LIST;
457        op.vertexData = mTerrain;
458        op.indexData = getIndexData();
459
460
461    }
462    //-----------------------------------------------------------------------
463    void TerrainRenderable::getWorldTransforms( Matrix4* xform ) const
464    {
465        *xform = mParentNode->_getFullTransform();
466    }
467    //-----------------------------------------------------------------------
468    const Quaternion& TerrainRenderable::getWorldOrientation(void) const
469    {
470        return mParentNode->_getDerivedOrientation();
471    }
472    //-----------------------------------------------------------------------
473    const Vector3& TerrainRenderable::getWorldPosition(void) const
474    {
475        return mParentNode->_getDerivedPosition();
476    }
477    //-----------------------------------------------------------------------
478    bool TerrainRenderable::_checkSize( int n )
479    {
480        for ( int i = 0; i < 10; i++ )
481        {
482            if ( ( ( 1 << i ) + 1 ) == n )
483                return true;
484        }
485
486        return false;
487    }
488    //-----------------------------------------------------------------------
489    void TerrainRenderable::_calculateMinLevelDist2( Real C )
490    {
491        //level 0 has no delta.
492        mMinLevelDistSqr[ 0 ] = 0;
493
494        int i, j;
495
496        for ( int level = 1; level < msOptions->maxGeoMipMapLevel; level++ )
497        {
498            mMinLevelDistSqr[ level ] = 0;
499
500            int step = 1 << level;
501            // The step of the next higher LOD
502            int higherstep = step >> 1;
503
504            float* pDeltas = 0;
505            if (msOptions->lodMorph)
506            {
507                // Create a set of delta values (store at index - 1 since 0 has none)
508                mDeltaBuffers[level - 1]  = createDeltaBuffer();
509                // Lock, but don't discard (we want the pre-initialised zeros)
510                pDeltas = static_cast<float*>(
511                    mDeltaBuffers[level - 1]->lock(HardwareBuffer::HBL_NORMAL));
512            }
513
514            for ( j = 0; j < msOptions->tileSize - step; j += step )
515            {
516                for ( i = 0; i < msOptions->tileSize - step; i += step )
517                {
518                    /* Form planes relating to the lower detail tris to be produced
519                    For tri lists and even tri strip rows, they are this shape:
520                    x---x
521                    | / |
522                    x---x
523                    For odd tri strip rows, they are this shape:
524                    x---x
525                    | \ |
526                    x---x
527                    */
528
529                    Vector3 v1(_vertex( i, j, 0 ), _vertex( i, j, 1 ), _vertex( i, j, 2 ));
530                    Vector3 v2(_vertex( i + step, j, 0 ), _vertex( i + step, j, 1 ), _vertex( i + step, j, 2 ));
531                    Vector3 v3(_vertex( i, j + step, 0 ), _vertex( i, j + step, 1 ), _vertex( i, j + step, 2 ));
532                    Vector3 v4(_vertex( i + step, j + step, 0 ), _vertex( i + step, j + step, 1 ), _vertex( i + step, j + step, 2 ));
533
534                    Plane t1, t2;
535                    bool backwardTri = false;
536                    if (!msOptions->useTriStrips || j % 2 == 0)
537                    {
538                        t1.redefine(v1, v3, v2);
539                        t2.redefine(v2, v3, v4);
540                    }
541                    else
542                    {
543                        t1.redefine(v1, v3, v4);
544                        t2.redefine(v1, v4, v2);
545                        backwardTri = true;
546                    }
547
548                    // include the bottommost row of vertices if this is the last row
549                    int zubound = (j == (msOptions->tileSize - step)? step : step - 1);
550                    for ( int z = 0; z <= zubound; z++ )
551                    {
552                        // include the rightmost col of vertices if this is the last col
553                        int xubound = (i == (msOptions->tileSize - step)? step : step - 1);
554                        for ( int x = 0; x <= xubound; x++ )
555                        {
556                            int fulldetailx = i + x;
557                            int fulldetailz = j + z;
558                            if ( fulldetailx % step == 0 &&
559                                fulldetailz % step == 0 )
560                            {
561                                // Skip, this one is a vertex at this level
562                                continue;
563                            }
564
565                            Real zpct = (Real)z / (Real)step;
566                            Real xpct = (Real)x / (Real)step;
567
568                            //interpolated height
569                            Vector3 actualPos(
570                                _vertex( fulldetailx, fulldetailz, 0 ),
571                                _vertex( fulldetailx, fulldetailz, 1 ),
572                                _vertex( fulldetailx, fulldetailz, 2 ));
573                            Real interp_h;
574                            // Determine which tri we're on
575                            if ((xpct + zpct <= 1.0f && !backwardTri) ||
576                                (xpct + (1-zpct) <= 1.0f && backwardTri))
577                            {
578                                // Solve for x/z
579                                interp_h =
580                                    (-(t1.normal.x * actualPos.x)
581                                    - t1.normal.z * actualPos.z
582                                    - t1.d) / t1.normal.y;
583                            }
584                            else
585                            {
586                                // Second tri
587                                interp_h =
588                                    (-(t2.normal.x * actualPos.x)
589                                    - t2.normal.z * actualPos.z
590                                    - t2.d) / t2.normal.y;
591                            }
592
593                            Real actual_h = _vertex( fulldetailx, fulldetailz, 1 );
594                            Real delta = fabs( interp_h - actual_h );
595
596                            Real D2 = delta * delta * C * C;
597
598                            if ( mMinLevelDistSqr[ level ] < D2 )
599                                mMinLevelDistSqr[ level ] = D2;
600
601                            // Should be save height difference?
602                            // Don't morph along edges
603                            if (msOptions->lodMorph &&
604                                fulldetailx != 0  && fulldetailx != (msOptions->tileSize - 1) &&
605                                fulldetailz != 0  && fulldetailz != (msOptions->tileSize - 1) )
606                            {
607                                // Save height difference
608                                pDeltas[fulldetailx + (fulldetailz * msOptions->tileSize)] =
609                                    interp_h - actual_h;
610                            }
611
612                        }
613
614                    }
615                }
616            }
617
618            // Unlock morph deltas if required
619            if (msOptions->lodMorph)
620            {
621                mDeltaBuffers[level - 1]->unlock();
622            }
623        }
624
625
626
627        // Post validate the whole set
628        for ( i = 1; i < msOptions->maxGeoMipMapLevel; i++ )
629        {
630
631            // Make sure no LOD transition within the tile
632            // This is especially a problem when using large tiles with flat areas
633            /* Hmm, this can look bad on some areas, disable for now
634            Vector3 delta(_vertex(0,0,0), mCenter.y, _vertex(0,0,2));
635            delta = delta - mCenter;
636            Real minDist = delta.squaredLength();
637            mMinLevelDistSqr[ i ] = std::max(mMinLevelDistSqr[ i ], minDist);
638            */
639
640            //make sure the levels are increasing...
641            if ( mMinLevelDistSqr[ i ] < mMinLevelDistSqr[ i - 1 ] )
642            {
643                mMinLevelDistSqr[ i ] = mMinLevelDistSqr[ i - 1 ];
644            }
645        }
646
647        // Now reverse traverse the list setting the 'next level down'
648        Real lastDist = -1;
649        int lastIndex = 0;
650        for (i = msOptions->maxGeoMipMapLevel - 1; i >= 0; --i)
651        {
652            if (i == msOptions->maxGeoMipMapLevel - 1)
653            {
654                // Last one is always 0
655                lastIndex = i;
656                lastDist = mMinLevelDistSqr[i];
657                mNextLevelDown[i] = 0;
658            }
659            else
660            {
661                mNextLevelDown[i] = lastIndex;
662                if (mMinLevelDistSqr[i] != lastDist)
663                {
664                    lastIndex = i;
665                    lastDist = mMinLevelDistSqr[i];
666                }
667            }
668
669        }
670
671
672    }
673    //-----------------------------------------------------------------------
674    void TerrainRenderable::_initLevelIndexes()
675    {
676        if ( mLevelInit )
677            return ;
678
679
680            if ( mLevelIndex.size() == 0 )
681        {
682            for ( int i = 0; i < 16; i++ )
683            {
684
685                                mLevelIndex.push_back( new IndexMap() );
686
687            }
688
689        }
690       
691        mLevelInit = true;
692    }
693    //-----------------------------------------------------------------------
694    void TerrainRenderable::_destroyLevelIndexes()
695    {
696        if ( mLevelInit )
697        {
698            for ( int i = 0; i < 16; i++ )
699            {
700                delete mLevelIndex[i];
701            }
702            mLevelIndex.clear();
703            mLevelInit = false;
704        }
705    }
706    //-----------------------------------------------------------------------
707    void TerrainRenderable::_adjustRenderLevel( int i )
708    {
709
710#ifdef GTP_VISIBILITY_MODIFIED_OGRE
711        mRenderLevel[msCurrentRenderLevelIndex] = i;
712#else
713                mRenderLevel = i;
714#endif // GTP_VISIBILITY_MODIFIED_OGRE
715    }
716    //-----------------------------------------------------------------------
717    Real TerrainRenderable::_calculateCFactor()
718    {
719        Real A, T;
720
721        const TerrainOptions& opts = TerrainSceneManager::getOptions();
722        if (!opts.primaryCamera)
723        {
724            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
725                "You have not created a camera yet!",
726                "TerrainRenderable::_calculateCFactor");
727        }
728
729        //A = 1 / Math::Tan(Math::AngleUnitsToRadians(opts.primaryCamera->getFOVy()));
730        // Turn off detail compression at higher FOVs
731        A = 1.0f;
732
733        int vertRes = opts.primaryCamera->getViewport()->getActualHeight();
734
735        T = 2 * ( Real ) opts.maxPixelError / ( Real ) vertRes;
736
737        return A / T;
738    }
739    //-----------------------------------------------------------------------
740    float TerrainRenderable::getHeightAt( float x, float z )
741    {
742        Vector3 start;
743        Vector3 end;
744
745        start.x = _vertex( 0, 0, 0 );
746        start.y = _vertex( 0, 0, 1 );
747        start.z = _vertex( 0, 0, 2 );
748
749        end.x = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 0 );
750        end.y = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 1 );
751        end.z = _vertex( msOptions->tileSize - 1, msOptions->tileSize - 1, 2 );
752
753        /* Safety catch, if the point asked for is outside
754        * of this tile, it will ask the appropriate tile
755        */
756
757        if ( x < start.x )
758        {
759            if ( mNeighbors[ WEST ] != 0 )
760                return mNeighbors[ WEST ] ->getHeightAt( x, z );
761            else
762                x = start.x;
763        }
764
765        if ( x > end.x )
766        {
767            if ( mNeighbors[ EAST ] != 0 )
768                return mNeighbors[ EAST ] ->getHeightAt( x, z );
769            else
770                x = end.x;
771        }
772
773        if ( z < start.z )
774        {
775            if ( mNeighbors[ NORTH ] != 0 )
776                return mNeighbors[ NORTH ] ->getHeightAt( x, z );
777            else
778                z = start.z;
779        }
780
781        if ( z > end.z )
782        {
783            if ( mNeighbors[ SOUTH ] != 0 )
784                return mNeighbors[ SOUTH ] ->getHeightAt( x, z );
785            else
786                z = end.z;
787        }
788
789
790
791        float x_pct = ( x - start.x ) / ( end.x - start.x );
792        float z_pct = ( z - start.z ) / ( end.z - start.z );
793
794        float x_pt = x_pct * ( float ) ( msOptions->tileSize - 1 );
795        float z_pt = z_pct * ( float ) ( msOptions->tileSize - 1 );
796
797        int x_index = ( int ) x_pt;
798        int z_index = ( int ) z_pt;
799
800        // If we got to the far right / bottom edge, move one back
801        if (x_index == msOptions->tileSize - 1)
802        {
803            --x_index;
804            x_pct = 1.0f;
805        }
806        else
807        {
808            // get remainder
809            x_pct = x_pt - x_index;
810        }
811        if (z_index == msOptions->tileSize - 1)
812        {
813            --z_index;
814            z_pct = 1.0f;
815        }
816        else
817        {
818            z_pct = z_pt - z_index;
819        }
820
821        //bilinear interpolate to find the height.
822
823        float t1 = _vertex( x_index, z_index, 1 );
824        float t2 = _vertex( x_index + 1, z_index, 1 );
825        float b1 = _vertex( x_index, z_index + 1, 1 );
826        float b2 = _vertex( x_index + 1, z_index + 1, 1 );
827
828        float midpoint = (b1 + t2) / 2.0;
829
830        if (x_pct + z_pct <= 1) {
831            b2 = midpoint + (midpoint - t1);
832        } else {
833            t1 = midpoint + (midpoint - b2);
834        }
835
836        float t = ( t1 * ( 1 - x_pct ) ) + ( t2 * ( x_pct ) );
837        float b = ( b1 * ( 1 - x_pct ) ) + ( b2 * ( x_pct ) );
838
839        float h = ( t * ( 1 - z_pct ) ) + ( b * ( z_pct ) );
840
841        return h;
842    }
843    //-----------------------------------------------------------------------
844    bool TerrainRenderable::intersectSegment( const Vector3 & start, const Vector3 & end, Vector3 * result )
845    {
846        Vector3 dir = end - start;
847        Vector3 ray = start;
848
849        //special case...
850        if ( dir.x == 0 && dir.z == 0 )
851        {
852            if ( ray.y <= getHeightAt( ray.x, ray.z ) )
853            {
854                if ( result != 0 )
855                    * result = start;
856
857                return true;
858            }
859        }
860
861        dir.normalise();
862
863        //dir.x *= mScale.x;
864        //dir.y *= mScale.y;
865        //dir.z *= mScale.z;
866
867        const Vector3 * corners = getBoundingBox().getAllCorners();
868
869        //start with the next one...
870        ray += dir;
871
872
873        while ( ! ( ( ray.x < corners[ 0 ].x ) ||
874            ( ray.x > corners[ 4 ].x ) ||
875            ( ray.z < corners[ 0 ].z ) ||
876            ( ray.z > corners[ 4 ].z ) ) )
877        {
878
879
880            float h = getHeightAt( ray.x, ray.z );
881
882            if ( ray.y <= h )
883            {
884                if ( result != 0 )
885                    * result = ray;
886
887                return true;
888            }
889
890            else
891            {
892                ray += dir;
893            }
894
895        }
896
897        if ( ray.x < corners[ 0 ].x && mNeighbors[ WEST ] != 0 )
898            return mNeighbors[ WEST ] ->intersectSegment( ray, end, result );
899        else if ( ray.z < corners[ 0 ].z && mNeighbors[ NORTH ] != 0 )
900            return mNeighbors[ NORTH ] ->intersectSegment( ray, end, result );
901        else if ( ray.x > corners[ 4 ].x && mNeighbors[ EAST ] != 0 )
902            return mNeighbors[ EAST ] ->intersectSegment( ray, end, result );
903        else if ( ray.z > corners[ 4 ].z && mNeighbors[ SOUTH ] != 0 )
904            return mNeighbors[ SOUTH ] ->intersectSegment( ray, end, result );
905        else
906        {
907            if ( result != 0 )
908                * result = Vector3( -1, -1, -1 );
909
910            return false;
911        }
912    }
913    //-----------------------------------------------------------------------
914    void TerrainRenderable::_generateVertexLighting( const Vector3 &sun, ColourValue ambient )
915    {
916
917        Vector3 pt;
918        Vector3 normal;
919        Vector3 light;
920
921        HardwareVertexBufferSharedPtr vbuf =
922            mTerrain->vertexBufferBinding->getBuffer(MAIN_BINDING);
923        const VertexElement* elem = mTerrain->vertexDeclaration->findElementBySemantic(VES_DIFFUSE);
924        //for each point in the terrain, see if it's in the line of sight for the sun.
925        for ( size_t i = 0; i < msOptions->tileSize; i++ )
926        {
927            for ( size_t j = 0; j < msOptions->tileSize; j++ )
928            {
929                //  printf( "Checking %f,%f,%f ", pt.x, pt.y, pt.z );
930                pt.x = _vertex( i, j, 0 );
931                pt.y = _vertex( i, j, 1 );
932                pt.z = _vertex( i, j, 2 );
933
934                light = sun - pt;
935
936                light.normalise();
937
938                if ( ! intersectSegment( pt, sun, 0 ) )
939                {
940                    //
941                    _getNormalAt( _vertex( i, j, 0 ), _vertex( i, j, 2 ), &normal );
942
943                    float l = light.dotProduct( normal );
944
945                    ColourValue v;
946                    v.r = ambient.r + l;
947                    v.g = ambient.g + l;
948                    v.b = ambient.b + l;
949
950                    if ( v.r > 1 ) v.r = 1;
951
952                    if ( v.g > 1 ) v.g = 1;
953
954                    if ( v.b > 1 ) v.b = 1;
955
956                    if ( v.r < 0 ) v.r = 0;
957
958                    if ( v.g < 0 ) v.g = 0;
959
960                    if ( v.b < 0 ) v.b = 0;
961
962                    RGBA colour;
963                    Root::getSingleton().convertColourValue( v, &colour );
964                    vbuf->writeData(
965                        (_index( i, j ) * vbuf->getVertexSize()) + elem->getOffset(),
966                        sizeof(RGBA), &colour);
967                }
968
969                else
970                {
971                    RGBA colour;
972                    Root::getSingleton().convertColourValue( ambient, &colour );
973
974                    vbuf->writeData(
975                        (_index( i, j ) * vbuf->getVertexSize()) + elem->getOffset(),
976                        sizeof(RGBA), &colour);
977                }
978
979            }
980
981        }
982
983        printf( "." );
984    }
985    //-----------------------------------------------------------------------
986    Real TerrainRenderable::getSquaredViewDepth(const Camera* cam) const
987    {
988        Vector3 diff = mCenter - cam->getDerivedPosition();
989        // Use squared length to avoid square root
990        return diff.squaredLength();
991    }
992
993    //-----------------------------------------------------------------------
994    const LightList& TerrainRenderable::getLights(void) const
995    {
996        return getParentSceneNode()->findLights(this->getBoundingRadius());
997    }
998    //-----------------------------------------------------------------------
999    IndexData* TerrainRenderable::getIndexData(void)
1000    {
1001        unsigned int stitchFlags = 0;
1002
1003        if ( mNeighbors[ EAST ] != 0 && mNeighbors[ EAST ] -> getRenderLevel() > getRenderLevel() )
1004        {
1005            stitchFlags |= STITCH_EAST;
1006            stitchFlags |=
1007                (mNeighbors[ EAST ] -> getRenderLevel() - getRenderLevel()) << STITCH_EAST_SHIFT;
1008        }
1009
1010        if ( mNeighbors[ WEST ] != 0 && mNeighbors[ WEST ] -> getRenderLevel() > getRenderLevel() )
1011        {
1012            stitchFlags |= STITCH_WEST;
1013            stitchFlags |=
1014                (mNeighbors[ WEST ] -> getRenderLevel() - getRenderLevel()) << STITCH_WEST_SHIFT;
1015        }
1016
1017        if ( mNeighbors[ NORTH ] != 0 && mNeighbors[ NORTH ] -> getRenderLevel() > getRenderLevel() )
1018        {
1019            stitchFlags |= STITCH_NORTH;
1020            stitchFlags |=
1021                (mNeighbors[ NORTH ] -> getRenderLevel() - getRenderLevel()) << STITCH_NORTH_SHIFT;
1022        }
1023
1024        if ( mNeighbors[ SOUTH ] != 0 && mNeighbors[ SOUTH ] -> getRenderLevel() > getRenderLevel() )
1025        {
1026            stitchFlags |= STITCH_SOUTH;
1027            stitchFlags |=
1028                (mNeighbors[ SOUTH ] -> getRenderLevel() - getRenderLevel()) << STITCH_SOUTH_SHIFT;
1029        }
1030
1031        // Check preexisting
1032        IndexMap::iterator ii = mLevelIndex[ getRenderLevel() ]->find( stitchFlags );
1033        IndexData* indexData;
1034        if ( ii == mLevelIndex[ getRenderLevel() ]->end())
1035        {
1036            // Create
1037            if (msOptions->useTriStrips)
1038            {
1039                indexData = generateTriStripIndexes(stitchFlags);
1040            }
1041            else
1042            {
1043                indexData = generateTriListIndexes(stitchFlags);
1044            }
1045            mLevelIndex[ getRenderLevel() ]->insert(
1046                IndexMap::value_type(stitchFlags, indexData));
1047        }
1048        else
1049        {
1050            indexData = ii->second;
1051        }
1052
1053
1054        return indexData;
1055
1056
1057    }
1058    //-----------------------------------------------------------------------
1059    IndexData* TerrainRenderable::generateTriStripIndexes(unsigned int stitchFlags)
1060    {
1061        // The step used for the current level
1062        int step = 1 << getRenderLevel();
1063        // The step used for the lower level
1064        int lowstep = 1 << (getRenderLevel() + 1);
1065
1066        int numIndexes = 0;
1067
1068        // Calculate the number of indexes required
1069        // This is the number of 'cells' at this detail level x 2
1070        // plus 3 degenerates to turn corners
1071        int numTrisAcross = (((msOptions->tileSize-1) / step) * 2) + 3;
1072        // Num indexes is number of tris + 2
1073        int new_length = numTrisAcross * ((msOptions->tileSize-1) / step) + 2;
1074        //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
1075
1076        IndexData* indexData = new IndexData;
1077        indexData->indexBuffer =
1078            HardwareBufferManager::getSingleton().createIndexBuffer(
1079            HardwareIndexBuffer::IT_16BIT,
1080            new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
1081
1082        msIndexCache.mCache.push_back( indexData );
1083
1084        unsigned short* pIdx = static_cast<unsigned short*>(
1085            indexData->indexBuffer->lock(0,
1086            indexData->indexBuffer->getSizeInBytes(),
1087            HardwareBuffer::HBL_DISCARD));
1088
1089        // Stripified mesh
1090        for ( int j = 0; j < msOptions->tileSize - 1; j += step )
1091        {
1092            int i;
1093            // Forward strip
1094            // We just do the |/ here, final | done after
1095            for ( i = 0; i < msOptions->tileSize - 1; i += step )
1096            {
1097                int x[4], y[4];
1098                x[0] = x[1] = i;
1099                x[2] = x[3] = i + step;
1100                y[0] = y[2] = j;
1101                y[1] = y[3] = j + step;
1102
1103                if (j == 0  && (stitchFlags & STITCH_NORTH))
1104                {
1105                    // North reduction means rounding x[0] and x[2]
1106                    if (x[0] % lowstep != 0)
1107                    {
1108                        // Since we know we only drop down one level of LOD,
1109                        // removing 1 step of higher LOD should return to lower
1110                        x[0] -= step;
1111                    }
1112                    if (x[2] % lowstep != 0)
1113                    {
1114                        x[2] -= step;
1115                    }
1116                }
1117
1118                // Never get a south tiling on a forward strip (always finish on
1119                // a backward strip)
1120
1121                if (i == 0  && (stitchFlags & STITCH_WEST))
1122                {
1123                    // West reduction means rounding y[0] / y[1]
1124                    if (y[0] % lowstep != 0)
1125                    {
1126                        y[0] -= step;
1127                    }
1128                    if (y[1] % lowstep != 0)
1129                    {
1130                        y[1] -= step;
1131                    }
1132                }
1133                if (i == (msOptions->tileSize - 1 - step) && (stitchFlags & STITCH_EAST))
1134                {
1135                    // East tiling means rounding y[2] & y[3]
1136                    if (y[2] % lowstep != 0)
1137                    {
1138                        y[2] -= step;
1139                    }
1140                    if (y[3] % lowstep != 0)
1141                    {
1142                        y[3] -= step;
1143                    }
1144                }
1145
1146                //triangles
1147                if (i == 0)
1148                {
1149                    // Starter
1150                    *pIdx++ = _index( x[0], y[0] ); numIndexes++;
1151                }
1152                *pIdx++ = _index( x[1], y[1] ); numIndexes++;
1153                *pIdx++ = _index( x[2], y[2] ); numIndexes++;
1154
1155                if (i == msOptions->tileSize - 1 - step)
1156                {
1157                    // Emit extra index to finish row
1158                    *pIdx++ = _index( x[3], y[3] ); numIndexes++;
1159                    if (j < msOptions->tileSize - 1 - step)
1160                    {
1161                        // Emit this index twice more (this is to turn around without
1162                        // artefacts)
1163                        // ** Hmm, looks like we can drop this and it's unnoticeable
1164                        //*pIdx++ = _index( x[3], y[3] ); numIndexes++;
1165                        //*pIdx++ = _index( x[3], y[3] ); numIndexes++;
1166                    }
1167                }
1168
1169            }
1170            // Increment row
1171            j += step;
1172            // Backward strip
1173            for ( i = msOptions->tileSize - 1; i > 0 ; i -= step )
1174            {
1175                int x[4], y[4];
1176                x[0] = x[1] = i;
1177                x[2] = x[3] = i - step;
1178                y[0] = y[2] = j;
1179                y[1] = y[3] = j + step;
1180
1181                // Never get a north tiling on a backward strip (always
1182                // start on a forward strip)
1183                if (j == (msOptions->tileSize - 1 - step) && (stitchFlags & STITCH_SOUTH))
1184                {
1185                    // South reduction means rounding x[1] / x[3]
1186                    if (x[1] % lowstep != 0)
1187                    {
1188                        x[1] -= step;
1189                    }
1190                    if (x[3] % lowstep != 0)
1191                    {
1192                        x[3] -= step;
1193                    }
1194                }
1195
1196                if (i == step  && (stitchFlags & STITCH_WEST))
1197                {
1198                    // West tiling on backward strip is rounding of y[2] / y[3]
1199                    if (y[2] % lowstep != 0)
1200                    {
1201                        y[2] -= step;
1202                    }
1203                    if (y[3] % lowstep != 0)
1204                    {
1205                        y[3] -= step;
1206                    }
1207                }
1208                if (i == msOptions->tileSize - 1 && (stitchFlags & STITCH_EAST))
1209                {
1210                    // East tiling means rounding y[0] and y[1] on backward strip
1211                    if (y[0] % lowstep != 0)
1212                    {
1213                        y[0] -= step;
1214                    }
1215                    if (y[1] % lowstep != 0)
1216                    {
1217                        y[1] -= step;
1218                    }
1219                }
1220
1221                //triangles
1222                if (i == msOptions->tileSize)
1223                {
1224                    // Starter
1225                    *pIdx++ = _index( x[0], y[0] ); numIndexes++;
1226                }
1227                *pIdx++ = _index( x[1], y[1] ); numIndexes++;
1228                *pIdx++ = _index( x[2], y[2] ); numIndexes++;
1229
1230                if (i == step)
1231                {
1232                    // Emit extra index to finish row
1233                    *pIdx++ = _index( x[3], y[3] ); numIndexes++;
1234                    if (j < msOptions->tileSize - 1 - step)
1235                    {
1236                        // Emit this index once more (this is to turn around)
1237                        *pIdx++ = _index( x[3], y[3] ); numIndexes++;
1238                    }
1239                }
1240            }
1241        }
1242
1243
1244        indexData->indexBuffer->unlock();
1245        indexData->indexCount = numIndexes;
1246        indexData->indexStart = 0;
1247
1248        return indexData;
1249
1250    }
1251    //-----------------------------------------------------------------------
1252    IndexData* TerrainRenderable::generateTriListIndexes(unsigned int stitchFlags)
1253    {
1254
1255        int numIndexes = 0;
1256        int step = 1 << getRenderLevel();
1257
1258        IndexData* indexData = 0;
1259
1260        int north = stitchFlags & STITCH_NORTH ? step : 0;
1261        int south = stitchFlags & STITCH_SOUTH ? step : 0;
1262        int east = stitchFlags & STITCH_EAST ? step : 0;
1263        int west = stitchFlags & STITCH_WEST ? step : 0;
1264
1265        int new_length = ( msOptions->tileSize / step ) * ( msOptions->tileSize / step ) * 2 * 2 * 2 ;
1266        //this is the maximum for a level.  It wastes a little, but shouldn't be a problem.
1267
1268        indexData = new IndexData;
1269        indexData->indexBuffer =
1270            HardwareBufferManager::getSingleton().createIndexBuffer(
1271            HardwareIndexBuffer::IT_16BIT,
1272            new_length, HardwareBuffer::HBU_STATIC_WRITE_ONLY);//, false);
1273
1274        msIndexCache.mCache.push_back( indexData );
1275
1276        unsigned short* pIdx = static_cast<unsigned short*>(
1277            indexData->indexBuffer->lock(0,
1278            indexData->indexBuffer->getSizeInBytes(),
1279            HardwareBuffer::HBL_DISCARD));
1280
1281        // Do the core vertices, minus stitches
1282        for ( int j = north; j < msOptions->tileSize - 1 - south; j += step )
1283        {
1284            for ( int i = west; i < msOptions->tileSize - 1 - east; i += step )
1285            {
1286                //triangles
1287                *pIdx++ = _index( i, j ); numIndexes++;
1288                *pIdx++ = _index( i, j + step ); numIndexes++;
1289                *pIdx++ = _index( i + step, j ); numIndexes++;
1290
1291                *pIdx++ = _index( i, j + step ); numIndexes++;
1292                *pIdx++ = _index( i + step, j + step ); numIndexes++;
1293                *pIdx++ = _index( i + step, j ); numIndexes++;
1294            }
1295        }
1296
1297        // North stitching
1298        if ( north > 0 )
1299        {
1300            numIndexes += stitchEdge(NORTH, getRenderLevel(), mNeighbors[NORTH]->getRenderLevel(),
1301                west > 0, east > 0, &pIdx);
1302        }
1303        // East stitching
1304        if ( east > 0 )
1305        {
1306            numIndexes += stitchEdge(EAST, getRenderLevel(), mNeighbors[EAST]->getRenderLevel(),
1307                north > 0, south > 0, &pIdx);
1308        }
1309        // South stitching
1310        if ( south > 0 )
1311        {
1312            numIndexes += stitchEdge(SOUTH, getRenderLevel(), mNeighbors[SOUTH]->getRenderLevel(),
1313                east > 0, west > 0, &pIdx);
1314        }
1315        // West stitching
1316        if ( west > 0 )
1317        {
1318            numIndexes += stitchEdge(WEST, getRenderLevel(), mNeighbors[WEST]->getRenderLevel(),
1319                south > 0, north > 0, &pIdx);
1320        }
1321
1322
1323        indexData->indexBuffer->unlock();
1324        indexData->indexCount = numIndexes;
1325        indexData->indexStart = 0;
1326
1327        return indexData;
1328    }
1329    //-----------------------------------------------------------------------
1330    HardwareVertexBufferSharedPtr TerrainRenderable::createDeltaBuffer(void)
1331    {
1332        // Delta buffer is a 1D float buffer of height offsets
1333        HardwareVertexBufferSharedPtr buf =
1334            HardwareBufferManager::getSingleton().createVertexBuffer(
1335            VertexElement::getTypeSize(VET_FLOAT1),
1336            msOptions->tileSize * msOptions->tileSize,
1337            HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1338        // Fill the buffer with zeros, we will only fill in delta
1339        void* pVoid = buf->lock(HardwareBuffer::HBL_DISCARD);
1340        memset(pVoid, 0, msOptions->tileSize * msOptions->tileSize * sizeof(float));
1341        buf->unlock();
1342
1343        return buf;
1344
1345    }
1346    //-----------------------------------------------------------------------
1347    void TerrainRenderable::_updateCustomGpuParameter(
1348        const GpuProgramParameters::AutoConstantEntry& constantEntry,
1349        GpuProgramParameters* params) const
1350    {
1351        if (constantEntry.data == MORPH_CUSTOM_PARAM_ID)
1352        {
1353            // Update morph LOD factor
1354            params->setConstant(constantEntry.index, mLODMorphFactor);
1355        }
1356        else
1357        {
1358            Renderable::_updateCustomGpuParameter(constantEntry, params);
1359        }
1360
1361    }
1362    //-----------------------------------------------------------------------
1363    int TerrainRenderable::stitchEdge(Neighbor neighbor, int hiLOD, int loLOD,
1364        bool omitFirstTri, bool omitLastTri, unsigned short** ppIdx)
1365    {
1366        assert(loLOD > hiLOD);
1367        /*
1368        Now do the stitching; we can stitch from any level to any level.
1369        The stitch pattern is like this for each pair of vertices in the lower LOD
1370        (excuse the poor ascii art):
1371
1372        lower LOD
1373        *-----------*
1374        |\  \ 3 /  /|
1375        |1\2 \ / 4/5|
1376        *--*--*--*--*
1377        higher LOD
1378
1379        The algorithm is, for each pair of lower LOD vertices:
1380        1. Iterate over the higher LOD vertices, generating tris connected to the
1381        first lower LOD vertex, up to and including 1/2 the span of the lower LOD
1382        over the higher LOD (tris 1-2). Skip the first tri if it is on the edge
1383        of the tile and that edge is to be stitched itself.
1384        2. Generate a single tri for the middle using the 2 lower LOD vertices and
1385        the middle vertex of the higher LOD (tri 3).
1386        3. Iterate over the higher LOD vertices from 1/2 the span of the lower LOD
1387        to the end, generating tris connected to the second lower LOD vertex
1388        (tris 4-5). Skip the last tri if it is on the edge of a tile and that
1389        edge is to be stitched itself.
1390
1391        The same algorithm works for all edges of the patch; stitching is done
1392        clockwise so that the origin and steps used change, but the general
1393        approach does not.
1394        */
1395
1396        // Get pointer to be updated
1397        unsigned short* pIdx = *ppIdx;
1398
1399        // Work out the steps ie how to increment indexes
1400        // Step from one vertex to another in the high detail version
1401        int step = 1 << hiLOD;
1402        // Step from one vertex to another in the low detail version
1403        int superstep = 1 << loLOD;
1404        // Step half way between low detail steps
1405        int halfsuperstep = superstep >> 1;
1406
1407        // Work out the starting points and sign of increments
1408        // We always work the strip clockwise
1409        int startx, starty, endx, rowstep;
1410        bool horizontal;
1411        switch(neighbor)
1412        {
1413        case NORTH:
1414            startx = starty = 0;
1415            endx = msOptions->tileSize - 1;
1416            rowstep = step;
1417            horizontal = true;
1418            break;
1419        case SOUTH:
1420            // invert x AND y direction, helps to keep same winding
1421            startx = starty = msOptions->tileSize - 1;
1422            endx = 0;
1423            rowstep = -step;
1424            step = -step;
1425            superstep = -superstep;
1426            halfsuperstep = -halfsuperstep;
1427            horizontal = true;
1428            break;
1429        case EAST:
1430            startx = 0;
1431            endx = msOptions->tileSize - 1;
1432            starty = msOptions->tileSize - 1;
1433            rowstep = -step;
1434            horizontal = false;
1435            break;
1436        case WEST:
1437            startx = msOptions->tileSize - 1;
1438            endx = 0;
1439            starty = 0;
1440            rowstep = step;
1441            step = -step;
1442            superstep = -superstep;
1443            halfsuperstep = -halfsuperstep;
1444            horizontal = false;
1445            break;
1446        };
1447
1448        int numIndexes = 0;
1449
1450        for ( int j = startx; j != endx; j += superstep )
1451        {
1452            int k;
1453            for (k = 0; k != halfsuperstep; k += step)
1454            {
1455                int jk = j + k;
1456                //skip the first bit of the corner?
1457                if ( j != startx || k != 0 || !omitFirstTri )
1458                {
1459                    if (horizontal)
1460                    {
1461                        *pIdx++ = _index( j , starty ); numIndexes++;
1462                        *pIdx++ = _index( jk, starty + rowstep ); numIndexes++;
1463                        *pIdx++ = _index( jk + step, starty + rowstep ); numIndexes++;
1464                    }
1465                    else
1466                    {
1467                        *pIdx++ = _index( starty, j ); numIndexes++;
1468                        *pIdx++ = _index( starty + rowstep, jk ); numIndexes++;
1469                        *pIdx++ = _index( starty + rowstep, jk + step); numIndexes++;
1470                    }
1471                }
1472            }
1473
1474            // Middle tri
1475            if (horizontal)
1476            {
1477                *pIdx++ = _index( j, starty ); numIndexes++;
1478                *pIdx++ = _index( j + halfsuperstep, starty + rowstep); numIndexes++;
1479                *pIdx++ = _index( j + superstep, starty ); numIndexes++;
1480            }
1481            else
1482            {
1483                *pIdx++ = _index( starty, j ); numIndexes++;
1484                *pIdx++ = _index( starty + rowstep, j + halfsuperstep ); numIndexes++;
1485                *pIdx++ = _index( starty, j + superstep ); numIndexes++;
1486            }
1487
1488            for (k = halfsuperstep; k != superstep; k += step)
1489            {
1490                int jk = j + k;
1491                if ( j != endx - superstep || k != superstep - step || !omitLastTri )
1492                {
1493                    if (horizontal)
1494                    {
1495                        *pIdx++ = _index( j + superstep, starty ); numIndexes++;
1496                        *pIdx++ = _index( jk, starty + rowstep ); numIndexes++;
1497                        *pIdx++ = _index( jk + step, starty + rowstep ); numIndexes++;
1498                    }
1499                    else
1500                    {
1501                        *pIdx++ = _index( starty, j + superstep ); numIndexes++;
1502                        *pIdx++ = _index( starty + rowstep, jk ); numIndexes++;
1503                        *pIdx++ = _index( starty + rowstep, jk + step ); numIndexes++;
1504                    }
1505                }
1506            }
1507        }
1508
1509        *ppIdx = pIdx;
1510
1511        return numIndexes;
1512
1513    }
1514#ifdef GTP_VISIBILITY_MODIFIED_OGRE
1515        //-----------------------------------------------------------------------
1516        void TerrainRenderable::ResetRenderLevelIndex()
1517        {
1518                msCurrentRenderLevelIndex = 0;
1519        }
1520        //-----------------------------------------------------------------------
1521        void TerrainRenderable::NextRenderLevelIndex()
1522        {
1523                if ((++ msCurrentRenderLevelIndex) > MAX_RENDERLEVEL_INDEX)
1524                        msCurrentRenderLevelIndex = 0;
1525        }
1526#endif // GTP_VISIBILITY_MODIFIED_OGRE
1527
1528} //namespace
Note: See TracBrowser for help on using the repository browser.