diff --git a/examples/osgterrain/ShaderTerrain.cpp b/examples/osgterrain/ShaderTerrain.cpp index 492ec8289..8211f9848 100644 --- a/examples/osgterrain/ShaderTerrain.cpp +++ b/examples/osgterrain/ShaderTerrain.cpp @@ -21,755 +21,6 @@ using namespace osgTerrain; #define LOCK(mutex) /* OpenThreads::Thread::microSleep(1);*/ #endif -const osgTerrain::Locator* osgTerrain::computeMasterLocator(const osgTerrain::TerrainTile* tile) -{ - const osgTerrain::Layer* elevationLayer = tile->getElevationLayer(); - const osgTerrain::Layer* colorLayer = tile->getColorLayer(0); - - const Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0; - const Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0; - - const Locator* masterLocator = elevationLocator ? elevationLocator : colorLocator; - if (!masterLocator) - { - OSG_NOTICE<<"Problem, no locator found in any of the terrain layers"<getTransform(); - osg::Vec3d bottom_left = osg::Vec3d(0.0,0.0,0.0) * matrix; - osg::Vec3d bottom_right = osg::Vec3d(1.0,0.0,0.0) * matrix; - osg::Vec3d top_left = osg::Vec3d(1.0,1.0,0.0) * matrix; - key.sx = static_cast((bottom_right-bottom_left).length()); - key.sy = static_cast((top_left-bottom_left).length()); - - if (masterLocator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) - { - // need to differentiate between tiles based of latitude, so use y position of bottom left corner. - key.y = static_cast(bottom_left.y()); - } - else - { - // when the projection is linear there is no need to differentiate tiles according to their latitude - key.y = 0.0; - } - - } - - osgTerrain::HeightFieldLayer* layer = dynamic_cast(tile->getElevationLayer()); - if (layer) - { - osg::HeightField* hf = layer->getHeightField(); - if (hf) - { - key.nx = hf->getNumColumns(); - key.ny = hf->getNumRows(); - } - } - return true; -} - -static int numberGeometryCreated = 0; -static int numberSharedGeometry = 0; - -osg::ref_ptr GeometryPool::getOrCreateGeometry(osgTerrain::TerrainTile* tile) -{ - OpenThreads::ScopedLock lock(_geometryMapMutex); - - GeometryKey key; - createKeyForTile(tile, key); - - GeometryMap::iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) - { - - ++numberSharedGeometry; -// OSG_NOTICE<<"Sharing geometry "<second.get()<<", number shared = "<second.get(); - } - - osg::ref_ptr geometry = new osg::Geometry; - _geometryMap[key] = geometry; - - osg::ref_ptr vertices = new osg::Vec3Array; - geometry->setVertexArray(vertices.get()); - - osg::ref_ptr normals = new osg::Vec3Array; - geometry->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX); - - osg::ref_ptr colours = new osg::Vec4Array; - geometry->setColorArray(colours.get(), osg::Array::BIND_OVERALL); - colours->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); - - osg::ref_ptr texcoords = new osg::Vec4Array; - geometry->setTexCoordArray(0, texcoords.get(), osg::Array::BIND_PER_VERTEX); - - int nx = key.nx; - int ny = key.nx; - - int numVerticesMainBody = nx * ny; - int numVerticesSkirt = (nx)*2 + (ny)*2; - int numVertices = numVerticesMainBody + numVerticesSkirt; - - vertices->reserve(numVertices); - normals->reserve(numVertices); - texcoords->reserve(numVertices); - - double c_mult = 1.0/static_cast(nx-1); - double r_mult = 1.0/static_cast(ny-1); - - typedef std::vector LocationCoords; - LocationCoords locationCoords; - locationCoords.reserve(numVertices); - - osg::Vec3d pos(0.0, 0.0, 0.0); - osg::Vec3d normal(0.0, 0.0, 1.0); - osg::Vec2 delta(1.0f/static_cast(nx), 1.0f/static_cast(ny)); - - // pass in the delta texcoord per texel via the color array - (*colours)[0].x() = c_mult; - (*colours)[0].y() = r_mult; - - - - osg::Matrixd matrix; - const osgTerrain::Locator* locator = computeMasterLocator(tile); - if (locator) - { - matrix = locator->getTransform(); - } - - // compute the size of the skirtHeight - osg::Vec3d bottom_left(0.0,0.0,0.0); - osg::Vec3d top_right(1.0,1.0,0.0); - - // transform for unit coords to local coords of the tile - bottom_left = bottom_left * matrix; - top_right = top_right * matrix; - - // if we have a geocentric database then transform into geocentric coords. - const osg::EllipsoidModel* em = locator->getEllipsoidModel(); - if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) - { - // note y axis maps to latitude, x axis to longitude - em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(), bottom_left.z()); - em->convertLatLongHeightToXYZ(top_right.y(), top_right.x(), top_right.z(), top_right.x(), top_right.y(), top_right.z()); - } - - double diagonalLength = (top_right-bottom_left).length(); - double skirtRatio = 0.02; - double skirtHeight = -diagonalLength*skirtRatio; - - // set up the vertex data - { - // bottom row for skirt - pos.y () = static_cast(0)*r_mult; - pos.z() = skirtHeight; - for(int c=0; c(c)*c_mult; - vertices->push_back(pos); - normals->push_back(normal); - texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); - locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); - } - - // main body - for(int r=0; r(r)*r_mult; - - // start skirt vertex - pos.z() = skirtHeight; - { - pos.x() = static_cast(0)*c_mult; - vertices->push_back(pos); - normals->push_back(normal); - texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); - locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); - } - - pos.z() = 0; - for(int c=0; c(c)*c_mult; - vertices->push_back(pos); - normals->push_back(normal); - texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); - locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); - } - - // end skirt vertex - pos.z() = skirtHeight; - { - pos.x() = static_cast(nx-1)*c_mult; - vertices->push_back(pos); - normals->push_back(normal); - texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); - locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); - } - - } - - // top row skirt - pos.y () = static_cast(ny-1)*r_mult; - pos.z() = skirtHeight; - for(int c=0; c(c)*c_mult; - vertices->push_back(pos); - normals->push_back(normal); - texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); - locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); - } - } - -#if 1 - - bool smallTile = numVertices <= 16384; - osg::ref_ptr elements = smallTile ? - static_cast(new osg::DrawElementsUShort(GL_TRIANGLE_STRIP)) : - static_cast(new osg::DrawElementsUInt(GL_TRIANGLE_STRIP)); - - elements->reserveElements( (nx-1) * (ny-1) * 2 + (nx-1)*2*2 + (ny-1)*2*2 +(ny)*2); - geometry->addPrimitiveSet(elements.get()); - - - // first row containing the skirt - int il = 0; - int iu = 0; - for(int c=0; caddElement(iu); - elements->addElement(il); - } - elements->addElement(il); - - // center section - for(int r=0; raddElement(iu); - for(int c=0; caddElement(iu); - elements->addElement(il); - } - elements->addElement(il); - } - - // top row containing skirt - il = nx+(ny-1)*(nx+2)+1; - iu = il+nx+1; - elements->addElement(iu); - for(int c=0; caddElement(iu); - elements->addElement(il); - } - -#else - bool smallTile = numVertices <= 16384; - osg::ref_ptr elements = smallTile ? - static_cast(new osg::DrawElementsUShort(GL_QUADS)) : - static_cast(new osg::DrawElementsUInt(GL_QUADS)); - - elements->reserveElements( (nx-1) * (ny-1) * 4 + (nx-1)*2*4 + (ny-1)*2*4 ); - geometry->addPrimitiveSet(elements.get()); - - - // first row containing the skirt - for(int c=0; caddElement(il); - elements->addElement(il+1); - elements->addElement(iu+1); - elements->addElement(iu); - } - - // center section - for(int r=0; raddElement(il); - elements->addElement(il+1); - elements->addElement(iu+1); - elements->addElement(iu); - } - } - - // top row containing skirt - for(int c=0; caddElement(il); - elements->addElement(il+1); - elements->addElement(iu+1); - elements->addElement(iu); - } -#endif - if (locator) - { - matrix = locator->getTransform(); - - osg::Vec3d center(0.5, 0.5, 0.0); - - osg::Vec3d bottom_left(0.0,0.0,0.0); - osg::Vec3d bottom_right(1.0,0.0,0.0); - osg::Vec3d top_left(0.0,1.0,0.0); - - center = center * matrix; - bottom_left = bottom_left * matrix; - bottom_right = bottom_right * matrix; - top_left = top_left * matrix; - - // shift to center.x() to x=0 and carry all the corners with it. - bottom_left.x() -= center.x(); - bottom_right.x() -= center.x(); - top_left.x() -= center.x(); - //center.x() = 0.0; - - // OSG_NOTICE<<" in lat/longs : bottom_left = "<convertLatLongHeightToXYZ(center.y(), center.x(), center.z(), center.x(), center.y(),center.z()); - em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(),bottom_left.z()); - em->convertLatLongHeightToXYZ(bottom_right.y(), bottom_right.x(), bottom_right.z(), bottom_right.x(), bottom_right.y(),bottom_right.z()); - em->convertLatLongHeightToXYZ(top_left.y(), top_left.x(), top_left.z(), top_left.x(), top_left.y(),top_left.z()); - - osg::Matrixd worldToLocalTransform; - worldToLocalTransform.invert(localToWorldTransform); - - center = center * worldToLocalTransform; - bottom_left = bottom_left * worldToLocalTransform; - bottom_right = bottom_right * worldToLocalTransform; - top_left = top_left * worldToLocalTransform; - - - for(int i=0; iconvertLatLongHeightToXYZ(pos.y(), pos.x(), height, pos.x(), pos.y(),pos.z()); - - osg::Vec4& tc = (*texcoords)[i]; - - osg::Vec3d pos_right = osg::Vec3d(location.x()+location[2], location.y(), 0.0) * matrix; - em->convertLatLongHeightToXYZ(pos_right.y(), pos_right.x(), height, pos_right.x(), pos_right.y(),pos_right.z()); - - osg::Vec3d pos_up = osg::Vec3d(location.x(), location.y()+location[3], 0.0) * matrix; - em->convertLatLongHeightToXYZ(pos_up.y(), pos_up.x(), height, pos_up.x(), pos_up.y(),pos_up.z()); - - double length_right = (pos_right-pos).length(); - double length_up = (pos_up-pos).length(); - tc[2] = 1.0/length_right; - tc[3] = 1.0/length_up; - - - osg::Vec3d normal(pos); - normal = osg::Matrixd::transform3x3(localToWorldTransform, normal); - normal.normalize(); - - pos = pos * worldToLocalTransform; - pos -= center; - - (*vertices)[i] = pos; - (*normals)[i] = normal; - - } - - } - } - - // double tileWidth = (bottom_right-bottom_left).length(); - // double skirtHeight = tileWidth*0.05; - - // OSG_NOTICE<<" in local coords : center = "< GeometryPool::getTileSubgraph(osgTerrain::TerrainTile* tile) -{ - // create or reuse Geometry - osg::ref_ptr geometry = getOrCreateGeometry(tile); - - - osg::ref_ptr hfDrawable = new HeightFieldDrawable(); - - osgTerrain::HeightFieldLayer* hfl = dynamic_cast(tile->getElevationLayer()); - osg::HeightField* hf = hfl ? hfl->getHeightField() : 0; - hfDrawable->setHeightField(hf); - hfDrawable->setGeometry(geometry.get()); - - - // create a transform to place the geometry in the appropriate place - osg::ref_ptr transform = new osg::MatrixTransform; - -// transform->addChild(geometry.get()); - transform->addChild(hfDrawable.get()); - - const osgTerrain::Locator* locator = computeMasterLocator(tile); - if (locator) - { - osg::Matrixd matrix = locator->getTransform(); - - osg::Vec3d center = osg::Vec3d(0.5, 0.5, 0.0) * matrix; - - // shift to center.x() to x=0 and carry all the corners with it. - const osg::EllipsoidModel* em = locator->getEllipsoidModel(); - if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) - { - osg::Matrixd localToWorldTransform; - // note y axis maps to latitude, x axis to longitude - em->computeLocalToWorldTransformFromLatLongHeight(center.y(), center.x(), center.z(), localToWorldTransform); - // OSG_NOTICE<<"We have a EllipsoidModel to take account of "<setMatrix(localToWorldTransform); - - //osgDB::writeNodeFile(*transform, "subgraph.osgt"); - } - else - { - transform->setMatrix(locator->getTransform()); - } - } - - osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); - osg::Vec3Array* normals = dynamic_cast(geometry->getNormalArray()); - if (hf && vertices && normals && (vertices->size()==normals->size())) - { - unsigned int nr = hf->getNumRows(); - unsigned int nc = hf->getNumColumns(); - - osg::BoundingBox bb; - osg::FloatArray* heights = hf->getFloatArray(); - - for(unsigned int r=0; rsetInitialBound(bb); - // OSG_NOTICE<<"Assigning initial bound ("<getBoundingBox(); - //OSG_NOTICE<<" getBoundingBox ("< stateset = transform->getOrCreateStateSet(); - - // apply colour layers - applyLayers(tile, stateset.get()); - - return transform; -} - -osg::ref_ptr GeometryPool::getOrCreateProgram(LayerTypes& layerTypes) -{ -#if 0 - OSG_NOTICE<<"getOrCreateProgram("; - for(LayerTypes::iterator itr = layerTypes.begin(); - itr != layerTypes.end(); - ++itr) - { - if (itr!= layerTypes.begin()) OSG_NOTICE<<", "; - switch(*itr) - { - case(HEIGHTFIELD_LAYER): OSG_NOTICE<<"HeightField"; break; - case(COLOR_LAYER): OSG_NOTICE<<"Colour"; break; - case(CONTOUR_LAYER): OSG_NOTICE<<"Contour"; break; - } - } -#endif - - OpenThreads::ScopedLock lock(_programMapMutex); - ProgramMap::iterator itr = _programMap.find(layerTypes); - if (itr!=_programMap.end()) - { - // OSG_NOTICE<<") returning exisitng Program "<second.get()<second.get(); - } - - osg::ref_ptr program = new osg::Program; - _programMap[layerTypes] = program; - - // OSG_NOTICE<<") creating new Program "< vertex_shader = osgDB::readShaderFile("shaders/terrain.vert"); - program->addShader(vertex_shader.get()); - - osg::ref_ptr fragment_shader = osgDB::readShaderFile("shaders/terrain.frag"); - program->addShader(fragment_shader.get()); - - return program; -} - -void GeometryPool::applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset) -{ - typedef std::map LayerToTextureMap; - LayerToTextureMap layerToTextureMap; - - // OSG_NOTICE<<"tile->getNumColorLayers() = "<getNumColorLayers()<(tile->getElevationLayer()); - if (hfl) - { - osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[hfl]); - if (!texture2D) - { - texture2D = new osg::Texture2D; - - osg::ref_ptr image = new osg::Image; - - const void* dataPtr = hfl->getHeightField()->getFloatArray()->getDataPointer(); - - image->setImage(hfl->getNumRows(), hfl->getNumColumns(), 1, - GL_LUMINANCE32F_ARB, - GL_LUMINANCE, GL_FLOAT, - reinterpret_cast(const_cast(dataPtr)), - osg::Image::NO_DELETE); - - texture2D->setImage(image.get()); - texture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST); - texture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST); - texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP); - texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP); - texture2D->setBorderColor(osg::Vec4d(0.0,0.0,0.0,0.0)); - texture2D->setResizeNonPowerOfTwoHint(false); - - layerToTextureMap[hfl] = texture2D; - } - - int textureUnit = layerTypes.size(); - stateset->setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON); - stateset->addUniform(new osg::Uniform("terrainTexture",textureUnit)); - - layerTypes.push_back(HEIGHTFIELD_LAYER); - } -#if 1 - for(unsigned int layerNum=0; layerNumgetNumColorLayers(); ++layerNum) - { - osgTerrain::Layer* colorLayer = tile->getColorLayer(layerNum); - if (!colorLayer) continue; - - osgTerrain::SwitchLayer* switchLayer = dynamic_cast(colorLayer); - if (switchLayer) - { - if (switchLayer->getActiveLayer()<0 || - static_cast(switchLayer->getActiveLayer())>=switchLayer->getNumLayers()) - { - continue; - } - - colorLayer = switchLayer->getLayer(switchLayer->getActiveLayer()); - if (!colorLayer) continue; - } - - osg::Image* image = colorLayer->getImage(); - if (!image) continue; - - osgTerrain::ImageLayer* imageLayer = dynamic_cast(colorLayer); - osgTerrain::ContourLayer* contourLayer = dynamic_cast(colorLayer); - if (imageLayer) - { - osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[colorLayer]); - if (!texture2D) - { - texture2D = new osg::Texture2D; - texture2D->setImage(image); - texture2D->setMaxAnisotropy(16.0f); - texture2D->setResizeNonPowerOfTwoHint(false); - - texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter()); - texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); - - texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); - texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); - - bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST); - bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1)); - bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1)); - - if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo)) - { - OSG_INFO<<"Disabling mipmapping for non power of two tile size("<s()<<", "<t()<<")"<setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); - } - - - layerToTextureMap[colorLayer] = texture2D; - - // OSG_NOTICE<<"Creating new ImageLayer texture "<s()="<s()<<" image->t()="<t()<setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON); - - std::stringstream str; - str<<"colorTexture"<addUniform(new osg::Uniform(str.str().c_str(),textureUnit)); - - layerTypes.push_back(COLOR_LAYER); - - } - else if (contourLayer) - { - osg::Texture1D* texture1D = dynamic_cast(layerToTextureMap[colorLayer]); - if (!texture1D) - { - texture1D = new osg::Texture1D; - texture1D->setImage(image); - texture1D->setResizeNonPowerOfTwoHint(false); - texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); - texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); - - layerToTextureMap[colorLayer] = texture1D; - } - - int textureUnit = layerTypes.size(); - stateset->setTextureAttributeAndModes(textureUnit, texture1D, osg::StateAttribute::ON); - - std::stringstream str; - str<<"contourTexture"<addUniform(new osg::Uniform(str.str().c_str(),textureUnit)); - - layerTypes.push_back(CONTOUR_LAYER); - } - } -#endif - - osg::ref_ptr program = getOrCreateProgram(layerTypes); - if (program.valid()) - { - stateset->setAttribute(program.get()); - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// HeightFieldDrawable -// -HeightFieldDrawable::HeightFieldDrawable() -{ - setSupportsDisplayList(false); -} - -HeightFieldDrawable::HeightFieldDrawable(const HeightFieldDrawable& rhs,const osg::CopyOp& copyop): - osg::Drawable(rhs, copyop), - _heightField(rhs._heightField), - _geometry(rhs._geometry) -{ - setSupportsDisplayList(false); -} - -void HeightFieldDrawable::drawImplementation(osg::RenderInfo& renderInfo) const -{ - if (_geometry.valid()) _geometry->draw(renderInfo); -} - -void HeightFieldDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const -{ - if (_geometry.valid()) _geometry->compileGLObjects(renderInfo); -} - -void HeightFieldDrawable::resizeGLObjectBuffers(unsigned int maxSize) -{ - if (_geometry.valid()) _geometry->resizeGLObjectBuffers(maxSize); -} - -void HeightFieldDrawable::releaseGLObjects(osg::State* state) const -{ - if (_geometry.valid()) _geometry->releaseGLObjects(state); -} - -void HeightFieldDrawable::accept(osg::Drawable::AttributeFunctor& af) -{ - if (_geometry) _geometry->accept(af); -} - -void HeightFieldDrawable::accept(osg::Drawable::ConstAttributeFunctor& caf) const -{ - if (_geometry) _geometry->accept(caf); -} - -void HeightFieldDrawable::accept(osg::PrimitiveFunctor& pf) const -{ - if (_geometry) _geometry->accept(pf); -} - -void HeightFieldDrawable::accept(osg::PrimitiveIndexFunctor& pif) const -{ - if (_geometry) _geometry->accept(pif); -} ///////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/examples/osgterrain/ShaderTerrain.h b/examples/osgterrain/ShaderTerrain.h index 3ca78ca96..fdf831ac2 100644 --- a/examples/osgterrain/ShaderTerrain.h +++ b/examples/osgterrain/ShaderTerrain.h @@ -5,122 +5,11 @@ #include #include #include +#include namespace osgTerrain { -extern const osgTerrain::Locator* computeMasterLocator(const osgTerrain::TerrainTile* tile); - -class GeometryPool : public osg::Referenced -{ - public: - GeometryPool() {} - - struct GeometryKey - { - GeometryKey(): sx(0.0), sy(0.0), y(0.0), nx(0), ny(0) {} - - bool operator < (const GeometryKey& rhs) const - { - if (sxrhs.sx) return false; - - if (sxrhs.sx) return false; - - if (yrhs.y) return false; - - if (nxrhs.nx) return false; - - return (ny > GeometryMap; - - bool createKeyForTile(TerrainTile* tile, GeometryKey& key); - - enum LayerType - { - HEIGHTFIELD_LAYER, - COLOR_LAYER, - CONTOUR_LAYER - }; - - typedef std::vector LayerTypes; - typedef std::map > ProgramMap; - - osg::ref_ptr getOrCreateProgram(LayerTypes& layerTypes); - - osg::ref_ptr getOrCreateGeometry(osgTerrain::TerrainTile* tile); - - osg::ref_ptr getTileSubgraph(osgTerrain::TerrainTile* tile); - - void applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset); - - protected: - virtual ~GeometryPool(); - - OpenThreads::Mutex _geometryMapMutex; - GeometryMap _geometryMap; - - OpenThreads::Mutex _programMapMutex; - ProgramMap _programMap; -}; - -class HeightFieldDrawable : public osg::Drawable -{ - public: - HeightFieldDrawable(); - - HeightFieldDrawable(const HeightFieldDrawable&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); - - META_Node(osgTerrain, HeightFieldDrawable); - - void setHeightField(osg::HeightField* hf) { _heightField = hf; } - osg::HeightField* getHeightField() { return _heightField.get(); } - const osg::HeightField* getHeightField() const { return _heightField.get(); } - - void setGeometry(osg::Geometry* geom) { _geometry = geom; } - osg::Geometry* getGeometry() { return _geometry.get(); } - const osg::Geometry* getGeometry() const { return _geometry.get(); } - - virtual void drawImplementation(osg::RenderInfo& renderInfo) const; - virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; - virtual void resizeGLObjectBuffers(unsigned int maxSize); - virtual void releaseGLObjects(osg::State* state=0) const; - - - virtual bool supports(const osg::Drawable::AttributeFunctor&) const { return true; } - virtual void accept(osg::Drawable::AttributeFunctor&); - - virtual bool supports(const osg::Drawable::ConstAttributeFunctor&) const { return true; } - virtual void accept(osg::Drawable::ConstAttributeFunctor&) const; - - virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } - virtual void accept(osg::PrimitiveFunctor&) const; - - virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return true; } - virtual void accept(osg::PrimitiveIndexFunctor&) const; - - - -protected: - - osg::ref_ptr _heightField; - osg::ref_ptr _geometry; - -}; - class ShaderTerrain : public osgTerrain::TerrainTechnique { public: diff --git a/include/osgTerrain/GeometryPool b/include/osgTerrain/GeometryPool new file mode 100644 index 000000000..03b86b41c --- /dev/null +++ b/include/osgTerrain/GeometryPool @@ -0,0 +1,145 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGTERRAIN_GEOMETRYPOOL +#define OSGTERRAIN_GEOMETRYPOOL 1 + +#include +#include +#include + +#include + +#include + + +namespace osgTerrain { + +extern const osgTerrain::Locator* computeMasterLocator(const osgTerrain::TerrainTile* tile); + +class OSGTERRAIN_EXPORT GeometryPool : public osg::Referenced +{ + public: + GeometryPool(); + + struct GeometryKey + { + GeometryKey(): sx(0.0), sy(0.0), y(0.0), nx(0), ny(0) {} + + bool operator < (const GeometryKey& rhs) const + { + if (sxrhs.sx) return false; + + if (sxrhs.sx) return false; + + if (yrhs.y) return false; + + if (nxrhs.nx) return false; + + return (ny > GeometryMap; + + bool createKeyForTile(TerrainTile* tile, GeometryKey& key); + + enum LayerType + { + HEIGHTFIELD_LAYER, + COLOR_LAYER, + CONTOUR_LAYER + }; + + typedef std::vector LayerTypes; + typedef std::map > ProgramMap; + + osg::ref_ptr getOrCreateProgram(LayerTypes& layerTypes); + + osg::ref_ptr getOrCreateGeometry(osgTerrain::TerrainTile* tile); + + osg::ref_ptr getTileSubgraph(osgTerrain::TerrainTile* tile); + + void applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset); + + protected: + virtual ~GeometryPool(); + + OpenThreads::Mutex _geometryMapMutex; + GeometryMap _geometryMap; + + OpenThreads::Mutex _programMapMutex; + ProgramMap _programMap; +}; + + +class HeightFieldDrawable : public osg::Drawable +{ + public: + HeightFieldDrawable(); + + HeightFieldDrawable(const HeightFieldDrawable&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_Node(osgTerrain, HeightFieldDrawable); + + void setHeightField(osg::HeightField* hf) { _heightField = hf; } + osg::HeightField* getHeightField() { return _heightField.get(); } + const osg::HeightField* getHeightField() const { return _heightField.get(); } + + void setGeometry(osg::Geometry* geom) { _geometry = geom; } + osg::Geometry* getGeometry() { return _geometry.get(); } + const osg::Geometry* getGeometry() const { return _geometry.get(); } + + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; + virtual void resizeGLObjectBuffers(unsigned int maxSize); + virtual void releaseGLObjects(osg::State* state=0) const; + + + virtual bool supports(const osg::Drawable::AttributeFunctor&) const { return true; } + virtual void accept(osg::Drawable::AttributeFunctor&); + + virtual bool supports(const osg::Drawable::ConstAttributeFunctor&) const { return true; } + virtual void accept(osg::Drawable::ConstAttributeFunctor&) const; + + virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } + virtual void accept(osg::PrimitiveFunctor&) const; + + virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return true; } + virtual void accept(osg::PrimitiveIndexFunctor&) const; + + + +protected: + + osg::ref_ptr _heightField; + osg::ref_ptr _geometry; + +}; + + + +} + +#endif diff --git a/src/osgTerrain/CMakeLists.txt b/src/osgTerrain/CMakeLists.txt index 561071917..f627e39d0 100644 --- a/src/osgTerrain/CMakeLists.txt +++ b/src/osgTerrain/CMakeLists.txt @@ -14,6 +14,7 @@ SET(TARGET_H ${HEADER_PATH}/TerrainTechnique ${HEADER_PATH}/Terrain ${HEADER_PATH}/GeometryTechnique + ${HEADER_PATH}/GeometryPool ${HEADER_PATH}/ValidDataOperator ${HEADER_PATH}/Version ) @@ -26,6 +27,7 @@ SET(TARGET_SRC TerrainTechnique.cpp Terrain.cpp GeometryTechnique.cpp + GeometryPool.cpp Version.cpp ${OPENSCENEGRAPH_VERSIONINFO_RC} ) diff --git a/src/osgTerrain/GeometryPool.cpp b/src/osgTerrain/GeometryPool.cpp new file mode 100644 index 000000000..0e221257e --- /dev/null +++ b/src/osgTerrain/GeometryPool.cpp @@ -0,0 +1,774 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include +#include +#include +#include + +using namespace osgTerrain; + +const osgTerrain::Locator* osgTerrain::computeMasterLocator(const osgTerrain::TerrainTile* tile) +{ + const osgTerrain::Layer* elevationLayer = tile->getElevationLayer(); + const osgTerrain::Layer* colorLayer = tile->getColorLayer(0); + + const Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0; + const Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0; + + const Locator* masterLocator = elevationLocator ? elevationLocator : colorLocator; + if (!masterLocator) + { + OSG_NOTICE<<"Problem, no locator found in any of the terrain layers"<getTransform(); + osg::Vec3d bottom_left = osg::Vec3d(0.0,0.0,0.0) * matrix; + osg::Vec3d bottom_right = osg::Vec3d(1.0,0.0,0.0) * matrix; + osg::Vec3d top_left = osg::Vec3d(1.0,1.0,0.0) * matrix; + key.sx = static_cast((bottom_right-bottom_left).length()); + key.sy = static_cast((top_left-bottom_left).length()); + + if (masterLocator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) + { + // need to differentiate between tiles based of latitude, so use y position of bottom left corner. + key.y = static_cast(bottom_left.y()); + } + else + { + // when the projection is linear there is no need to differentiate tiles according to their latitude + key.y = 0.0; + } + + } + + osgTerrain::HeightFieldLayer* layer = dynamic_cast(tile->getElevationLayer()); + if (layer) + { + osg::HeightField* hf = layer->getHeightField(); + if (hf) + { + key.nx = hf->getNumColumns(); + key.ny = hf->getNumRows(); + } + } + return true; +} + +static int numberGeometryCreated = 0; +static int numberSharedGeometry = 0; + +osg::ref_ptr GeometryPool::getOrCreateGeometry(osgTerrain::TerrainTile* tile) +{ + OpenThreads::ScopedLock lock(_geometryMapMutex); + + GeometryKey key; + createKeyForTile(tile, key); + + GeometryMap::iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) + { + + ++numberSharedGeometry; +// OSG_NOTICE<<"Sharing geometry "<second.get()<<", number shared = "<second.get(); + } + + osg::ref_ptr geometry = new osg::Geometry; + _geometryMap[key] = geometry; + + osg::ref_ptr vertices = new osg::Vec3Array; + geometry->setVertexArray(vertices.get()); + + osg::ref_ptr normals = new osg::Vec3Array; + geometry->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX); + + osg::ref_ptr colours = new osg::Vec4Array; + geometry->setColorArray(colours.get(), osg::Array::BIND_OVERALL); + colours->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + + osg::ref_ptr texcoords = new osg::Vec4Array; + geometry->setTexCoordArray(0, texcoords.get(), osg::Array::BIND_PER_VERTEX); + + int nx = key.nx; + int ny = key.nx; + + int numVerticesMainBody = nx * ny; + int numVerticesSkirt = (nx)*2 + (ny)*2; + int numVertices = numVerticesMainBody + numVerticesSkirt; + + vertices->reserve(numVertices); + normals->reserve(numVertices); + texcoords->reserve(numVertices); + + double c_mult = 1.0/static_cast(nx-1); + double r_mult = 1.0/static_cast(ny-1); + + typedef std::vector LocationCoords; + LocationCoords locationCoords; + locationCoords.reserve(numVertices); + + osg::Vec3d pos(0.0, 0.0, 0.0); + osg::Vec3d normal(0.0, 0.0, 1.0); + osg::Vec2 delta(1.0f/static_cast(nx), 1.0f/static_cast(ny)); + + // pass in the delta texcoord per texel via the color array + (*colours)[0].x() = c_mult; + (*colours)[0].y() = r_mult; + + + + osg::Matrixd matrix; + const osgTerrain::Locator* locator = computeMasterLocator(tile); + if (locator) + { + matrix = locator->getTransform(); + } + + // compute the size of the skirtHeight + osg::Vec3d bottom_left(0.0,0.0,0.0); + osg::Vec3d top_right(1.0,1.0,0.0); + + // transform for unit coords to local coords of the tile + bottom_left = bottom_left * matrix; + top_right = top_right * matrix; + + // if we have a geocentric database then transform into geocentric coords. + const osg::EllipsoidModel* em = locator->getEllipsoidModel(); + if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) + { + // note y axis maps to latitude, x axis to longitude + em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(), bottom_left.z()); + em->convertLatLongHeightToXYZ(top_right.y(), top_right.x(), top_right.z(), top_right.x(), top_right.y(), top_right.z()); + } + + double diagonalLength = (top_right-bottom_left).length(); + double skirtRatio = 0.02; + double skirtHeight = -diagonalLength*skirtRatio; + + // set up the vertex data + { + // bottom row for skirt + pos.y () = static_cast(0)*r_mult; + pos.z() = skirtHeight; + for(int c=0; c(c)*c_mult; + vertices->push_back(pos); + normals->push_back(normal); + texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); + locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); + } + + // main body + for(int r=0; r(r)*r_mult; + + // start skirt vertex + pos.z() = skirtHeight; + { + pos.x() = static_cast(0)*c_mult; + vertices->push_back(pos); + normals->push_back(normal); + texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); + locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); + } + + pos.z() = 0; + for(int c=0; c(c)*c_mult; + vertices->push_back(pos); + normals->push_back(normal); + texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); + locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); + } + + // end skirt vertex + pos.z() = skirtHeight; + { + pos.x() = static_cast(nx-1)*c_mult; + vertices->push_back(pos); + normals->push_back(normal); + texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); + locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); + } + + } + + // top row skirt + pos.y () = static_cast(ny-1)*r_mult; + pos.z() = skirtHeight; + for(int c=0; c(c)*c_mult; + vertices->push_back(pos); + normals->push_back(normal); + texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f)); + locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult)); + } + } + +#if 1 + + bool smallTile = numVertices <= 16384; + osg::ref_ptr elements = smallTile ? + static_cast(new osg::DrawElementsUShort(GL_TRIANGLE_STRIP)) : + static_cast(new osg::DrawElementsUInt(GL_TRIANGLE_STRIP)); + + elements->reserveElements( (nx-1) * (ny-1) * 2 + (nx-1)*2*2 + (ny-1)*2*2 +(ny)*2); + geometry->addPrimitiveSet(elements.get()); + + + // first row containing the skirt + int il = 0; + int iu = 0; + for(int c=0; caddElement(iu); + elements->addElement(il); + } + elements->addElement(il); + + // center section + for(int r=0; raddElement(iu); + for(int c=0; caddElement(iu); + elements->addElement(il); + } + elements->addElement(il); + } + + // top row containing skirt + il = nx+(ny-1)*(nx+2)+1; + iu = il+nx+1; + elements->addElement(iu); + for(int c=0; caddElement(iu); + elements->addElement(il); + } + +#else + bool smallTile = numVertices <= 16384; + osg::ref_ptr elements = smallTile ? + static_cast(new osg::DrawElementsUShort(GL_QUADS)) : + static_cast(new osg::DrawElementsUInt(GL_QUADS)); + + elements->reserveElements( (nx-1) * (ny-1) * 4 + (nx-1)*2*4 + (ny-1)*2*4 ); + geometry->addPrimitiveSet(elements.get()); + + + // first row containing the skirt + for(int c=0; caddElement(il); + elements->addElement(il+1); + elements->addElement(iu+1); + elements->addElement(iu); + } + + // center section + for(int r=0; raddElement(il); + elements->addElement(il+1); + elements->addElement(iu+1); + elements->addElement(iu); + } + } + + // top row containing skirt + for(int c=0; caddElement(il); + elements->addElement(il+1); + elements->addElement(iu+1); + elements->addElement(iu); + } +#endif + if (locator) + { + matrix = locator->getTransform(); + + osg::Vec3d center(0.5, 0.5, 0.0); + + osg::Vec3d bottom_left(0.0,0.0,0.0); + osg::Vec3d bottom_right(1.0,0.0,0.0); + osg::Vec3d top_left(0.0,1.0,0.0); + + center = center * matrix; + bottom_left = bottom_left * matrix; + bottom_right = bottom_right * matrix; + top_left = top_left * matrix; + + // shift to center.x() to x=0 and carry all the corners with it. + bottom_left.x() -= center.x(); + bottom_right.x() -= center.x(); + top_left.x() -= center.x(); + //center.x() = 0.0; + + // OSG_NOTICE<<" in lat/longs : bottom_left = "<convertLatLongHeightToXYZ(center.y(), center.x(), center.z(), center.x(), center.y(),center.z()); + em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(),bottom_left.z()); + em->convertLatLongHeightToXYZ(bottom_right.y(), bottom_right.x(), bottom_right.z(), bottom_right.x(), bottom_right.y(),bottom_right.z()); + em->convertLatLongHeightToXYZ(top_left.y(), top_left.x(), top_left.z(), top_left.x(), top_left.y(),top_left.z()); + + osg::Matrixd worldToLocalTransform; + worldToLocalTransform.invert(localToWorldTransform); + + center = center * worldToLocalTransform; + bottom_left = bottom_left * worldToLocalTransform; + bottom_right = bottom_right * worldToLocalTransform; + top_left = top_left * worldToLocalTransform; + + + for(int i=0; iconvertLatLongHeightToXYZ(pos.y(), pos.x(), height, pos.x(), pos.y(),pos.z()); + + osg::Vec4& tc = (*texcoords)[i]; + + osg::Vec3d pos_right = osg::Vec3d(location.x()+location[2], location.y(), 0.0) * matrix; + em->convertLatLongHeightToXYZ(pos_right.y(), pos_right.x(), height, pos_right.x(), pos_right.y(),pos_right.z()); + + osg::Vec3d pos_up = osg::Vec3d(location.x(), location.y()+location[3], 0.0) * matrix; + em->convertLatLongHeightToXYZ(pos_up.y(), pos_up.x(), height, pos_up.x(), pos_up.y(),pos_up.z()); + + double length_right = (pos_right-pos).length(); + double length_up = (pos_up-pos).length(); + tc[2] = 1.0/length_right; + tc[3] = 1.0/length_up; + + + osg::Vec3d normal(pos); + normal = osg::Matrixd::transform3x3(localToWorldTransform, normal); + normal.normalize(); + + pos = pos * worldToLocalTransform; + pos -= center; + + (*vertices)[i] = pos; + (*normals)[i] = normal; + + } + + } + } + + // double tileWidth = (bottom_right-bottom_left).length(); + // double skirtHeight = tileWidth*0.05; + + // OSG_NOTICE<<" in local coords : center = "< GeometryPool::getTileSubgraph(osgTerrain::TerrainTile* tile) +{ + // create or reuse Geometry + osg::ref_ptr geometry = getOrCreateGeometry(tile); + + + osg::ref_ptr hfDrawable = new HeightFieldDrawable(); + + osgTerrain::HeightFieldLayer* hfl = dynamic_cast(tile->getElevationLayer()); + osg::HeightField* hf = hfl ? hfl->getHeightField() : 0; + hfDrawable->setHeightField(hf); + hfDrawable->setGeometry(geometry.get()); + + + // create a transform to place the geometry in the appropriate place + osg::ref_ptr transform = new osg::MatrixTransform; + +// transform->addChild(geometry.get()); + transform->addChild(hfDrawable.get()); + + const osgTerrain::Locator* locator = computeMasterLocator(tile); + if (locator) + { + osg::Matrixd matrix = locator->getTransform(); + + osg::Vec3d center = osg::Vec3d(0.5, 0.5, 0.0) * matrix; + + // shift to center.x() to x=0 and carry all the corners with it. + const osg::EllipsoidModel* em = locator->getEllipsoidModel(); + if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) + { + osg::Matrixd localToWorldTransform; + // note y axis maps to latitude, x axis to longitude + em->computeLocalToWorldTransformFromLatLongHeight(center.y(), center.x(), center.z(), localToWorldTransform); + // OSG_NOTICE<<"We have a EllipsoidModel to take account of "<setMatrix(localToWorldTransform); + + //osgDB::writeNodeFile(*transform, "subgraph.osgt"); + } + else + { + transform->setMatrix(locator->getTransform()); + } + } + + osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); + osg::Vec3Array* normals = dynamic_cast(geometry->getNormalArray()); + if (hf && vertices && normals && (vertices->size()==normals->size())) + { + unsigned int nr = hf->getNumRows(); + unsigned int nc = hf->getNumColumns(); + + osg::BoundingBox bb; + osg::FloatArray* heights = hf->getFloatArray(); + + for(unsigned int r=0; rsetInitialBound(bb); + // OSG_NOTICE<<"Assigning initial bound ("<getBoundingBox(); + //OSG_NOTICE<<" getBoundingBox ("< stateset = transform->getOrCreateStateSet(); + + // apply colour layers + applyLayers(tile, stateset.get()); + + return transform; +} + +osg::ref_ptr GeometryPool::getOrCreateProgram(LayerTypes& layerTypes) +{ +#if 0 + OSG_NOTICE<<"getOrCreateProgram("; + for(LayerTypes::iterator itr = layerTypes.begin(); + itr != layerTypes.end(); + ++itr) + { + if (itr!= layerTypes.begin()) OSG_NOTICE<<", "; + switch(*itr) + { + case(HEIGHTFIELD_LAYER): OSG_NOTICE<<"HeightField"; break; + case(COLOR_LAYER): OSG_NOTICE<<"Colour"; break; + case(CONTOUR_LAYER): OSG_NOTICE<<"Contour"; break; + } + } +#endif + + OpenThreads::ScopedLock lock(_programMapMutex); + ProgramMap::iterator itr = _programMap.find(layerTypes); + if (itr!=_programMap.end()) + { + // OSG_NOTICE<<") returning exisitng Program "<second.get()<second.get(); + } + + osg::ref_ptr program = new osg::Program; + _programMap[layerTypes] = program; + + // OSG_NOTICE<<") creating new Program "< vertex_shader = osgDB::readShaderFile("shaders/terrain.vert"); + program->addShader(vertex_shader.get()); + + osg::ref_ptr fragment_shader = osgDB::readShaderFile("shaders/terrain.frag"); + program->addShader(fragment_shader.get()); + + return program; +} + +void GeometryPool::applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset) +{ + typedef std::map LayerToTextureMap; + LayerToTextureMap layerToTextureMap; + + // OSG_NOTICE<<"tile->getNumColorLayers() = "<getNumColorLayers()<(tile->getElevationLayer()); + if (hfl) + { + osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[hfl]); + if (!texture2D) + { + texture2D = new osg::Texture2D; + + osg::ref_ptr image = new osg::Image; + + const void* dataPtr = hfl->getHeightField()->getFloatArray()->getDataPointer(); + + image->setImage(hfl->getNumRows(), hfl->getNumColumns(), 1, + GL_LUMINANCE32F_ARB, + GL_LUMINANCE, GL_FLOAT, + reinterpret_cast(const_cast(dataPtr)), + osg::Image::NO_DELETE); + + texture2D->setImage(image.get()); + texture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST); + texture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST); + texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP); + texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP); + texture2D->setBorderColor(osg::Vec4d(0.0,0.0,0.0,0.0)); + texture2D->setResizeNonPowerOfTwoHint(false); + + layerToTextureMap[hfl] = texture2D; + } + + int textureUnit = layerTypes.size(); + stateset->setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON); + stateset->addUniform(new osg::Uniform("terrainTexture",textureUnit)); + + layerTypes.push_back(HEIGHTFIELD_LAYER); + } +#if 1 + for(unsigned int layerNum=0; layerNumgetNumColorLayers(); ++layerNum) + { + osgTerrain::Layer* colorLayer = tile->getColorLayer(layerNum); + if (!colorLayer) continue; + + osgTerrain::SwitchLayer* switchLayer = dynamic_cast(colorLayer); + if (switchLayer) + { + if (switchLayer->getActiveLayer()<0 || + static_cast(switchLayer->getActiveLayer())>=switchLayer->getNumLayers()) + { + continue; + } + + colorLayer = switchLayer->getLayer(switchLayer->getActiveLayer()); + if (!colorLayer) continue; + } + + osg::Image* image = colorLayer->getImage(); + if (!image) continue; + + osgTerrain::ImageLayer* imageLayer = dynamic_cast(colorLayer); + osgTerrain::ContourLayer* contourLayer = dynamic_cast(colorLayer); + if (imageLayer) + { + osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[colorLayer]); + if (!texture2D) + { + texture2D = new osg::Texture2D; + texture2D->setImage(image); + texture2D->setMaxAnisotropy(16.0f); + texture2D->setResizeNonPowerOfTwoHint(false); + + texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter()); + texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); + + texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); + texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); + + bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST); + bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1)); + bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1)); + + if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo)) + { + OSG_INFO<<"Disabling mipmapping for non power of two tile size("<s()<<", "<t()<<")"<setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + } + + + layerToTextureMap[colorLayer] = texture2D; + + // OSG_NOTICE<<"Creating new ImageLayer texture "<s()="<s()<<" image->t()="<t()<setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON); + + std::stringstream str; + str<<"colorTexture"<addUniform(new osg::Uniform(str.str().c_str(),textureUnit)); + + layerTypes.push_back(COLOR_LAYER); + + } + else if (contourLayer) + { + osg::Texture1D* texture1D = dynamic_cast(layerToTextureMap[colorLayer]); + if (!texture1D) + { + texture1D = new osg::Texture1D; + texture1D->setImage(image); + texture1D->setResizeNonPowerOfTwoHint(false); + texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); + texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); + + layerToTextureMap[colorLayer] = texture1D; + } + + int textureUnit = layerTypes.size(); + stateset->setTextureAttributeAndModes(textureUnit, texture1D, osg::StateAttribute::ON); + + std::stringstream str; + str<<"contourTexture"<addUniform(new osg::Uniform(str.str().c_str(),textureUnit)); + + layerTypes.push_back(CONTOUR_LAYER); + } + } +#endif + + osg::ref_ptr program = getOrCreateProgram(layerTypes); + if (program.valid()) + { + stateset->setAttribute(program.get()); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// HeightFieldDrawable +// +HeightFieldDrawable::HeightFieldDrawable() +{ + setSupportsDisplayList(false); +} + +HeightFieldDrawable::HeightFieldDrawable(const HeightFieldDrawable& rhs,const osg::CopyOp& copyop): + osg::Drawable(rhs, copyop), + _heightField(rhs._heightField), + _geometry(rhs._geometry) +{ + setSupportsDisplayList(false); +} + +void HeightFieldDrawable::drawImplementation(osg::RenderInfo& renderInfo) const +{ + if (_geometry.valid()) _geometry->draw(renderInfo); +} + +void HeightFieldDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const +{ + if (_geometry.valid()) _geometry->compileGLObjects(renderInfo); +} + +void HeightFieldDrawable::resizeGLObjectBuffers(unsigned int maxSize) +{ + if (_geometry.valid()) _geometry->resizeGLObjectBuffers(maxSize); +} + +void HeightFieldDrawable::releaseGLObjects(osg::State* state) const +{ + if (_geometry.valid()) _geometry->releaseGLObjects(state); +} + +void HeightFieldDrawable::accept(osg::Drawable::AttributeFunctor& af) +{ + if (_geometry) _geometry->accept(af); +} + +void HeightFieldDrawable::accept(osg::Drawable::ConstAttributeFunctor& caf) const +{ + if (_geometry) _geometry->accept(caf); +} + +void HeightFieldDrawable::accept(osg::PrimitiveFunctor& pf) const +{ + if (_geometry) _geometry->accept(pf); +} + +void HeightFieldDrawable::accept(osg::PrimitiveIndexFunctor& pif) const +{ + if (_geometry) _geometry->accept(pif); +}