source: GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTerrainRenderable.cpp @ 1273

Revision 1273, 57.1 KB checked in by szydlowski, 18 years ago (diff)

Added the KdTerrainSceneManager?, a subclass of the KdTreeSceneManager? capable of rendering terrain like the TerrainSceneManager? from Ogre.
All the *Kd*Terrain* classes are identical to their octree counterparts, save prefixing all classes and structures with Kd to avoid namespace clashes.
This was necessary, since the TerrainSceneManager? was hard coded in these classes, and all references had to be replaced with the KdTerrainSceneManager?.
Also added a comprehensive README for the demo application.

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 "OgreKdTerrainRenderable.h"
37#include "OgreSceneNode.h"
38#include "OgreRenderQueue.h"
39#include "OgreRenderOperation.h"
40#include "OgreCamera.h"
41#include "OgreRoot.h"
42#include "OgreKdTerrainSceneManager.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 KdTerrainRenderable::mType = "TerrainMipMap";
58    //-----------------------------------------------------------------------
59    //-----------------------------------------------------------------------
60#ifdef GTP_VISIBILITY_MODIFIED_OGRE
61        int KdTerrainRenderable::msCurrentRenderLevelIndex = 0;
62#endif // GTP_VISIBILITY_MODIFIED_OGRE
63    //-----------------------------------------------------------------------
64    KdTerrainRenderable::KdTerrainRenderable(const String& name, KdTerrainSceneManager* 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    KdTerrainRenderable::~KdTerrainRenderable()
87    {
88
89        deleteGeometry();
90    }
91        //-----------------------------------------------------------------------
92        uint32 KdTerrainRenderable::getTypeFlags(void) const
93        {
94                // return world flag
95                return SceneManager::WORLD_GEOMETRY_TYPE_MASK;
96        }
97    //-----------------------------------------------------------------------
98    void KdTerrainRenderable::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 KdTerrainRenderable::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 KdTerrainRenderable::_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 KdTerrainRenderable::_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 KdTerrainRenderable::_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 KdTerrainRenderable::_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 KdTerrainRenderable::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 KdTerrainRenderable::getWorldTransforms( Matrix4* xform ) const
475    {
476        *xform = mParentNode->_getFullTransform();
477    }
478    //-----------------------------------------------------------------------
479    const Quaternion& KdTerrainRenderable::getWorldOrientation(void) const
480    {
481        return mParentNode->_getDerivedOrientation();
482    }
483    //-----------------------------------------------------------------------
484    const Vector3& KdTerrainRenderable::getWorldPosition(void) const
485    {
486        return mParentNode->_getDerivedPosition();
487    }
488    //-----------------------------------------------------------------------
489    bool KdTerrainRenderable::_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 KdTerrainRenderable::_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 KdTerrainRenderable::_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 KdTerrainRenderable::_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                "KdTerrainRenderable::_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 KdTerrainRenderable::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 KdTerrainRenderable::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 KdTerrainRenderable::_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 KdTerrainRenderable::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& KdTerrainRenderable::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* KdTerrainRenderable::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* KdTerrainRenderable::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* KdTerrainRenderable::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 KdTerrainRenderable::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 KdTerrainRenderable::_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 KdTerrainRenderable::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 KdTerrainRenderable::ResetRenderLevelIndex()
1582        {
1583                msCurrentRenderLevelIndex = 0;
1584        }
1585        //-----------------------------------------------------------------------
1586        void KdTerrainRenderable::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.