source: OGRE/trunk/ogre_changes/Plugins/OctreeSceneManager/src/OgreTerrainRenderable.cpp @ 657

Revision 657, 54.8 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

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