1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 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/GeometryPool>
15 #include <osg/Texture1D>
16 #include <osg/Texture2D>
17 #include <osgDB/ReadFile>
18 
19 using namespace osgTerrain;
20 
computeMasterLocator(const osgTerrain::TerrainTile * tile)21 const osgTerrain::Locator* osgTerrain::computeMasterLocator(const osgTerrain::TerrainTile* tile)
22 {
23     const osgTerrain::Layer* elevationLayer = tile->getElevationLayer();
24     const osgTerrain::Layer* colorLayer = tile->getColorLayer(0);
25 
26     const Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0;
27     const Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0;
28 
29     const Locator* masterLocator = elevationLocator ? elevationLocator : colorLocator;
30     if (!masterLocator)
31     {
32         OSG_NOTICE<<"Problem, no locator found in any of the terrain layers"<<std::endl;
33         return 0;
34     }
35 
36     return masterLocator;
37 }
38 
39 
40 /////////////////////////////////////////////////////////////////////////////////////////////////////////
41 //
42 //  GeometryPool
43 //
GeometryPool()44 GeometryPool::GeometryPool():
45     _rootStateSetAssigned(false)
46 
47 {
48     _rootStateSet = new osg::StateSet;
49 }
50 
~GeometryPool()51 GeometryPool::~GeometryPool()
52 {
53 }
54 
createKeyForTile(TerrainTile * tile,GeometryKey & key)55 bool GeometryPool::createKeyForTile(TerrainTile* tile, GeometryKey& key)
56 {
57     const osgTerrain::Locator* masterLocator = computeMasterLocator(tile);
58     if (masterLocator)
59     {
60         const osg::Matrixd& matrix = masterLocator->getTransform();
61         osg::Vec3d bottom_left = osg::Vec3d(0.0,0.0,0.0) * matrix;
62         osg::Vec3d bottom_right = osg::Vec3d(1.0,0.0,0.0) * matrix;
63         osg::Vec3d top_left = osg::Vec3d(1.0,1.0,0.0) * matrix;
64         key.sx = static_cast<float>((bottom_right-bottom_left).length());
65         key.sy = static_cast<float>((top_left-bottom_left).length());
66 
67         if (masterLocator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC)
68         {
69             // need to differentiate between tiles based of latitude, so use y position of bottom left corner.
70             key.y = static_cast<float>(bottom_left.y());
71         }
72         else
73         {
74             // when the projection is linear there is no need to differentiate tiles according to their latitude
75             key.y = 0.0;
76         }
77 
78     }
79 
80     osgTerrain::HeightFieldLayer* layer = dynamic_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer());
81     if (layer)
82     {
83         osg::HeightField* hf = layer->getHeightField();
84         if (hf)
85         {
86             key.nx = hf->getNumColumns();
87             key.ny = hf->getNumRows();
88         }
89     }
90     return true;
91 }
92 
getOrCreateGeometry(osgTerrain::TerrainTile * tile)93 osg::ref_ptr<SharedGeometry> GeometryPool::getOrCreateGeometry(osgTerrain::TerrainTile* tile)
94 {
95     OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_geometryMapMutex);
96 
97     GeometryKey key;
98     createKeyForTile(tile, key);
99 
100     GeometryMap::iterator itr = _geometryMap.find(key);
101     if (itr != _geometryMap.end())
102     {
103         return itr->second.get();
104     }
105 
106     osg::ref_ptr<SharedGeometry> geometry = new SharedGeometry;
107     _geometryMap[key] = geometry;
108 
109     geometry->setUseVertexBufferObjects(true);
110 
111     osg::ref_ptr<osg::VertexBufferObject> vbo = new osg::VertexBufferObject;
112 
113     SharedGeometry::VertexToHeightFieldMapping& vthfm = geometry->getVertexToHeightFieldMapping();
114 
115     osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array(osg::Array::BIND_PER_VERTEX);
116     vertices->setVertexBufferObject(vbo.get());
117     geometry->setVertexArray(vertices.get());
118 
119     osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array(osg::Array::BIND_PER_VERTEX);
120     normals->setVertexBufferObject(vbo.get());
121     geometry->setNormalArray(normals.get());
122 
123     osg::ref_ptr<osg::Vec4Array> colours = new osg::Vec4Array(osg::Array::BIND_OVERALL);
124     geometry->setColorArray(colours.get());
125     colours->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
126 
127     osg::ref_ptr<osg::Vec4Array> texcoords = new osg::Vec4Array(osg::Array::BIND_PER_VERTEX);
128     texcoords->setVertexBufferObject(vbo.get());
129     geometry->setTexCoordArray(texcoords.get());
130 
131 
132 
133     int nx = key.nx;
134     int ny = key.nx;
135 
136     int numVerticesMainBody = nx * ny;
137     int numVerticesSkirt = (nx)*2 + (ny)*2;
138     int numVertices = numVerticesMainBody + numVerticesSkirt;
139 
140     vertices->reserve(numVertices);
141     normals->reserve(numVertices);
142     texcoords->reserve(numVertices);
143     vthfm.reserve(numVertices);
144 
145     double c_mult = 1.0/static_cast<double>(nx-1);
146     double r_mult = 1.0/static_cast<double>(ny-1);
147 
148     typedef std::vector<osg::Vec4d> LocationCoords;
149     LocationCoords locationCoords;
150     locationCoords.reserve(numVertices);
151 
152     osg::Vec3d pos(0.0, 0.0, 0.0);
153     osg::Vec3d normal(0.0, 0.0, 1.0);
154     osg::Vec2 delta(1.0f/static_cast<float>(nx), 1.0f/static_cast<float>(ny));
155 
156     // pass in the delta texcoord per texel via the color array
157     (*colours)[0].x() = c_mult;
158     (*colours)[0].y() = r_mult;
159 
160 
161 
162     osg::Matrixd matrix;
163     const osgTerrain::Locator* locator = computeMasterLocator(tile);
164     if (locator)
165     {
166         matrix = locator->getTransform();
167     }
168 
169     // compute the size of the skirtHeight
170     osg::Vec3d bottom_left(0.0,0.0,0.0);
171     osg::Vec3d top_right(1.0,1.0,0.0);
172 
173     // transform for unit coords to local coords of the tile
174     bottom_left = bottom_left * matrix;
175     top_right = top_right * matrix;
176 
177     // if we have a geocentric database then transform into geocentric coords.
178     const osg::EllipsoidModel* em = locator->getEllipsoidModel();
179     if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC)
180     {
181         // note y axis maps to latitude, x axis to longitude
182         em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(), bottom_left.z());
183         em->convertLatLongHeightToXYZ(top_right.y(), top_right.x(), top_right.z(), top_right.x(), top_right.y(), top_right.z());
184     }
185 
186     double diagonalLength = (top_right-bottom_left).length();
187     double skirtRatio = 0.02;
188     double skirtHeight = -diagonalLength*skirtRatio;
189 
190 
191     // set up the vertex data
192     {
193         // bottom row for skirt
194         pos.y () = static_cast<double>(0)*r_mult;
195         pos.z() = skirtHeight;
196         for(int c=0; c<nx; ++c)
197         {
198             pos.x() = static_cast<double>(c)*c_mult;
199             vertices->push_back(pos);
200             normals->push_back(normal);
201             texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
202             locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
203             vthfm.push_back(0*nx + c);
204         }
205 
206         // main body
207         for(int r=0; r<ny; ++r)
208         {
209             pos.y () = static_cast<double>(r)*r_mult;
210 
211             // start skirt vertex
212             pos.z() = skirtHeight;
213             {
214                 pos.x() = static_cast<double>(0)*c_mult;
215                 vertices->push_back(pos);
216                 normals->push_back(normal);
217                 texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
218                 locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
219                 vthfm.push_back(r*nx + 0);
220             }
221 
222             pos.z() = 0;
223             for(int c=0; c<nx; ++c)
224             {
225                 pos.x() = static_cast<double>(c)*c_mult;
226                 vertices->push_back(pos);
227                 normals->push_back(normal);
228                 texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
229                 locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
230                 vthfm.push_back(r*nx + c);
231             }
232 
233             // end skirt vertex
234             pos.z() = skirtHeight;
235             {
236                 pos.x() = static_cast<double>(nx-1)*c_mult;
237                 vertices->push_back(pos);
238                 normals->push_back(normal);
239                 texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
240                 locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
241                 vthfm.push_back((r+1)*nx-1);
242             }
243 
244         }
245 
246         // top row skirt
247         pos.y () = static_cast<double>(ny-1)*r_mult;
248         pos.z() = skirtHeight;
249         for(int c=0; c<nx; ++c)
250         {
251             pos.x() = static_cast<double>(c)*c_mult;
252             vertices->push_back(pos);
253             normals->push_back(normal);
254             texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
255             locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
256             vthfm.push_back((ny-1)*nx + c);
257         }
258     }
259 
260 #if 0
261 
262     bool smallTile = numVertices <= 16384;
263     osg::ref_ptr<osg::DrawElements> elements = smallTile ?
264         static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(GL_TRIANGLE_STRIP)) :
265         static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(GL_TRIANGLE_STRIP));
266 
267     elements->reserveElements( (nx-1) * (ny-1) * 2 + (nx-1)*2*2 + (ny-1)*2*2 +(ny)*2);
268     geometry->addPrimitiveSet(elements.get());
269 
270 
271     // first row containing the skirt
272     int il = 0;
273     int iu = 0;
274     for(int c=0; c<nx; ++c)
275     {
276         il = c;
277         iu = il+nx+1;
278         elements->addElement(iu);
279         elements->addElement(il);
280     }
281     elements->addElement(il);
282 
283     // center section
284     for(int r=0; r<ny-1; ++r)
285     {
286         il = nx+r*(nx+2);
287         iu = il+nx+2;
288         elements->addElement(iu);
289         for(int c=0; c<nx+2; ++c)
290         {
291             il = c+nx+r*(nx+2);
292             iu = il+nx+2;
293             elements->addElement(iu);
294             elements->addElement(il);
295         }
296         elements->addElement(il);
297     }
298 
299     // top row containing skirt
300     il = nx+(ny-1)*(nx+2)+1;
301     iu = il+nx+1;
302     elements->addElement(iu);
303     for(int c=0; c<nx; ++c)
304     {
305         il = c+nx+(ny-1)*(nx+2)+1;
306         iu = il+nx+1;
307         elements->addElement(iu);
308         elements->addElement(il);
309     }
310 
311 #else
312     bool smallTile = numVertices <= 16384;
313 
314     GLenum primitiveTypes = GL_QUADS;
315 
316     osg::ref_ptr<osg::DrawElements> elements = smallTile ?
317         static_cast<osg::DrawElements*>(new osg::DrawElementsUShort(primitiveTypes)) :
318         static_cast<osg::DrawElements*>(new osg::DrawElementsUInt(primitiveTypes));
319 
320     elements->reserveElements( (nx-1) * (ny-1) * 4 + (nx-1)*2*4 + (ny-1)*2*4 );
321     elements->setElementBufferObject(new osg::ElementBufferObject());
322     geometry->setDrawElements(elements.get());
323 
324 
325     // first row containing the skirt
326     for(int c=0; c<nx-1; ++c)
327     {
328         int il = c;
329         int iu = il+nx+1;
330         elements->addElement(il);
331         elements->addElement(il+1);
332         elements->addElement(iu+1);
333         elements->addElement(iu);
334     }
335 
336     // center section
337     for(int r=0; r<ny-1; ++r)
338     {
339         for(int c=0; c<nx+1; ++c)
340         {
341             int il = c+nx+r*(nx+2);
342             int iu = il+nx+2;
343             elements->addElement(il);
344             elements->addElement(il+1);
345             elements->addElement(iu+1);
346             elements->addElement(iu);
347         }
348     }
349 
350     // top row containing skirt
351     for(int c=0; c<nx-1; ++c)
352     {
353         int il = c+nx+(ny-1)*(nx+2)+1;
354         int iu = il+nx+1;
355         elements->addElement(il);
356         elements->addElement(il+1);
357         elements->addElement(iu+1);
358         elements->addElement(iu);
359     }
360 #endif
361     if (locator)
362     {
363         matrix = locator->getTransform();
364 
365         osg::Vec3d center(0.5, 0.5, 0.0);
366 
367         osg::Vec3d bottom_left(0.0,0.0,0.0);
368         osg::Vec3d bottom_right(1.0,0.0,0.0);
369         osg::Vec3d top_left(0.0,1.0,0.0);
370 
371         center = center * matrix;
372         bottom_left = bottom_left * matrix;
373         bottom_right = bottom_right * matrix;
374         top_left = top_left * matrix;
375 
376         // shift to center.x() to x=0 and carry all the corners with it.
377         bottom_left.x() -= center.x();
378         bottom_right.x() -= center.x();
379         top_left.x() -= center.x();
380         //center.x() = 0.0;
381 
382  //       OSG_NOTICE<<"   in lat/longs : bottom_left = "<<bottom_left<<std::endl;
383  //       OSG_NOTICE<<"   in lat/longs : bottom_right = "<<bottom_right<<std::endl;
384  //       OSG_NOTICE<<"   in lat/longs : top_left = "<<top_left<<std::endl;
385 
386         const osg::EllipsoidModel* em = locator->getEllipsoidModel();
387         if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC)
388         {
389             osg::Matrixd localToWorldTransform;
390             // note y axis maps to latitude, x axis to longitude
391             em->computeLocalToWorldTransformFromLatLongHeight(center.y(), center.x(), center.z(), localToWorldTransform);
392  //           OSG_NOTICE<<"We have a EllipsoidModel to take account of "<<localToWorldTransform<<std::endl;
393 
394             // note y axis maps to latitude, x axis to longitude
395             em->convertLatLongHeightToXYZ(center.y(), center.x(), center.z(), center.x(), center.y(),center.z());
396             em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(),bottom_left.z());
397             em->convertLatLongHeightToXYZ(bottom_right.y(), bottom_right.x(), bottom_right.z(), bottom_right.x(), bottom_right.y(),bottom_right.z());
398             em->convertLatLongHeightToXYZ(top_left.y(), top_left.x(), top_left.z(), top_left.x(), top_left.y(),top_left.z());
399 
400             osg::Matrixd worldToLocalTransform;
401             worldToLocalTransform.invert(localToWorldTransform);
402 
403             center = center * worldToLocalTransform;
404             bottom_left = bottom_left * worldToLocalTransform;
405             bottom_right = bottom_right * worldToLocalTransform;
406             top_left = top_left * worldToLocalTransform;
407 
408 
409             for(int i=0; i<numVertices; ++i)
410             {
411                 const osg::Vec4d& location = locationCoords[i];
412                 double height = (*vertices)[i].z();
413                 osg::Vec3d pos = osg::Vec3d(location.x(), location.y(), 0.0) * matrix;
414                 em->convertLatLongHeightToXYZ(pos.y(), pos.x(), height, pos.x(), pos.y(),pos.z());
415 
416                 osg::Vec4& tc = (*texcoords)[i];
417 
418                 osg::Vec3d pos_right = osg::Vec3d(location.x()+location[2], location.y(), 0.0) * matrix;
419                 em->convertLatLongHeightToXYZ(pos_right.y(), pos_right.x(), height, pos_right.x(), pos_right.y(),pos_right.z());
420 
421                 osg::Vec3d pos_up = osg::Vec3d(location.x(), location.y()+location[3], 0.0) * matrix;
422                 em->convertLatLongHeightToXYZ(pos_up.y(), pos_up.x(), height, pos_up.x(), pos_up.y(),pos_up.z());
423 
424                 double length_right = (pos_right-pos).length();
425                 double length_up = (pos_up-pos).length();
426                 tc[2] = 1.0/length_right;
427                 tc[3] = 1.0/length_up;
428 
429 
430                 osg::Vec3d normal(pos);
431                 normal = osg::Matrixd::transform3x3(localToWorldTransform, normal);
432                 normal.normalize();
433 
434                 pos = pos * worldToLocalTransform;
435                 pos -= center;
436 
437                 (*vertices)[i] = pos;
438                 (*normals)[i] = normal;
439 
440             }
441 
442         }
443     }
444 
445     // double tileWidth = (bottom_right-bottom_left).length();
446     // double skirtHeight = tileWidth*0.05;
447 
448  //   OSG_NOTICE<<"   in local coords : center = "<<center<<std::endl;
449  //   OSG_NOTICE<<"   in local coords : bottom_left = "<<bottom_left<<std::endl;
450  //   OSG_NOTICE<<"   in local coords : bottom_right = "<<bottom_right<<std::endl;
451  //   OSG_NOTICE<<"   in local coords : top_left = "<<top_left<<std::endl;
452  //   OSG_NOTICE<<"   skirtHeight = "<<skirtHeight<<std::endl;
453 
454 
455     //osgDB::writeNodeFile(*geometry, "geometry.osgt");
456 
457 //    OSG_NOTICE<<"Creating new geometry "<<geometry.get()<<std::endl;
458 
459     return geometry;
460 }
461 
getTileSubgraph(osgTerrain::TerrainTile * tile)462 osg::ref_ptr<osg::MatrixTransform> GeometryPool::getTileSubgraph(osgTerrain::TerrainTile* tile)
463 {
464     // create or reuse Geometry
465     osg::ref_ptr<SharedGeometry> geometry = getOrCreateGeometry(tile);
466 
467 
468     osg::ref_ptr<HeightFieldDrawable> hfDrawable = new HeightFieldDrawable();
469 
470     osgTerrain::HeightFieldLayer* hfl = dynamic_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer());
471     osg::HeightField* hf = hfl ? hfl->getHeightField() : 0;
472     hfDrawable->setHeightField(hf);
473     hfDrawable->setGeometry(geometry.get());
474 
475 
476     // create a transform to place the geometry in the appropriate place
477     osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;
478 
479 //    transform->addChild(geometry.get());
480     transform->addChild(hfDrawable.get());
481 
482     const osgTerrain::Locator* locator = computeMasterLocator(tile);
483     if (locator)
484     {
485         osg::Matrixd matrix = locator->getTransform();
486 
487         osg::Vec3d center = osg::Vec3d(0.5, 0.5, 0.0) * matrix;
488 
489         // shift to center.x() to x=0 and carry all the corners with it.
490         const osg::EllipsoidModel* em = locator->getEllipsoidModel();
491         if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC)
492         {
493             osg::Matrixd localToWorldTransform;
494             // note y axis maps to latitude, x axis to longitude
495             em->computeLocalToWorldTransformFromLatLongHeight(center.y(), center.x(), center.z(), localToWorldTransform);
496  //           OSG_NOTICE<<"We have a EllipsoidModel to take account of "<<localToWorldTransform<<std::endl;
497 
498             transform->setMatrix(localToWorldTransform);
499 
500             //osgDB::writeNodeFile(*transform, "subgraph.osgt");
501         }
502         else
503         {
504             transform->setMatrix(locator->getTransform());
505         }
506     }
507 
508     osg::Vec3Array* shared_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
509     osg::Vec3Array* shared_normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
510     osg::FloatArray* heights = hf->getFloatArray();
511     const SharedGeometry::VertexToHeightFieldMapping& vthfm = geometry->getVertexToHeightFieldMapping();
512 
513     if (hf && shared_vertices && shared_normals && (shared_vertices->size()==shared_normals->size()))
514     {
515         if (vthfm.size()==shared_vertices->size())
516         {
517             // Using cache VertexArray
518             unsigned int numVertices = shared_vertices->size();
519             osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
520             vertices->resize(numVertices);
521 
522             for(unsigned int i=0; i<numVertices; ++i)
523             {
524                 unsigned int hi = vthfm[i];
525                 (*vertices)[i] = (*shared_vertices)[i] + (*shared_normals)[i] * (*heights)[hi];
526             }
527 
528             hfDrawable->setVertices(vertices.get());
529         }
530         else
531         {
532             // Setting local bounding
533             unsigned int nr = hf->getNumRows();
534             unsigned int nc = hf->getNumColumns();
535 
536             osg::BoundingBox bb;
537 
538             for(unsigned int r=0; r<nr; ++r)
539             {
540                 for(unsigned int c=0; c<nc; ++c)
541                 {
542                     unsigned int i = r*nc+c;
543                     float h = (*heights)[i];
544                     const osg::Vec3& v = (*shared_vertices)[i];
545                     const osg::Vec3& n = (*shared_normals)[i];
546 
547                     const osg::Vec3 vt(v+n*h);
548                     bb.expandBy(vt);
549                 }
550             }
551             hfDrawable->setInitialBound(bb);
552             // OSG_NOTICE<<"Assigning initial bound ("<<bb.xMin()<<", "<<bb.xMax()<<") ,  ("<<bb.yMin()<<", "<<bb.yMax()<<") ("<<bb.zMin()<<", "<<bb.zMax()<<")"<< std::endl;
553             // bb = hfDrawable->getBoundingBox();
554             //OSG_NOTICE<<"         getBoundingBox ("<<bb.xMin()<<", "<<bb.xMax()<<") ,  ("<<bb.yMin()<<", "<<bb.yMax()<<") ("<<bb.zMin()<<", "<<bb.zMax()<<")"<< std::endl;
555 
556         }
557     }
558 
559     osg::ref_ptr<osg::StateSet> stateset = transform->getOrCreateStateSet();
560 
561     // apply colour layers
562     applyLayers(tile, stateset.get());
563 
564     return transform;
565 }
566 
getOrCreateProgram(LayerTypes & layerTypes)567 osg::ref_ptr<osg::Program> GeometryPool::getOrCreateProgram(LayerTypes& layerTypes)
568 {
569     //OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_programMapMutex);
570     ProgramMap::iterator itr = _programMap.find(layerTypes);
571     if (itr!=_programMap.end())
572     {
573         // OSG_NOTICE<<") returning existing Program "<<itr->second.get()<<std::endl;
574         return itr->second.get();
575     }
576 
577 #if 1
578     unsigned int num_HeightField = 0;
579     unsigned int num_Color = 0;
580     unsigned int num_Contour = 0;
581     for(LayerTypes::iterator itr = layerTypes.begin();
582         itr != layerTypes.end();
583         ++itr)
584     {
585         switch(*itr)
586         {
587             case(HEIGHTFIELD_LAYER): ++num_HeightField; break;
588             case(COLOR_LAYER): ++num_Color; break;
589             case(CONTOUR_LAYER): ++num_Contour; break;
590         }
591     }
592     OSG_NOTICE<<"getOrCreateProgram()"<<std::endl;
593 
594     OSG_NOTICE<<"    HeightField "<<num_HeightField<<std::endl;
595     OSG_NOTICE<<"    Color "<<num_Color<<std::endl;
596     OSG_NOTICE<<"    Contour "<<num_Contour<<std::endl;
597 
598 #endif
599 
600     osg::ref_ptr<osg::Program> program = new osg::Program;
601     _programMap[layerTypes] = program;
602 
603     // add shader that provides the lighting functions
604     program->addShader(osgDB::readRefShaderFile("shaders/lighting.vert"));
605 
606     // OSG_NOTICE<<") creating new Program "<<program.get()<<std::endl;
607     {
608         #include "shaders/terrain_displacement_mapping_vert.cpp"
609         program->addShader(osgDB::readRefShaderFileWithFallback(osg::Shader::VERTEX, "shaders/terrain_displacement_mapping.vert", terrain_displacement_mapping_vert));
610     }
611 
612 
613     {
614         #include "shaders/terrain_displacement_mapping_geom.cpp"
615         program->addShader(osgDB::readRefShaderFileWithFallback(osg::Shader::GEOMETRY, "shaders/terrain_displacement_mapping.geom", terrain_displacement_mapping_geom));
616 
617         program->setParameter( GL_GEOMETRY_VERTICES_OUT, 4 );
618         program->setParameter( GL_GEOMETRY_INPUT_TYPE, GL_LINES_ADJACENCY );
619         program->setParameter( GL_GEOMETRY_OUTPUT_TYPE, GL_TRIANGLE_STRIP);
620     }
621 
622     if (num_Contour>0)
623     {
624         OSG_NOTICE<<"No support for Contour yet."<<std::endl;
625     }
626 
627     {
628         #include "shaders/terrain_displacement_mapping_frag.cpp"
629         program->addShader(osgDB::readRefShaderFileWithFallback(osg::Shader::FRAGMENT, "shaders/terrain_displacement_mapping.frag", terrain_displacement_mapping_frag));
630     }
631 
632     return program;
633 }
634 
applyLayers(osgTerrain::TerrainTile * tile,osg::StateSet * stateset)635 void GeometryPool::applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset)
636 {
637     typedef std::map<osgTerrain::Layer*, osg::Texture*> LayerToTextureMap;
638     LayerToTextureMap layerToTextureMap;
639 
640  //   OSG_NOTICE<<"tile->getNumColorLayers() = "<<tile->getNumColorLayers()<<std::endl;
641 
642     LayerTypes layerTypes;
643 
644     osgTerrain::HeightFieldLayer* hfl = dynamic_cast<osgTerrain::HeightFieldLayer*>(tile->getElevationLayer());
645     if (hfl)
646     {
647         osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(layerToTextureMap[hfl]);
648         if (!texture2D)
649         {
650             texture2D = new osg::Texture2D;
651 
652             osg::ref_ptr<osg::Image> image = new osg::Image;
653 
654             const void* dataPtr = hfl->getHeightField()->getFloatArray()->getDataPointer();
655 
656             image->setImage(hfl->getNumRows(), hfl->getNumColumns(), 1,
657                       GL_LUMINANCE32F_ARB,
658                       GL_LUMINANCE, GL_FLOAT,
659                       reinterpret_cast<unsigned char*>(const_cast<void*>(dataPtr)),
660                       osg::Image::NO_DELETE);
661 
662             texture2D->setImage(image.get());
663             texture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
664             texture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
665             texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
666             texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
667             texture2D->setBorderColor(osg::Vec4d(0.0,0.0,0.0,0.0));
668             texture2D->setResizeNonPowerOfTwoHint(false);
669 
670             layerToTextureMap[hfl] = texture2D;
671         }
672 
673         int textureUnit = layerTypes.size();
674         stateset->setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON);
675         stateset->addUniform(new osg::Uniform("terrainTexture",textureUnit));
676 
677         layerTypes.push_back(HEIGHTFIELD_LAYER);
678     }
679 #if 1
680     int colorLayerNum = 0;
681     for(unsigned int layerNum=0; layerNum<tile->getNumColorLayers(); ++layerNum)
682     {
683         osgTerrain::Layer* colorLayer = tile->getColorLayer(layerNum);
684         if (!colorLayer) continue;
685 
686         osgTerrain::SwitchLayer* switchLayer = dynamic_cast<osgTerrain::SwitchLayer*>(colorLayer);
687         if (switchLayer)
688         {
689             if (switchLayer->getActiveLayer()<0 ||
690                 static_cast<unsigned int>(switchLayer->getActiveLayer())>=switchLayer->getNumLayers())
691             {
692                 continue;
693             }
694 
695             colorLayer = switchLayer->getLayer(switchLayer->getActiveLayer());
696             if (!colorLayer) continue;
697         }
698 
699         osg::Image* image = colorLayer->getImage();
700         if (!image) continue;
701 
702         osgTerrain::ImageLayer* imageLayer = dynamic_cast<osgTerrain::ImageLayer*>(colorLayer);
703         osgTerrain::ContourLayer* contourLayer = dynamic_cast<osgTerrain::ContourLayer*>(colorLayer);
704         if (imageLayer)
705         {
706             osg::Texture2D* texture2D = dynamic_cast<osg::Texture2D*>(layerToTextureMap[colorLayer]);
707             if (!texture2D)
708             {
709                 texture2D = new osg::Texture2D;
710                 texture2D->setImage(image);
711                 texture2D->setMaxAnisotropy(16.0f);
712                 texture2D->setResizeNonPowerOfTwoHint(false);
713 
714                 texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter());
715                 texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter());
716 
717                 texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE);
718                 texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE);
719 
720                 bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST);
721                 bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1));
722                 bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1));
723 
724                 if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo))
725                 {
726                     OSG_INFO<<"Disabling mipmapping for non power of two tile size("<<image->s()<<", "<<image->t()<<")"<<std::endl;
727                     texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
728                 }
729 
730 
731                 layerToTextureMap[colorLayer] = texture2D;
732 
733                 // OSG_NOTICE<<"Creating new ImageLayer texture "<<layerNum<<" image->s()="<<image->s()<<"  image->t()="<<image->t()<<std::endl;
734 
735             }
736             else
737             {
738                 // OSG_NOTICE<<"Reusing ImageLayer texture "<<layerNum<<std::endl;
739             }
740 
741             int textureUnit = layerTypes.size();
742             stateset->setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON);
743 
744             std::stringstream str;
745             str<<"colorTexture"<<colorLayerNum;
746             stateset->addUniform(new osg::Uniform(str.str().c_str(),textureUnit));
747 
748             layerTypes.push_back(COLOR_LAYER);
749 
750             ++colorLayerNum;
751 
752         }
753         else if (contourLayer)
754         {
755             OSG_NOTICE<<"Warning : GeometryPool does not presently support ContourLayers."<<std::endl;
756         }
757     }
758 #endif
759 
760 
761     // If we have a root StateSet assigned for Terrain?
762     //   If tile_LayerTypes a subset of root_LayerTypes then toggle on/off locally
763     //   If tile_LayerTypes a superset of root_LayerTypes then create local Program
764     //   else no need to set anything
765     // else no root StateSet
766     //    create new StateSet for Program required and assigned with layers required enabled
767     //
768 
769 
770 
771     //stateset->setDefine("GL_LIGHTING", osg::StateAttribute::ON);
772     {
773         OpenThreads::ScopedLock<OpenThreads::Mutex>  lock(_programMapMutex);
774         if (!_rootStateSetAssigned)
775         {
776             _rootStateSetAssigned = true;
777 
778             _rootStateSet->setDefine("LIGHTING");
779 
780             int num_Color = 0;
781             for(LayerTypes::iterator itr = layerTypes.begin();
782                 itr != layerTypes.end();
783                 ++itr)
784             {
785                 switch(*itr)
786                 {
787                     case(HEIGHTFIELD_LAYER): _rootStateSet->setDefine("HEIGHTFIELD_LAYER"); break;
788                     case(COLOR_LAYER): ++num_Color; break;
789                     case(CONTOUR_LAYER): break; // not supported right now
790                 }
791             }
792 
793             if (num_Color>=1)
794             {
795                 _rootStateSet->setDefine("TEXTURE_2D");
796                 _rootStateSet->setDefine("COLOR_LAYER0");
797             }
798 
799             if (num_Color>=2) _rootStateSet->setDefine("COLOR_LAYER1");
800             if (num_Color>=3) _rootStateSet->setDefine("COLOR_LAYER2");
801 
802             osg::ref_ptr<osg::Program> program = getOrCreateProgram(layerTypes);
803             if (program.valid())
804             {
805                 _rootStateSet->setAttribute(program.get());
806             }
807         }
808     }
809 }
810 
getRootStateSetForTerrain(Terrain * terrain)811 osg::StateSet* GeometryPool::getRootStateSetForTerrain(Terrain* terrain)
812 {
813     //OSG_NOTICE<<"getRootStateSetForTerrain("<<terrain<<")"<<std::endl;
814     return _rootStateSet.get();
815 }
816 
817 /////////////////////////////////////////////////////////////////////////////////////////////////////////
818 //
819 //  SharedGeometry
820 //
SharedGeometry()821 SharedGeometry::SharedGeometry()
822 {
823     setSupportsDisplayList(false);
824     _supportsVertexBufferObjects = true;
825 }
826 
SharedGeometry(const SharedGeometry & rhs,const osg::CopyOp & copyop)827 SharedGeometry::SharedGeometry(const SharedGeometry& rhs,const osg::CopyOp& copyop):
828     osg::Drawable(rhs, copyop),
829     _vertexArray(rhs._vertexArray),
830     _normalArray(rhs._normalArray),
831     _colorArray(rhs._colorArray),
832     _texcoordArray(rhs._texcoordArray),
833     _drawElements(rhs._drawElements),
834     _vertexToHeightFieldMapping(rhs._vertexToHeightFieldMapping)
835 {
836 //    setSupportsDisplayList(false);
837 }
838 
~SharedGeometry()839 SharedGeometry::~SharedGeometry()
840 {
841 }
842 
compileGLObjects(osg::RenderInfo & renderInfo) const843 void SharedGeometry::compileGLObjects(osg::RenderInfo& renderInfo) const
844 {
845     if (!_vertexArray) return;
846     if (_vertexArray->getVertexBufferObject())
847     {
848         osg::State& state = *renderInfo.getState();
849         unsigned int contextID = state.getContextID();
850         osg::GLExtensions* extensions = state.get<osg::GLExtensions>();
851         if (!extensions) return;
852 
853         {
854             osg::BufferObject* vbo = _vertexArray->getVertexBufferObject();
855             osg::GLBufferObject* glBufferObject = vbo->getOrCreateGLBufferObject(contextID);
856             if (glBufferObject && glBufferObject->isDirty())
857             {
858                 // OSG_NOTICE<<"Compile buffer "<<glBufferObject<<std::endl;
859                 glBufferObject->compileBuffer();
860             }
861         }
862 
863         {
864             osg::BufferObject* ebo = _drawElements->getElementBufferObject();
865             osg::GLBufferObject* glBufferObject = ebo->getOrCreateGLBufferObject(contextID);
866             if (glBufferObject && glBufferObject->isDirty())
867             {
868                 // OSG_NOTICE<<"Compile buffer "<<glBufferObject<<std::endl;
869                 glBufferObject->compileBuffer();
870             }
871         }
872 
873         // unbind the BufferObjects
874         extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,0);
875         extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,0);
876     }
877     else
878     {
879         Drawable::compileGLObjects(renderInfo);
880     }
881 }
882 
resizeGLObjectBuffers(unsigned int maxSize)883 void SharedGeometry::resizeGLObjectBuffers(unsigned int maxSize)
884 {
885     Drawable::resizeGLObjectBuffers(maxSize);
886 
887     osg::BufferObject* vbo = _vertexArray->getVertexBufferObject();
888     if (vbo) vbo->resizeGLObjectBuffers(maxSize);
889 
890     osg::BufferObject* ebo = _drawElements->getElementBufferObject();
891     if (ebo) ebo->resizeGLObjectBuffers(maxSize);
892 }
893 
releaseGLObjects(osg::State * state) const894 void SharedGeometry::releaseGLObjects(osg::State* state) const
895 {
896     Drawable::releaseGLObjects(state);
897 
898     osg::BufferObject* vbo = _vertexArray->getVertexBufferObject();
899     if (vbo) vbo->releaseGLObjects(state);
900 
901     osg::BufferObject* ebo = _drawElements->getElementBufferObject();
902     if (ebo) ebo->releaseGLObjects(state);
903 }
904 
drawImplementation(osg::RenderInfo & renderInfo) const905 void SharedGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
906 {
907     bool computeDiagonals = renderInfo.getState()->supportsShaderRequirement("COMPUTE_DIAGONALS");
908     //OSG_NOTICE<<"SharedGeometry "<<computeDiagonals<<std::endl;
909 
910     osg::State& state = *renderInfo.getState();
911 
912 
913     // state.checkGLErrors("Before SharedGeometry::drawImplementation.");
914 
915 
916     bool checkForGLErrors = state.getCheckForGLErrors()==osg::State::ONCE_PER_ATTRIBUTE;
917     if (checkForGLErrors) state.checkGLErrors("start of SharedGeometry::drawImplementation()");
918 
919     osg::ArrayDispatchers& arrayDispatchers = state.getArrayDispatchers();
920 
921     arrayDispatchers.reset();
922     arrayDispatchers.setUseVertexAttribAlias(state.getUseVertexAttributeAliasing());
923 
924     arrayDispatchers.activateNormalArray(_normalArray.get());
925     arrayDispatchers.activateColorArray(_colorArray.get());
926 
927     // dispatch any attributes that are bound overall
928     arrayDispatchers.dispatch(osg::Array::BIND_OVERALL,0);
929 
930     state.lazyDisablingOfVertexAttributes();
931 
932     // set up arrays
933     if( _vertexArray.valid() )
934         state.setVertexPointer(_vertexArray.get());
935 
936     if (_normalArray.valid() && _normalArray->getBinding()==osg::Array::BIND_PER_VERTEX)
937         state.setNormalPointer(_normalArray.get());
938 
939     if (_colorArray.valid() && _colorArray->getBinding()==osg::Array::BIND_PER_VERTEX)
940         state.setColorPointer(_colorArray.get());
941 
942     if (_texcoordArray.valid() && _texcoordArray->getBinding()==osg::Array::BIND_PER_VERTEX)
943         state.setTexCoordPointer(0, _texcoordArray.get());
944 
945     state.applyDisablingOfVertexAttributes();
946 
947     if (checkForGLErrors) state.checkGLErrors("Geometry::drawImplementation() after vertex arrays setup.");
948 
949     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
950     //
951     // draw the primitives themselves.
952     //
953     GLenum primitiveType = computeDiagonals ? GL_LINES_ADJACENCY : GL_QUADS;
954 
955     osg::GLBufferObject* ebo = _drawElements->getOrCreateGLBufferObject(state.getContextID());
956     state.bindElementBufferObject(ebo);
957 
958     glDrawElements(primitiveType, _drawElements->getNumIndices(), _drawElements->getDataType(), (const GLvoid *)(ebo->getOffset(_drawElements->getBufferIndex())));
959 
960 
961     // unbind the VBO's if any are used.
962     state.unbindVertexBufferObject();
963     state.unbindElementBufferObject();
964 
965 #if 0
966     if (computeDiagonals)
967     {
968         if (state.checkGLErrors("End of SharedGeometry::drawImplementation. computeDiagonals=TRUE")) {}
969         else OSG_NOTICE<<"SharedGeometry::drawImplementation. OK computeDiagonals=TRUE"<<std::endl;
970     }
971     else
972     {
973         if (state.checkGLErrors("End of SharedGeometry::drawImplementation. computeDiagonals=FALSE")) {}
974         else OSG_NOTICE<<"SharedGeometry::drawImplementation. OK computeDiagonals=FALSE"<<std::endl;
975     }
976 #endif
977 
978     if (checkForGLErrors) state.checkGLErrors("end of SharedGeometry::drawImplementation().");
979 }
980 
accept(osg::Drawable::AttributeFunctor & af)981 void SharedGeometry::accept(osg::Drawable::AttributeFunctor& af)
982 {
983     osg::AttributeFunctorArrayVisitor afav(af);
984 
985     afav.applyArray(VERTICES,_vertexArray.get());
986     afav.applyArray(NORMALS, _normalArray.get());
987     afav.applyArray(COLORS, _colorArray.get());
988     afav.applyArray(TEXTURE_COORDS_0,_texcoordArray.get());
989 }
990 
accept(osg::Drawable::ConstAttributeFunctor & af) const991 void SharedGeometry::accept(osg::Drawable::ConstAttributeFunctor& af) const
992 {
993     osg::ConstAttributeFunctorArrayVisitor afav(af);
994 
995     afav.applyArray(VERTICES,_vertexArray.get());
996     afav.applyArray(NORMALS, _normalArray.get());
997     afav.applyArray(COLORS, _colorArray.get());
998     afav.applyArray(TEXTURE_COORDS_0,_texcoordArray.get());
999 }
1000 
accept(osg::PrimitiveFunctor & pf) const1001 void SharedGeometry::accept(osg::PrimitiveFunctor& pf) const
1002 {
1003     pf.setVertexArray(_vertexArray->getNumElements(),static_cast<const osg::Vec3*>(_vertexArray->getDataPointer()));
1004 
1005     _drawElements->accept(pf);
1006 }
1007 
accept(osg::PrimitiveIndexFunctor & pif) const1008 void SharedGeometry::accept(osg::PrimitiveIndexFunctor& pif) const
1009 {
1010     pif.setVertexArray(_vertexArray->getNumElements(),static_cast<const osg::Vec3*>(_vertexArray->getDataPointer()));
1011 
1012     _drawElements->accept(pif);
1013 }
1014 
1015 
1016 /////////////////////////////////////////////////////////////////////////////////////////////////////////
1017 //
1018 //  HeightFieldDrawable
1019 //
HeightFieldDrawable()1020 HeightFieldDrawable::HeightFieldDrawable()
1021 {
1022     setSupportsDisplayList(false);
1023 }
1024 
HeightFieldDrawable(const HeightFieldDrawable & rhs,const osg::CopyOp & copyop)1025 HeightFieldDrawable::HeightFieldDrawable(const HeightFieldDrawable& rhs,const osg::CopyOp& copyop):
1026     osg::Drawable(rhs, copyop),
1027     _heightField(rhs._heightField),
1028     _geometry(rhs._geometry),
1029     _vertices(rhs._vertices)
1030 {
1031     setSupportsDisplayList(false);
1032 }
1033 
~HeightFieldDrawable()1034 HeightFieldDrawable::~HeightFieldDrawable()
1035 {
1036 }
1037 
drawImplementation(osg::RenderInfo & renderInfo) const1038 void HeightFieldDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
1039 {
1040     if (_geometry.valid()) _geometry->draw(renderInfo);
1041 }
1042 
compileGLObjects(osg::RenderInfo & renderInfo) const1043 void HeightFieldDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const
1044 {
1045     if (_geometry.valid()) _geometry->compileGLObjects(renderInfo);
1046 }
1047 
resizeGLObjectBuffers(unsigned int maxSize)1048 void HeightFieldDrawable::resizeGLObjectBuffers(unsigned int maxSize)
1049 {
1050     if (_geometry.valid()) _geometry->resizeGLObjectBuffers(maxSize);
1051 }
1052 
releaseGLObjects(osg::State * state) const1053 void HeightFieldDrawable::releaseGLObjects(osg::State* state) const
1054 {
1055     if (_geometry.valid()) _geometry->releaseGLObjects(state);
1056 }
1057 
accept(osg::Drawable::AttributeFunctor & af)1058 void HeightFieldDrawable::accept(osg::Drawable::AttributeFunctor& af)
1059 {
1060     if (_geometry) _geometry->accept(af);
1061 }
1062 
accept(osg::Drawable::ConstAttributeFunctor & caf) const1063 void HeightFieldDrawable::accept(osg::Drawable::ConstAttributeFunctor& caf) const
1064 {
1065     if (_geometry) _geometry->accept(caf);
1066 }
1067 
accept(osg::PrimitiveFunctor & pf) const1068 void HeightFieldDrawable::accept(osg::PrimitiveFunctor& pf) const
1069 {
1070     // use the cached vertex positions for PrimitiveFunctor operations
1071     if (!_geometry) return;
1072 
1073     if (_vertices.valid())
1074     {
1075         pf.setVertexArray(_vertices->size(), &((*_vertices)[0]));
1076 
1077         const osg::DrawElementsUShort* deus = dynamic_cast<const osg::DrawElementsUShort*>(_geometry->getDrawElements());
1078         if (deus)
1079         {
1080             pf.drawElements(GL_QUADS, deus->size(), &((*deus)[0]));
1081         }
1082         else
1083         {
1084             const osg::DrawElementsUInt* deui = dynamic_cast<const osg::DrawElementsUInt*>(_geometry->getDrawElements());
1085             if (deui)
1086             {
1087                 pf.drawElements(GL_QUADS, deui->size(), &((*deui)[0]));
1088             }
1089         }
1090     }
1091     else
1092     {
1093         _geometry->accept(pf);
1094     }
1095 }
1096 
accept(osg::PrimitiveIndexFunctor & pif) const1097 void HeightFieldDrawable::accept(osg::PrimitiveIndexFunctor& pif) const
1098 {
1099     if (_vertices.valid())
1100     {
1101         pif.setVertexArray(_vertices->size(), &((*_vertices)[0]));
1102 
1103         const osg::DrawElementsUShort* deus = dynamic_cast<const osg::DrawElementsUShort*>(_geometry->getDrawElements());
1104         if (deus)
1105         {
1106             pif.drawElements(GL_QUADS, deus->size(), &((*deus)[0]));
1107         }
1108         else
1109         {
1110             const osg::DrawElementsUInt* deui = dynamic_cast<const osg::DrawElementsUInt*>(_geometry->getDrawElements());
1111             if (deui)
1112             {
1113                 pif.drawElements(GL_QUADS, deui->size(), &((*deui)[0]));
1114             }
1115         }
1116     }
1117     else
1118     {
1119         _geometry->accept(pif);
1120     }
1121 }
1122