root/OpenSceneGraph/trunk/src/osgTerrain/GeometryTechnique.cpp @ 12292

Revision 12292, 55.6 kB (checked in by robert, 3 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
Line 
1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgTerrain/GeometryTechnique>
15#include <osgTerrain/TerrainTile>
16#include <osgTerrain/Terrain>
17
18#include <osgUtil/MeshOptimizers>
19
20#include <osgDB/FileUtils>
21
22#include <osg/io_utils>
23#include <osg/Texture2D>
24#include <osg/Texture1D>
25#include <osg/TexEnvCombine>
26#include <osg/Program>
27#include <osg/Math>
28#include <osg/Timer>
29
30using namespace osgTerrain;
31
32GeometryTechnique::GeometryTechnique()
33{
34    setFilterBias(0);
35    setFilterWidth(0.1);
36    setFilterMatrixAs(GAUSSIAN);
37   
38}
39
40GeometryTechnique::GeometryTechnique(const GeometryTechnique& gt,const osg::CopyOp& copyop):
41    TerrainTechnique(gt,copyop)
42{
43    setFilterBias(gt._filterBias);
44    setFilterWidth(gt._filterWidth);
45    setFilterMatrix(gt._filterMatrix);
46}
47
48GeometryTechnique::~GeometryTechnique()
49{
50}
51
52void GeometryTechnique::setFilterBias(float filterBias)
53{
54    _filterBias = filterBias;
55    if (!_filterBiasUniform) _filterBiasUniform = new osg::Uniform("filterBias",_filterBias);
56    else _filterBiasUniform->set(filterBias);
57}
58
59void GeometryTechnique::setFilterWidth(float filterWidth)
60{
61    _filterWidth = filterWidth;
62    if (!_filterWidthUniform) _filterWidthUniform = new osg::Uniform("filterWidth",_filterWidth);
63    else _filterWidthUniform->set(filterWidth);
64}
65
66void GeometryTechnique::setFilterMatrix(const osg::Matrix3& matrix)
67{
68    _filterMatrix = matrix;
69    if (!_filterMatrixUniform) _filterMatrixUniform = new osg::Uniform("filterMatrix",_filterMatrix);
70    else _filterMatrixUniform->set(_filterMatrix);
71}
72
73void GeometryTechnique::setFilterMatrixAs(FilterType filterType)
74{
75    switch(filterType)
76    {
77        case(SMOOTH):
78            setFilterMatrix(osg::Matrix3(0.0, 0.5/2.5, 0.0,
79                                         0.5/2.5, 0.5/2.5, 0.5/2.5,
80                                         0.0, 0.5/2.5, 0.0));
81            break;
82        case(GAUSSIAN):
83            setFilterMatrix(osg::Matrix3(0.0, 1.0/8.0, 0.0,
84                                         1.0/8.0, 4.0/8.0, 1.0/8.0,
85                                         0.0, 1.0/8.0, 0.0));
86            break;
87        case(SHARPEN):
88            setFilterMatrix(osg::Matrix3(0.0, -1.0, 0.0,
89                                         -1.0, 5.0, -1.0,
90                                         0.0, -1.0, 0.0));
91            break;
92
93    };
94}
95
96void GeometryTechnique::init(int dirtyMask, bool assumeMultiThreaded)
97{
98    OSG_INFO<<"Doing GeometryTechnique::init()"<<std::endl;
99   
100    if (!_terrainTile) return;
101
102    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_writeBufferMutex);
103
104    // take a temporary referecen
105    osg::ref_ptr<TerrainTile> tile = _terrainTile;
106
107    if (dirtyMask==0) return;
108
109    osg::ref_ptr<BufferData> buffer = new BufferData;
110
111    Locator* masterLocator = computeMasterLocator();
112
113    osg::Vec3d centerModel = computeCenterModel(*buffer, masterLocator);
114
115    if ((dirtyMask & TerrainTile::IMAGERY_DIRTY)==0)
116    {
117        generateGeometry(*buffer, masterLocator, centerModel);
118
119        osg::ref_ptr<BufferData> read_buffer = _currentBufferData;
120
121        osg::StateSet* stateset = read_buffer->_geode->getStateSet();
122        if (stateset)
123        {
124            // OSG_NOTICE<<"Reusing StateSet"<<std::endl;
125            buffer->_geode->setStateSet(stateset);
126        }
127        else
128        {
129            applyColorLayers(*buffer);
130            applyTransparency(*buffer);
131        }
132    }
133    else
134    {
135        generateGeometry(*buffer, masterLocator, centerModel);
136        applyColorLayers(*buffer);
137        applyTransparency(*buffer);
138    }
139
140    if (buffer->_transform.valid()) buffer->_transform->setThreadSafeRefUnref(true);
141
142    if (!_currentBufferData || !assumeMultiThreaded)
143    {
144        // no currentBufferData so we must be the first init to be applied
145        _currentBufferData = buffer;
146    }
147    else
148    {
149        // there is already an active _currentBufferData so we'll request that this gets swapped on next frame.
150        _newBufferData = buffer;
151        if (_terrainTile->getTerrain()) _terrainTile->getTerrain()->updateTerrainTileOnNextFrame(_terrainTile);
152    }
153
154    _terrainTile->setDirtyMask(0);
155}
156
157Locator* GeometryTechnique::computeMasterLocator()
158{
159    osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer();
160    osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0);
161
162    Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0;
163    Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0;
164   
165    Locator* masterLocator = elevationLocator ? elevationLocator : colorLocator;
166    if (!masterLocator)
167    {
168        OSG_NOTICE<<"Problem, no locator found in any of the terrain layers"<<std::endl;
169        return 0;
170    }
171   
172    return masterLocator;
173}
174
175osg::Vec3d GeometryTechnique::computeCenterModel(BufferData& buffer, Locator* masterLocator)
176{
177    if (!masterLocator) return osg::Vec3d(0.0,0.0,0.0);
178
179    osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer();
180    osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(0);
181
182    Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0;
183    Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0;
184   
185    if (!elevationLocator) elevationLocator = masterLocator;
186    if (!colorLocator) colorLocator = masterLocator;
187
188    osg::Vec3d bottomLeftNDC(DBL_MAX, DBL_MAX, 0.0);
189    osg::Vec3d topRightNDC(-DBL_MAX, -DBL_MAX, 0.0);
190   
191    if (elevationLayer)
192    {
193        if (elevationLocator!= masterLocator)
194        {
195            masterLocator->computeLocalBounds(*elevationLocator, bottomLeftNDC, topRightNDC);
196        }
197        else
198        {
199            bottomLeftNDC.x() = osg::minimum(bottomLeftNDC.x(), 0.0);
200            bottomLeftNDC.y() = osg::minimum(bottomLeftNDC.y(), 0.0);
201            topRightNDC.x() = osg::maximum(topRightNDC.x(), 1.0);
202            topRightNDC.y() = osg::maximum(topRightNDC.y(), 1.0);
203        }
204    }
205
206    if (colorLayer)
207    {
208        if (colorLocator!= masterLocator)
209        {
210            masterLocator->computeLocalBounds(*colorLocator, bottomLeftNDC, topRightNDC);
211        }
212        else
213        {
214            bottomLeftNDC.x() = osg::minimum(bottomLeftNDC.x(), 0.0);
215            bottomLeftNDC.y() = osg::minimum(bottomLeftNDC.y(), 0.0);
216            topRightNDC.x() = osg::maximum(topRightNDC.x(), 1.0);
217            topRightNDC.y() = osg::maximum(topRightNDC.y(), 1.0);
218        }
219    }
220
221    OSG_INFO<<"bottomLeftNDC = "<<bottomLeftNDC<<std::endl;
222    OSG_INFO<<"topRightNDC = "<<topRightNDC<<std::endl;
223
224    buffer._transform = new osg::MatrixTransform;
225
226    osg::Vec3d centerNDC = (bottomLeftNDC + topRightNDC)*0.5;
227    osg::Vec3d centerModel = (bottomLeftNDC + topRightNDC)*0.5;
228    masterLocator->convertLocalToModel(centerNDC, centerModel);
229   
230    buffer._transform->setMatrix(osg::Matrix::translate(centerModel));
231   
232    return centerModel;
233}
234
235class VertexNormalGenerator
236{
237    public:
238
239        typedef std::vector<int> Indices;
240        typedef std::pair< osg::ref_ptr<osg::Vec2Array>, Locator* > TexCoordLocatorPair;
241        typedef std::map< Layer*, TexCoordLocatorPair > LayerToTexCoordMap;
242
243        VertexNormalGenerator(Locator* masterLocator, const osg::Vec3d& centerModel, int numRows, int numColmns, float scaleHeight, bool createSkirt);
244
245        void populateCenter(osgTerrain::Layer* elevationLayer, LayerToTexCoordMap& layerToTexCoordMap);
246        void populateLeftBoundary(osgTerrain::Layer* elevationLayer);
247        void populateRightBoundary(osgTerrain::Layer* elevationLayer);
248        void populateAboveBoundary(osgTerrain::Layer* elevationLayer);
249        void populateBelowBoundary(osgTerrain::Layer* elevationLayer);
250
251        void computeNormals();
252
253        unsigned int capacity() const { return _vertices->capacity(); }
254
255        inline void setVertex(int c, int r, const osg::Vec3& v, const osg::Vec3& n)
256        {
257            int& i = index(c,r);
258            if (i==0)
259            {
260                if (r<0 || r>=_numRows || c<0 || c>=_numColumns)
261                {
262                    i = -(1+static_cast<int>(_boundaryVertices->size()));
263                    _boundaryVertices->push_back(v);
264                    // OSG_NOTICE<<"setVertex("<<c<<", "<<r<<", ["<<v<<"], ["<<n<<"]), i="<<i<<" _boundaryVertices["<<-i-1<<"]="<<(*_boundaryVertices)[-i-1]<<"]"<<std::endl;
265                }
266                else
267                {
268                    i = _vertices->size() + 1;
269                    _vertices->push_back(v);
270                    _normals->push_back(n);
271                    // OSG_NOTICE<<"setVertex("<<c<<", "<<r<<", ["<<v<<"], ["<<n<<"]), i="<<i<<" _vertices["<<i-1<<"]="<<(*_vertices)[i-1]<<"]"<<std::endl;
272                }
273            }
274            else if (i<0)
275            {
276                (*_boundaryVertices)[-i-1] = v;
277                // OSG_NOTICE<<"setVertex("<<c<<", "<<r<<", ["<<v<<"], ["<<n<<"] _boundaryVertices["<<-i-1<<"]="<<(*_boundaryVertices)[-i-1]<<"]"<<std::endl;
278            }
279            else
280            {
281                // OSG_NOTICE<<"Overwriting setVertex("<<c<<", "<<r<<", ["<<v<<"], ["<<n<<"]"<<std::endl;
282                // OSG_NOTICE<<"     previous values ( vertex ["<<(*_vertices)[i-1]<<"], normal (*_normals)[i-1] ["<<n<<"]"<<std::endl;
283                // (*_vertices)[i-1] = v;
284
285                // average the vertex positions
286                (*_vertices)[i-1] = ((*_vertices)[i-1] + v)*0.5f;
287
288                (*_normals)[i-1] = n;
289            }
290        }
291
292        inline int& index(int c, int r) { return _indices[(r+1)*(_numColumns+2)+c+1]; }
293
294        inline int index(int c, int r) const { return _indices[(r+1)*(_numColumns+2)+c+1]; }
295
296        inline int vertex_index(int c, int r) const { int i = _indices[(r+1)*(_numColumns+2)+c+1]; return i-1; }
297
298        inline bool vertex(int c, int r, osg::Vec3& v) const
299        {
300            int i = index(c,r);
301            if (i==0) return false;
302            if (i<0) v = (*_boundaryVertices)[-i-1];
303            else v = (*_vertices)[i-1];
304            return true;
305        }
306
307        inline bool computeNormal(int c, int r, osg::Vec3& n) const
308        {
309#if 1
310            return computeNormalWithNoDiagonals(c,r,n);
311#else
312            return computeNormalWithDiagonals(c,r,n);
313#endif
314        }
315
316        inline bool computeNormalWithNoDiagonals(int c, int r, osg::Vec3& n) const
317        {
318            osg::Vec3 center;
319            bool center_valid  = vertex(c, r,  center);
320            if (!center_valid) return false;
321
322            osg::Vec3 left, right, top,  bottom;
323            bool left_valid  = vertex(c-1, r,  left);
324            bool right_valid = vertex(c+1, r,   right);
325            bool bottom_valid = vertex(c,   r-1, bottom);
326            bool top_valid = vertex(c,   r+1, top);
327
328            osg::Vec3 dx(0.0f,0.0f,0.0f);
329            osg::Vec3 dy(0.0f,0.0f,0.0f);
330            osg::Vec3 zero(0.0f,0.0f,0.0f);
331            if (left_valid)
332            {
333                dx = center-left;
334            }
335            if (right_valid)
336            {
337                dx = right-center;
338            }
339            if (bottom_valid)
340            {
341                dy += center-bottom;
342            }
343            if (top_valid)
344            {
345                dy += top-center;
346            }
347
348            if (dx==zero || dy==zero) return false;
349
350            n = dx ^ dy;
351            return n.normalize() != 0.0f;
352        }
353
354        inline bool computeNormalWithDiagonals(int c, int r, osg::Vec3& n) const
355        {
356            osg::Vec3 center;
357            bool center_valid  = vertex(c, r,  center);
358            if (!center_valid) return false;
359
360            osg::Vec3 top_left, top_right, bottom_left, bottom_right;
361            bool top_left_valid  = vertex(c-1, r+1,  top_left);
362            bool top_right_valid  = vertex(c+1, r+1,  top_right);
363            bool bottom_left_valid  = vertex(c-1, r-1,  bottom_left);
364            bool bottom_right_valid  = vertex(c+1, r-1,  bottom_right);
365
366            osg::Vec3 left, right, top,  bottom;
367            bool left_valid  = vertex(c-1, r,  left);
368            bool right_valid = vertex(c+1, r,   right);
369            bool bottom_valid = vertex(c,   r-1, bottom);
370            bool top_valid = vertex(c,   r+1, top);
371
372            osg::Vec3 dx(0.0f,0.0f,0.0f);
373            osg::Vec3 dy(0.0f,0.0f,0.0f);
374            osg::Vec3 zero(0.0f,0.0f,0.0f);
375            const float ratio = 0.5f;
376            if (left_valid)
377            {
378                dx = center-left;
379                if (top_left_valid) dy += (top_left-left)*ratio;
380                if (bottom_left_valid) dy += (left-bottom_left)*ratio;
381            }
382            if (right_valid)
383            {
384                dx = right-center;
385                if (top_right_valid) dy += (top_right-right)*ratio;
386                if (bottom_right_valid) dy += (right-bottom_right)*ratio;
387            }
388            if (bottom_valid)
389            {
390                dy += center-bottom;
391                if (bottom_left_valid) dx += (bottom-bottom_left)*ratio;
392                if (bottom_right_valid) dx += (bottom_right-bottom)*ratio;
393            }
394            if (top_valid)
395            {
396                dy += top-center;
397                if (top_left_valid) dx += (top-top_left)*ratio;
398                if (top_right_valid) dx += (top_right-top)*ratio;
399            }
400
401            if (dx==zero || dy==zero) return false;
402
403            n = dx ^ dy;
404            return n.normalize() != 0.0f;
405        }
406
407        Locator*                        _masterLocator;
408        const osg::Vec3d                _centerModel;
409        int                             _numRows;
410        int                             _numColumns;
411        float                           _scaleHeight;
412
413        Indices                         _indices;
414
415        osg::ref_ptr<osg::Vec3Array>    _vertices;
416        osg::ref_ptr<osg::Vec3Array>    _normals;
417        osg::ref_ptr<osg::FloatArray>   _elevations;
418
419        osg::ref_ptr<osg::Vec3Array>    _boundaryVertices;
420
421};
422
423VertexNormalGenerator::VertexNormalGenerator(Locator* masterLocator, const osg::Vec3d& centerModel, int numRows, int numColumns, float scaleHeight, bool createSkirt):
424    _masterLocator(masterLocator),
425    _centerModel(centerModel),
426    _numRows(numRows),
427    _numColumns(numColumns),
428    _scaleHeight(scaleHeight)
429{
430    int numVerticesInBody = numColumns*numRows;
431    int numVerticesInSkirt = createSkirt ? numColumns*2 + numRows*2 - 4 : 0;
432    int numVertices = numVerticesInBody+numVerticesInSkirt;
433
434    _indices.resize((_numRows+2)*(_numColumns+2),0);
435
436    _vertices = new osg::Vec3Array;
437    _vertices->reserve(numVertices);
438
439    _normals = new osg::Vec3Array;
440    _normals->reserve(numVertices);
441
442    _elevations = new osg::FloatArray;
443    _elevations->reserve(numVertices);
444
445    _boundaryVertices = new osg::Vec3Array;
446    _boundaryVertices->reserve(_numRows*2 + _numColumns*2 + 4);
447}
448
449void VertexNormalGenerator::populateCenter(osgTerrain::Layer* elevationLayer, LayerToTexCoordMap& layerToTexCoordMap)
450{
451    // OSG_NOTICE<<std::endl<<"VertexNormalGenerator::populateCenter("<<elevationLayer<<")"<<std::endl;
452
453    bool sampled = elevationLayer &&
454                   ( (elevationLayer->getNumRows()!=static_cast<unsigned int>(_numRows)) ||
455                     (elevationLayer->getNumColumns()!=static_cast<unsigned int>(_numColumns)) );
456
457    for(int j=0; j<_numRows; ++j)
458    {
459        for(int i=0; i<_numColumns; ++i)
460        {
461            osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0);
462
463            bool validValue = true;
464            if (elevationLayer)
465            {
466                float value = 0.0f;
467                if (sampled) validValue = elevationLayer->getInterpolatedValidValue(ndc.x(), ndc.y(), value);
468                else validValue = elevationLayer->getValidValue(i,j,value);
469                ndc.z() = value*_scaleHeight;
470            }
471
472            if (validValue)
473            {
474                osg::Vec3d model;
475                _masterLocator->convertLocalToModel(ndc, model);
476
477                for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin();
478                    itr != layerToTexCoordMap.end();
479                    ++itr)
480                {
481                    osg::Vec2Array* texcoords = itr->second.first.get();
482                    osgTerrain::ImageLayer* imageLayer(dynamic_cast<osgTerrain::ImageLayer*>(itr->first));
483
484                    if (imageLayer != NULL)
485                    {
486                        Locator* colorLocator = itr->second.second;
487                        if (colorLocator != _masterLocator)
488                        {
489                            osg::Vec3d color_ndc;
490                            Locator::convertLocalCoordBetween(*_masterLocator, ndc, *colorLocator, color_ndc);
491                            (*texcoords).push_back(osg::Vec2(color_ndc.x(), color_ndc.y()));
492                        }
493                        else
494                        {
495                            (*texcoords).push_back(osg::Vec2(ndc.x(), ndc.y()));
496                        }
497                    }
498                    else
499                    {
500                        osgTerrain::ContourLayer* contourLayer(dynamic_cast<osgTerrain::ContourLayer*>(itr->first));
501
502                        bool texCoordSet = false;
503                        if (contourLayer)
504                        {
505                            osg::TransferFunction1D* transferFunction = contourLayer->getTransferFunction();
506                            if (transferFunction)
507                            {
508                                float difference = transferFunction->getMaximum()-transferFunction->getMinimum();
509                                if (difference != 0.0f)
510                                {
511                                    osg::Vec3d           color_ndc;
512                                    osgTerrain::Locator* colorLocator(itr->second.second);
513
514                                    if (colorLocator != _masterLocator)
515                                    {
516                                        Locator::convertLocalCoordBetween(*_masterLocator,ndc,*colorLocator,color_ndc);
517                                    }
518                                    else
519                                    {
520                                        color_ndc = ndc;
521                                    }
522
523                                    color_ndc[2] /= _scaleHeight;
524
525                                    (*texcoords).push_back(osg::Vec2((color_ndc[2]-transferFunction->getMinimum())/difference,0.0f));
526                                    texCoordSet = true;
527                                }
528                            }
529                        }
530                        if (!texCoordSet)
531                        {
532                            (*texcoords).push_back(osg::Vec2(0.0f,0.0f));
533                        }
534                    }
535                }
536
537                if (_elevations.valid())
538                {
539                    (*_elevations).push_back(ndc.z());
540                }
541
542                // compute the local normal
543                osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
544                osg::Vec3d model_one;
545                _masterLocator->convertLocalToModel(ndc_one, model_one);
546                model_one = model_one - model;
547                model_one.normalize();
548
549                setVertex(i, j, osg::Vec3(model-_centerModel), model_one);
550            }
551        }
552    }
553}
554
555void VertexNormalGenerator::populateLeftBoundary(osgTerrain::Layer* elevationLayer)
556{
557    // OSG_NOTICE<<"   VertexNormalGenerator::populateLeftBoundary("<<elevationLayer<<")"<<std::endl;
558
559    if (!elevationLayer) return;
560
561    bool sampled = elevationLayer &&
562                   ( (elevationLayer->getNumRows()!=static_cast<unsigned int>(_numRows)) ||
563                     (elevationLayer->getNumColumns()!=static_cast<unsigned int>(_numColumns)) );
564
565    for(int j=0; j<_numRows; ++j)
566    {
567        for(int i=-1; i<=0; ++i)
568        {
569            osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0);
570            osg::Vec3d left_ndc( 1.0+ndc.x(), ndc.y(), 0.0);
571
572            bool validValue = true;
573            if (elevationLayer)
574            {
575                float value = 0.0f;
576                if (sampled) validValue = elevationLayer->getInterpolatedValidValue(left_ndc.x(), left_ndc.y(), value);
577                else validValue = elevationLayer->getValidValue((_numColumns-1)+i,j,value);
578                ndc.z() = value*_scaleHeight;
579
580                ndc.z() += 0.f;
581            }
582            if (validValue)
583            {
584                osg::Vec3d model;
585                _masterLocator->convertLocalToModel(ndc, model);
586
587                // compute the local normal
588                osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
589                osg::Vec3d model_one;
590                _masterLocator->convertLocalToModel(ndc_one, model_one);
591                model_one = model_one - model;
592                model_one.normalize();
593
594                setVertex(i, j, osg::Vec3(model-_centerModel), model_one);
595                // OSG_NOTICE<<"       setVertex("<<i<<", "<<j<<"..)"<<std::endl;
596            }
597        }
598    }
599}
600
601void VertexNormalGenerator::populateRightBoundary(osgTerrain::Layer* elevationLayer)
602{
603    // OSG_NOTICE<<"   VertexNormalGenerator::populateRightBoundary("<<elevationLayer<<")"<<std::endl;
604
605    if (!elevationLayer) return;
606
607    bool sampled = elevationLayer &&
608                   ( (elevationLayer->getNumRows()!=static_cast<unsigned int>(_numRows)) ||
609                     (elevationLayer->getNumColumns()!=static_cast<unsigned int>(_numColumns)) );
610
611    for(int j=0; j<_numRows; ++j)
612    {
613        for(int i=_numColumns-1; i<_numColumns+1; ++i)
614        {
615            osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0);
616            osg::Vec3d right_ndc(ndc.x()-1.0, ndc.y(), 0.0);
617
618            bool validValue = true;
619            if (elevationLayer)
620            {
621                float value = 0.0f;
622                if (sampled) validValue = elevationLayer->getInterpolatedValidValue(right_ndc.x(), right_ndc.y(), value);
623                else validValue = elevationLayer->getValidValue(i-(_numColumns-1),j,value);
624                ndc.z() = value*_scaleHeight;
625            }
626
627            if (validValue)
628            {
629                osg::Vec3d model;
630                _masterLocator->convertLocalToModel(ndc, model);
631
632                // compute the local normal
633                osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
634                osg::Vec3d model_one;
635                _masterLocator->convertLocalToModel(ndc_one, model_one);
636                model_one = model_one - model;
637                model_one.normalize();
638
639                setVertex(i, j, osg::Vec3(model-_centerModel), model_one);
640                // OSG_NOTICE<<"       setVertex("<<i<<", "<<j<<"..)"<<std::endl;
641            }
642        }
643    }
644}
645
646void VertexNormalGenerator::populateAboveBoundary(osgTerrain::Layer* elevationLayer)
647{
648    // OSG_NOTICE<<"   VertexNormalGenerator::populateAboveBoundary("<<elevationLayer<<")"<<std::endl;
649
650    if (!elevationLayer) return;
651
652    bool sampled = elevationLayer &&
653                   ( (elevationLayer->getNumRows()!=static_cast<unsigned int>(_numRows)) ||
654                     (elevationLayer->getNumColumns()!=static_cast<unsigned int>(_numColumns)) );
655
656    for(int j=_numRows-1; j<_numRows+1; ++j)
657    {
658        for(int i=0; i<_numColumns; ++i)
659        {
660            osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0);
661            osg::Vec3d above_ndc( ndc.x(), ndc.y()-1.0, 0.0);
662
663            bool validValue = true;
664            if (elevationLayer)
665            {
666                float value = 0.0f;
667                if (sampled) validValue = elevationLayer->getInterpolatedValidValue(above_ndc.x(), above_ndc.y(), value);
668                else validValue = elevationLayer->getValidValue(i,j-(_numRows-1),value);
669                ndc.z() = value*_scaleHeight;
670            }
671
672            if (validValue)
673            {
674                osg::Vec3d model;
675                _masterLocator->convertLocalToModel(ndc, model);
676
677                // compute the local normal
678                osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
679                osg::Vec3d model_one;
680                _masterLocator->convertLocalToModel(ndc_one, model_one);
681                model_one = model_one - model;
682                model_one.normalize();
683
684                setVertex(i, j, osg::Vec3(model-_centerModel), model_one);
685                // OSG_NOTICE<<"       setVertex("<<i<<", "<<j<<"..)"<<std::endl;
686            }
687        }
688    }
689}
690
691void VertexNormalGenerator::populateBelowBoundary(osgTerrain::Layer* elevationLayer)
692{
693    // OSG_NOTICE<<"   VertexNormalGenerator::populateBelowBoundary("<<elevationLayer<<")"<<std::endl;
694
695    if (!elevationLayer) return;
696
697    bool sampled = elevationLayer &&
698                   ( (elevationLayer->getNumRows()!=static_cast<unsigned int>(_numRows)) ||
699                     (elevationLayer->getNumColumns()!=static_cast<unsigned int>(_numColumns)) );
700
701    for(int j=-1; j<=0; ++j)
702    {
703        for(int i=0; i<_numColumns; ++i)
704        {
705            osg::Vec3d ndc( ((double)i)/(double)(_numColumns-1), ((double)j)/(double)(_numRows-1), 0.0);
706            osg::Vec3d below_ndc( ndc.x(), 1.0+ndc.y(), 0.0);
707
708            bool validValue = true;
709            if (elevationLayer)
710            {
711                float value = 0.0f;
712                if (sampled) validValue = elevationLayer->getInterpolatedValidValue(below_ndc.x(), below_ndc.y(), value);
713                else validValue = elevationLayer->getValidValue(i,(_numRows-1)+j,value);
714                ndc.z() = value*_scaleHeight;
715            }
716
717            if (validValue)
718            {
719                osg::Vec3d model;
720                _masterLocator->convertLocalToModel(ndc, model);
721
722                // compute the local normal
723                osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
724                osg::Vec3d model_one;
725                _masterLocator->convertLocalToModel(ndc_one, model_one);
726                model_one = model_one - model;
727                model_one.normalize();
728
729                setVertex(i, j, osg::Vec3(model-_centerModel), model_one);
730                // OSG_NOTICE<<"       setVertex("<<i<<", "<<j<<"..)"<<std::endl;
731            }
732        }
733    }
734}
735
736
737void VertexNormalGenerator::computeNormals()
738{
739    // compute normals for the center section
740    for(int j=0; j<_numRows; ++j)
741    {
742        for(int i=0; i<_numColumns; ++i)
743        {
744            int vi = vertex_index(i, j);
745            if (vi>=0) computeNormal(i, j, (*_normals)[vi]);
746            else OSG_NOTICE<<"Not computing normal, vi="<<vi<<std::endl;
747        }
748    }
749}
750
751void GeometryTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, const osg::Vec3d& centerModel)
752{
753    Terrain* terrain = _terrainTile->getTerrain();
754    osgTerrain::Layer* elevationLayer = _terrainTile->getElevationLayer();
755
756
757    buffer._geode = new osg::Geode;
758    if(buffer._transform.valid())
759        buffer._transform->addChild(buffer._geode.get());
760
761    buffer._geometry = new osg::Geometry;
762    buffer._geode->addDrawable(buffer._geometry.get());
763
764    osg::Geometry* geometry = buffer._geometry.get();
765
766    unsigned int numRows = 20;
767    unsigned int numColumns = 20;
768
769    if (elevationLayer)
770    {
771        numColumns = elevationLayer->getNumColumns();
772        numRows = elevationLayer->getNumRows();
773    }
774
775    float sampleRatio = terrain ? terrain->getSampleRatio() : 1.0f;
776
777    double i_sampleFactor = 1.0;
778    double j_sampleFactor = 1.0;
779
780    // OSG_NOTICE<<"Sample ratio="<<sampleRatio<<std::endl;
781
782    unsigned int minimumNumColumns = 16u;
783    unsigned int minimumNumRows = 16u;
784
785    if ((sampleRatio!=1.0f) && (numColumns>minimumNumColumns) && (numRows>minimumNumRows))
786    {
787        unsigned int originalNumColumns = numColumns;
788        unsigned int originalNumRows = numRows;
789   
790        numColumns = std::max((unsigned int) (float(originalNumColumns)*sqrtf(sampleRatio)), minimumNumColumns);
791        numRows = std::max((unsigned int) (float(originalNumRows)*sqrtf(sampleRatio)),minimumNumRows);
792
793        i_sampleFactor = double(originalNumColumns-1)/double(numColumns-1);
794        j_sampleFactor = double(originalNumRows-1)/double(numRows-1);
795    }
796   
797   
798
799    bool treatBoundariesToValidDataAsDefaultValue = _terrainTile->getTreatBoundariesToValidDataAsDefaultValue();
800    OSG_INFO<<"TreatBoundariesToValidDataAsDefaultValue="<<treatBoundariesToValidDataAsDefaultValue<<std::endl;
801   
802    float skirtHeight = 0.0f;
803    HeightFieldLayer* hfl = dynamic_cast<HeightFieldLayer*>(elevationLayer);
804    if (hfl && hfl->getHeightField())
805    {
806        skirtHeight = hfl->getHeightField()->getSkirtHeight();
807    }
808   
809    bool createSkirt = skirtHeight != 0.0f;
810
811
812    float scaleHeight = terrain ? terrain->getVerticalScale() : 1.0f;
813
814    // construct the VertexNormalGenerator which will manage the generation and the vertices and normals
815    VertexNormalGenerator VNG(masterLocator, centerModel, numRows, numColumns, scaleHeight, createSkirt);
816
817    unsigned int numVertices = VNG.capacity();
818
819    // allocate and assign vertices
820    geometry->setVertexArray(VNG._vertices.get());
821
822    // allocate and assign normals
823    geometry->setNormalArray(VNG._normals.get());
824    geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
825
826
827    // allocate and assign tex coords
828    // typedef std::pair< osg::ref_ptr<osg::Vec2Array>, Locator* > TexCoordLocatorPair;
829    // typedef std::map< Layer*, TexCoordLocatorPair > LayerToTexCoordMap;
830
831    VertexNormalGenerator::LayerToTexCoordMap layerToTexCoordMap;
832    for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum)
833    {
834        osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(layerNum);
835        if (colorLayer)
836        {
837            VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.find(colorLayer);
838            if (itr!=layerToTexCoordMap.end())
839            {
840                geometry->setTexCoordArray(layerNum, itr->second.first.get());
841            }
842            else
843            {
844
845                Locator* locator = colorLayer->getLocator();
846                if (!locator)
847                {
848                    osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(colorLayer);
849                    if (switchLayer)
850                    {
851                        if (switchLayer->getActiveLayer()>=0 &&
852                            static_cast<unsigned int>(switchLayer->getActiveLayer())<switchLayer->getNumLayers() &&
853                            switchLayer->getLayer(switchLayer->getActiveLayer()))
854                        {
855                            locator = switchLayer->getLayer(switchLayer->getActiveLayer())->getLocator();
856                        }
857                    }
858                }
859
860                VertexNormalGenerator::TexCoordLocatorPair& tclp = layerToTexCoordMap[colorLayer];
861                tclp.first = new osg::Vec2Array;
862                tclp.first->reserve(numVertices);
863                tclp.second = locator ? locator : masterLocator;
864                geometry->setTexCoordArray(layerNum, tclp.first.get());
865            }
866        }
867    }
868
869    // allocate and assign color
870    osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
871    (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);
872   
873    geometry->setColorArray(colors.get());
874    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
875
876    //
877    // populate vertex and tex coord arrays
878    //
879    VNG.populateCenter(elevationLayer, layerToTexCoordMap);
880
881    if (terrain && terrain->getEqualizeBoundaries())
882    {
883        TileID tileID = _terrainTile->getTileID();
884
885        osg::ref_ptr<TerrainTile> left_tile  = terrain->getTile(TileID(tileID.level, tileID.x-1, tileID.y));
886        osg::ref_ptr<TerrainTile> right_tile = terrain->getTile(TileID(tileID.level, tileID.x+1, tileID.y));
887        osg::ref_ptr<TerrainTile> top_tile = terrain->getTile(TileID(tileID.level, tileID.x, tileID.y+1));
888        osg::ref_ptr<TerrainTile> bottom_tile = terrain->getTile(TileID(tileID.level, tileID.x, tileID.y-1));
889
890#if 0
891        osg::ref_ptr<TerrainTile> top_left_tile  = terrain->getTile(TileID(tileID.level, tileID.x-1, tileID.y+1));
892        osg::ref_ptr<TerrainTile> top_right_tile = terrain->getTile(TileID(tileID.level, tileID.x+1, tileID.y+1));
893        osg::ref_ptr<TerrainTile> bottom_left_tile = terrain->getTile(TileID(tileID.level, tileID.x-1, tileID.y-1));
894        osg::ref_ptr<TerrainTile> bottom_right_tile = terrain->getTile(TileID(tileID.level, tileID.x+1, tileID.y-1));
895#endif
896        VNG.populateLeftBoundary(left_tile.valid() ? left_tile->getElevationLayer() : 0);
897        VNG.populateRightBoundary(right_tile.valid() ? right_tile->getElevationLayer() : 0);
898        VNG.populateAboveBoundary(top_tile.valid() ? top_tile->getElevationLayer() : 0);
899        VNG.populateBelowBoundary(bottom_tile.valid() ? bottom_tile->getElevationLayer() : 0);
900
901        _neighbours.clear();
902
903        bool updateNeighboursImmediately = false;
904
905        if (left_tile.valid())   addNeighbour(left_tile.get());
906        if (right_tile.valid())  addNeighbour(right_tile.get());
907        if (top_tile.valid())    addNeighbour(top_tile.get());
908        if (bottom_tile.valid()) addNeighbour(bottom_tile.get());
909
910#if 0
911        if (bottom_left_tile.valid()) addNeighbour(bottom_left_tile.get());
912        if (bottom_right_tile.valid()) addNeighbour(bottom_right_tile.get());
913        if (top_left_tile.valid()) addNeighbour(top_left_tile.get());
914        if (top_right_tile.valid()) addNeighbour(top_right_tile.get());
915#endif
916
917        if (left_tile.valid())
918        {
919            if (!(left_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
920            {
921                int dirtyMask = left_tile->getDirtyMask() | TerrainTile::LEFT_EDGE_DIRTY;
922                if (updateNeighboursImmediately) left_tile->init(dirtyMask, true);
923                else left_tile->setDirtyMask(dirtyMask);
924            }
925        }
926        if (right_tile.valid())
927        {
928            if (!(right_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
929            {
930                int dirtyMask = right_tile->getDirtyMask() | TerrainTile::RIGHT_EDGE_DIRTY;
931                if (updateNeighboursImmediately) right_tile->init(dirtyMask, true);
932                else right_tile->setDirtyMask(dirtyMask);
933            }
934        }
935        if (top_tile.valid())
936        {
937            if (!(top_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
938            {
939                int dirtyMask = top_tile->getDirtyMask() | TerrainTile::TOP_EDGE_DIRTY;
940                if (updateNeighboursImmediately) top_tile->init(dirtyMask, true);
941                else top_tile->setDirtyMask(dirtyMask);
942            }
943        }
944
945        if (bottom_tile.valid())
946        {
947            if (!(bottom_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
948            {
949                int dirtyMask = bottom_tile->getDirtyMask() | TerrainTile::BOTTOM_EDGE_DIRTY;
950                if (updateNeighboursImmediately) bottom_tile->init(dirtyMask, true);
951                else bottom_tile->setDirtyMask(dirtyMask);
952            }
953        }
954
955#if 0
956        if (bottom_left_tile.valid())
957        {
958            if (!(bottom_left_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
959            {
960                int dirtyMask = bottom_left_tile->getDirtyMask() | TerrainTile::BOTTOM_LEFT_CORNER_DIRTY;
961                if (updateNeighboursImmediately) bottom_left_tile->init(dirtyMask, true);
962                else bottom_left_tile->setDirtyMask(dirtyMask);
963            }
964        }
965
966        if (bottom_right_tile.valid())
967        {
968            if (!(bottom_right_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
969            {
970                int dirtyMask = bottom_right_tile->getDirtyMask() | TerrainTile::BOTTOM_RIGHT_CORNER_DIRTY;
971                if (updateNeighboursImmediately) bottom_right_tile->init(dirtyMask, true);
972                else bottom_right_tile->setDirtyMask(dirtyMask);
973            }
974        }
975
976        if (top_right_tile.valid())
977        {
978            if (!(top_right_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
979            {
980                int dirtyMask = top_right_tile->getDirtyMask() | TerrainTile::TOP_RIGHT_CORNER_DIRTY;
981                if (updateNeighboursImmediately) top_right_tile->init(dirtyMask, true);
982                else top_right_tile->setDirtyMask(dirtyMask);
983            }
984        }
985
986        if (top_left_tile.valid())
987        {
988            if (!(top_left_tile->getTerrainTechnique()->containsNeighbour(_terrainTile)))
989            {
990                int dirtyMask = top_left_tile->getDirtyMask() | TerrainTile::TOP_LEFT_CORNER_DIRTY;
991                if (updateNeighboursImmediately) top_left_tile->init(dirtyMask, true);
992                else top_left_tile->setDirtyMask(dirtyMask);
993            }
994        }
995#endif
996    }
997
998
999    osg::ref_ptr<osg::Vec3Array> skirtVectors = new osg::Vec3Array((*VNG._normals));
1000    VNG.computeNormals();
1001
1002    //
1003    // populate the primitive data
1004    //
1005    bool swapOrientation = !(masterLocator->orientationOpenGL());
1006    bool smallTile = numVertices <= 16384;
1007
1008    // OSG_NOTICE<<"smallTile = "<<smallTile<<std::endl;
1009
1010    osg::ref_ptr<osg::DrawElements> elements = smallTile ?
1011        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_TRIANGLES)) :
1012        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_TRIANGLES));
1013
1014    elements->reserveElements((numRows-1) * (numColumns-1) * 6);
1015
1016    geometry->addPrimitiveSet(elements.get());
1017
1018
1019    unsigned int i, j;
1020    for(j=0; j<numRows-1; ++j)
1021    {
1022        for(i=0; i<numColumns-1; ++i)
1023        {
1024            // remap indices to final vertex positions
1025            int i00 = VNG.vertex_index(i,   j);
1026            int i01 = VNG.vertex_index(i,   j+1);
1027            int i10 = VNG.vertex_index(i+1, j);
1028            int i11 = VNG.vertex_index(i+1, j+1);
1029
1030            if (swapOrientation)
1031            {
1032                std::swap(i00,i01);
1033                std::swap(i10,i11);
1034            }
1035
1036            unsigned int numValid = 0;
1037            if (i00>=0) ++numValid;
1038            if (i01>=0) ++numValid;
1039            if (i10>=0) ++numValid;
1040            if (i11>=0) ++numValid;
1041
1042            if (numValid==4)
1043            {
1044                // optimize which way to put the diagonal by choosing to
1045                // place it between the two corners that have the least curvature
1046                // relative to each other.
1047                float dot_00_11 = (*VNG._normals)[i00] * (*VNG._normals)[i11];
1048                float dot_01_10 = (*VNG._normals)[i01] * (*VNG._normals)[i10];
1049                if (dot_00_11 > dot_01_10)
1050                {
1051                    elements->addElement(i01);
1052                    elements->addElement(i00);
1053                    elements->addElement(i11);
1054
1055                    elements->addElement(i00);
1056                    elements->addElement(i10);
1057                    elements->addElement(i11);
1058                }
1059                else
1060                {
1061                    elements->addElement(i01);
1062                    elements->addElement(i00);
1063                    elements->addElement(i10);
1064
1065                    elements->addElement(i01);
1066                    elements->addElement(i10);
1067                    elements->addElement(i11);
1068                }
1069            }
1070            else if (numValid==3)
1071            {
1072                if (i00>=0) elements->addElement(i00);
1073                if (i01>=0) elements->addElement(i01);
1074                if (i11>=0) elements->addElement(i11);
1075                if (i10>=0) elements->addElement(i10);
1076            }
1077        }
1078    }
1079
1080
1081    if (createSkirt)
1082    {
1083        osg::ref_ptr<osg::Vec3Array> vertices = VNG._vertices.get();
1084        osg::ref_ptr<osg::Vec3Array> normals = VNG._normals.get();
1085
1086        osg::ref_ptr<osg::DrawElements> skirtDrawElements = smallTile ?
1087            static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1088            static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1089
1090        // create bottom skirt vertices
1091        int r,c;
1092        r=0;
1093        for(c=0;c<static_cast<int>(numColumns);++c)
1094        {
1095            int orig_i = VNG.vertex_index(c,r);
1096            if (orig_i>=0)
1097            {
1098                unsigned int new_i = vertices->size(); // index of new index of added skirt point
1099                osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
1100                (*vertices).push_back(new_v);
1101                if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
1102
1103                for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin();
1104                    itr != layerToTexCoordMap.end();
1105                    ++itr)
1106                {
1107                    itr->second.first->push_back((*itr->second.first)[orig_i]);
1108                }
1109
1110                skirtDrawElements->addElement(orig_i);
1111                skirtDrawElements->addElement(new_i);
1112            }
1113            else
1114            {
1115                if (skirtDrawElements->getNumIndices()!=0)
1116                {
1117                    geometry->addPrimitiveSet(skirtDrawElements.get());
1118                    skirtDrawElements = smallTile ?
1119                        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1120                        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1121                }
1122
1123            }
1124        }
1125
1126        if (skirtDrawElements->getNumIndices()!=0)
1127        {
1128            geometry->addPrimitiveSet(skirtDrawElements.get());
1129            skirtDrawElements = smallTile ?
1130                        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1131                        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1132        }
1133
1134        // create right skirt vertices
1135        c=numColumns-1;
1136        for(r=0;r<static_cast<int>(numRows);++r)
1137        {
1138            int orig_i = VNG.vertex_index(c,r); // index of original vertex of grid
1139            if (orig_i>=0)
1140            {
1141                unsigned int new_i = vertices->size(); // index of new index of added skirt point
1142                osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
1143                (*vertices).push_back(new_v);
1144                if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
1145                for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin();
1146                    itr != layerToTexCoordMap.end();
1147                    ++itr)
1148                {
1149                    itr->second.first->push_back((*itr->second.first)[orig_i]);
1150                }
1151
1152                skirtDrawElements->addElement(orig_i);
1153                skirtDrawElements->addElement(new_i);
1154            }
1155            else
1156            {
1157                if (skirtDrawElements->getNumIndices()!=0)
1158                {
1159                    geometry->addPrimitiveSet(skirtDrawElements.get());
1160                    skirtDrawElements = smallTile ?
1161                        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1162                        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1163                }
1164
1165            }
1166        }
1167
1168        if (skirtDrawElements->getNumIndices()!=0)
1169        {
1170            geometry->addPrimitiveSet(skirtDrawElements.get());
1171            skirtDrawElements = smallTile ?
1172                        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1173                        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1174        }
1175
1176        // create top skirt vertices
1177        r=numRows-1;
1178        for(c=numColumns-1;c>=0;--c)
1179        {
1180            int orig_i = VNG.vertex_index(c,r); // index of original vertex of grid
1181            if (orig_i>=0)
1182            {
1183                unsigned int new_i = vertices->size(); // index of new index of added skirt point
1184                osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
1185                (*vertices).push_back(new_v);
1186                if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
1187                for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin();
1188                    itr != layerToTexCoordMap.end();
1189                    ++itr)
1190                {
1191                    itr->second.first->push_back((*itr->second.first)[orig_i]);
1192                }
1193
1194                skirtDrawElements->addElement(orig_i);
1195                skirtDrawElements->addElement(new_i);
1196            }
1197            else
1198            {
1199                if (skirtDrawElements->getNumIndices()!=0)
1200                {
1201                    geometry->addPrimitiveSet(skirtDrawElements.get());
1202                    skirtDrawElements = smallTile ?
1203                        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1204                        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1205                }
1206
1207            }
1208        }
1209
1210        if (skirtDrawElements->getNumIndices()!=0)
1211        {
1212            geometry->addPrimitiveSet(skirtDrawElements.get());
1213            skirtDrawElements = smallTile ?
1214                        static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_QUAD_STRIP)) :
1215                        static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_QUAD_STRIP));
1216        }
1217
1218        // create left skirt vertices
1219        c=0;
1220        for(r=numRows-1;r>=0;--r)
1221        {
1222            int orig_i = VNG.vertex_index(c,r); // index of original vertex of grid
1223            if (orig_i>=0)
1224            {
1225                unsigned int new_i = vertices->size(); // index of new index of added skirt point
1226                osg::Vec3 new_v = (*vertices)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight;
1227                (*vertices).push_back(new_v);
1228                if (normals.valid()) (*normals).push_back((*normals)[orig_i]);
1229                for(VertexNormalGenerator::LayerToTexCoordMap::iterator itr = layerToTexCoordMap.begin();
1230                    itr != layerToTexCoordMap.end();
1231                    ++itr)
1232                {
1233                    itr->second.first->push_back((*itr->second.first)[orig_i]);
1234                }
1235
1236                skirtDrawElements->addElement(orig_i);
1237                skirtDrawElements->addElement(new_i);
1238            }
1239            else
1240            {
1241                if (skirtDrawElements->getNumIndices()!=0)
1242                {
1243                    geometry->addPrimitiveSet(skirtDrawElements.get());
1244                    skirtDrawElements = new osg::DrawElementsUShort(GL_QUAD_STRIP);
1245                }
1246            }
1247        }
1248
1249        if (skirtDrawElements->getNumIndices()!=0)
1250        {
1251            geometry->addPrimitiveSet(skirtDrawElements.get());
1252        }
1253    }
1254
1255
1256    geometry->setUseDisplayList(false);
1257    geometry->setUseVertexBufferObjects(true);
1258
1259#if 0
1260    {
1261        osgUtil::VertexCacheMissVisitor vcmv_before;
1262        osgUtil::VertexCacheMissVisitor vcmv_after;
1263        osgUtil::VertexCacheVisitor vcv;
1264        osgUtil::VertexAccessOrderVisitor vaov;
1265
1266        vcmv_before.doGeometry(*geometry);
1267        vcv.optimizeVertices(*geometry);
1268        vaov.optimizeOrder(*geometry);
1269        vcmv_after.doGeometry(*geometry);
1270#if 0
1271        OSG_NOTICE<<"vcmv_before.triangles="<<vcmv_before.triangles<<std::endl;
1272        OSG_NOTICE<<"vcmv_before.misses="<<vcmv_before.misses<<std::endl;
1273        OSG_NOTICE<<"vcmv_after.misses="<<vcmv_after.misses<<std::endl;
1274        OSG_NOTICE<<std::endl;
1275#endif
1276    }
1277#endif
1278
1279    if (osgDB::Registry::instance()->getBuildKdTreesHint()==osgDB::ReaderWriter::Options::BUILD_KDTREES &&
1280        osgDB::Registry::instance()->getKdTreeBuilder())
1281    {
1282
1283        //osg::Timer_t before = osg::Timer::instance()->tick();
1284        //OSG_NOTICE<<"osgTerrain::GeometryTechnique::build kd tree"<<std::endl;
1285        osg::ref_ptr<osg::KdTreeBuilder> builder = osgDB::Registry::instance()->getKdTreeBuilder()->clone();
1286        buffer._geode->accept(*builder);
1287        //osg::Timer_t after = osg::Timer::instance()->tick();
1288        //OSG_NOTICE<<"KdTree build time "<<osg::Timer::instance()->delta_m(before, after)<<std::endl;
1289    }
1290}
1291
1292void GeometryTechnique::applyColorLayers(BufferData& buffer)
1293{
1294    typedef std::map<osgTerrain::Layer*, osg::Texture*> LayerToTextureMap;
1295    LayerToTextureMap layerToTextureMap;
1296   
1297    for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum)
1298    {
1299        osgTerrain::Layer* colorLayer = _terrainTile->getColorLayer(layerNum);
1300        if (!colorLayer) continue;
1301
1302        osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(colorLayer);
1303        if (switchLayer)
1304        {
1305            if (switchLayer->getActiveLayer()<0 ||
1306                static_cast<unsigned int>(switchLayer->getActiveLayer())>=switchLayer->getNumLayers())
1307            {
1308                continue;
1309            }
1310
1311            colorLayer = switchLayer->getLayer(switchLayer->getActiveLayer());
1312            if (!colorLayer) continue;
1313        }
1314
1315        osg::Image* image = colorLayer->getImage();
1316        if (!image) continue;
1317
1318        osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(colorLayer);
1319        osgTerrain::ContourLayer* contourLayer = dynamic_cast<osgTerrain::ContourLayer*>(colorLayer);
1320        if (imageLayer)
1321        {
1322            osg::StateSet* stateset = buffer._geode->getOrCreateStateSet();
1323
1324            osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(layerToTextureMap[colorLayer]);
1325            if (!texture2D)
1326            {
1327                texture2D = new osg::Texture2D;
1328                texture2D->setImage(image);
1329                texture2D->setMaxAnisotropy(16.0f);
1330                texture2D->setResizeNonPowerOfTwoHint(false);
1331
1332                texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter());
1333                texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter());
1334
1335                texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
1336                texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
1337
1338                bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST);
1339                bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1));
1340                bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1));
1341
1342                if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo))
1343                {
1344                    OSG_INFO<<"Disabling mipmapping for non power of two tile size("<<image->s()<<", "<<image->t()<<")"<<std::endl;
1345                    texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
1346                }
1347
1348
1349                layerToTextureMap[colorLayer] = texture2D;
1350
1351                // OSG_NOTICE<<"Creating new ImageLayer texture "<<layerNum<<" image->s()="<<image->s()<<"  image->t()="<<image->t()<<std::endl;
1352
1353            }
1354            else
1355            {
1356                // OSG_NOTICE<<"Reusing ImageLayer texture "<<layerNum<<std::endl;
1357            }
1358
1359            stateset->setTextureAttributeAndModes(layerNum, texture2D, osg::StateAttribute::ON);
1360           
1361        }
1362        else if (contourLayer)
1363        {
1364            osg::StateSet* stateset = buffer._geode->getOrCreateStateSet();
1365
1366            osg::Texture1D* texture1D = dynamic_cast<osg::Texture1D*>(layerToTextureMap[colorLayer]);
1367            if (!texture1D)
1368            {
1369                texture1D = new osg::Texture1D;
1370                texture1D->setImage(image);
1371                texture1D->setResizeNonPowerOfTwoHint(false);
1372                texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
1373                texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter());
1374
1375                layerToTextureMap[colorLayer] = texture1D;
1376            }
1377           
1378            stateset->setTextureAttributeAndModes(layerNum, texture1D, osg::StateAttribute::ON);
1379
1380        }
1381    }
1382}
1383
1384void GeometryTechnique::applyTransparency(BufferData& buffer)
1385{
1386    TerrainTile::BlendingPolicy blendingPolicy = _terrainTile->getBlendingPolicy();
1387    if (blendingPolicy == TerrainTile::INHERIT && _terrainTile->getTerrain())
1388    {
1389        OSG_INFO<<"GeometryTechnique::applyTransparency() inheriting policy from Terrain"<<std::endl;
1390        blendingPolicy = _terrainTile->getTerrain()->getBlendingPolicy();
1391    }
1392
1393    if (blendingPolicy == TerrainTile::INHERIT)
1394    {
1395        OSG_INFO<<"GeometryTechnique::applyTransparency() policy is INHERIT, defaulting to ENABLE_BLENDING_WHEN_ALPHA_PRESENT"<<std::endl;
1396        blendingPolicy = TerrainTile::ENABLE_BLENDING_WHEN_ALPHA_PRESENT;
1397    }
1398
1399    if (blendingPolicy == TerrainTile::DO_NOT_SET_BLENDING)
1400    {
1401        OSG_INFO<<"blendingPolicy == TerrainTile::DO_NOT_SET_BLENDING"<<std::endl;
1402        return;
1403    }
1404
1405    bool enableBlending = false;
1406
1407    if (blendingPolicy == TerrainTile::ENABLE_BLENDING)
1408    {
1409        OSG_INFO<<"blendingPolicy == TerrainTile::ENABLE_BLENDING"<<std::endl;
1410        enableBlending = true;
1411    }
1412    else if (blendingPolicy == TerrainTile::ENABLE_BLENDING_WHEN_ALPHA_PRESENT)
1413    {
1414        OSG_INFO<<"blendingPolicy == TerrainTile::ENABLE_BLENDING_WHEN_ALPHA_PRESENT"<<std::endl;
1415        for(unsigned int i=0; i<_terrainTile->getNumColorLayers(); ++i)
1416        {
1417            osg::Image* image = (_terrainTile->getColorLayer(i)!=0) ? _terrainTile->getColorLayer(i)->getImage() : 0;
1418            if (image)
1419            {
1420                enableBlending = image->isImageTranslucent();
1421                break;
1422            }
1423        }
1424    }
1425
1426    if (enableBlending)
1427    {
1428        osg::StateSet* stateset = buffer._geode->getOrCreateStateSet();
1429        stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
1430        stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1431    }
1432
1433}
1434
1435void GeometryTechnique::update(osgUtil::UpdateVisitor* uv)
1436{
1437    if (_terrainTile) _terrainTile->osg::Group::traverse(*uv);
1438
1439    if (_newBufferData.valid())
1440    {
1441        _currentBufferData = _newBufferData;
1442        _newBufferData = 0;
1443    }
1444}
1445
1446
1447void GeometryTechnique::cull(osgUtil::CullVisitor* cv)
1448{
1449    if (_currentBufferData.valid())
1450    {
1451        if (_currentBufferData->_transform.valid())
1452        {
1453            _currentBufferData->_transform->accept(*cv);
1454        }
1455    }
1456}
1457
1458
1459void GeometryTechnique::traverse(osg::NodeVisitor& nv)
1460{
1461    if (!_terrainTile) return;
1462
1463    // if app traversal update the frame count.
1464    if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
1465    {
1466        if (_terrainTile->getDirty()) _terrainTile->init(_terrainTile->getDirtyMask(), false);
1467
1468        osgUtil::UpdateVisitor* uv = dynamic_cast<osgUtil::UpdateVisitor*>(&nv);
1469        if (uv)
1470        {
1471            update(uv);
1472            return;
1473        }
1474    }
1475    else if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
1476    {
1477        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
1478        if (cv)
1479        {
1480            cull(cv);
1481            return;
1482        }
1483    }
1484
1485
1486    if (_terrainTile->getDirty())
1487    {
1488        OSG_INFO<<"******* Doing init ***********"<<std::endl;
1489        _terrainTile->init(_terrainTile->getDirtyMask(), false);
1490    }
1491
1492    if (_currentBufferData.valid())
1493    {
1494        if (_currentBufferData->_transform.valid()) _currentBufferData->_transform->accept(nv);
1495    }
1496}
1497
1498
1499void GeometryTechnique::cleanSceneGraph()
1500{
1501}
1502
1503void GeometryTechnique::releaseGLObjects(osg::State* state) const
1504{
1505    if (_currentBufferData.valid() && _currentBufferData->_transform.valid()) _currentBufferData->_transform->releaseGLObjects(state);
1506    if (_newBufferData.valid() && _newBufferData->_transform.valid()) _newBufferData->_transform->releaseGLObjects(state);
1507}
Note: See TracBrowser for help on using the browser.