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