source: OGRE/trunk/ogre_changes/Ogre1.2/PlugIns/OctreeSceneManager/src/OgreTerrainRenderable.cpp @ 922

Revision 922, 57.0 KB checked in by mattausch, 18 years ago (diff)

fixed terrain error

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