source: GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreBiTerrainRenderable.cpp @ 2348

Revision 2348, 57.1 KB checked in by vizrt_christian_seidl, 17 years ago (diff)

Added: BIHierarchy SceneManager?

BITerrain SceneManager?

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