osgEarth 2.1.1
|
00001 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00002 * Copyright 2010 Pelican Ventures, Inc. 00003 * http://osgearth.org 00004 * 00005 * osgEarth is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/> 00017 */ 00018 00019 #include "Projected" 00020 00021 #include <string> 00022 00023 #include <osg/Math> 00024 #include <osg/MatrixTransform> 00025 #include <osg/StateSet> 00026 #include <osg/Texture2D> 00027 00028 #include <osgEarth/GeoData> 00029 #include <osgEarth/HeightFieldUtils> 00030 #include <osgEarth/ThreadingUtils> 00031 00032 namespace seamless 00033 { 00034 using namespace std; 00035 using namespace osg; 00036 using namespace osgEarth; 00037 00038 class ProjectedOptions : public PatchOptions 00039 { 00040 public: 00041 ProjectedOptions() 00042 { 00043 } 00044 ProjectedOptions(string& str) 00045 : PatchOptions(str) 00046 { 00047 } 00048 ProjectedOptions(const ProjectedOptions& rhs, 00049 const CopyOp& copyop = CopyOp::SHALLOW_COPY) 00050 : PatchOptions(rhs, copyop) 00051 { 00052 00053 } 00054 }; 00055 00056 namespace 00057 { 00058 // Create a tile key for the map using the normalized patch 00059 // extents. This might look a little dicey, but there is enough 00060 // precision in the extents to recover the integer tile key 00061 // coordinates up to a LOD of 56. That should be sufficient :) 00062 00063 TileKey makeTileKey(const Projected* ps, const ProjectedOptions* pjoptions) 00064 { 00065 Vec2d ll, ur; 00066 pjoptions->getPatchExtents(ll, ur); 00067 double levelFactor = pow(2.0, pjoptions->getPatchLevel()); 00068 int x = static_cast<int>(ll.x() * levelFactor); 00069 int y = static_cast<int>(ll.y() * levelFactor); 00070 return TileKey(pjoptions->getPatchLevel(), x, y, 00071 ps->getMap()->getProfile()); 00072 } 00073 00074 HeightField* resampleHeightField(HeightField* hf, unsigned newDim) 00075 { 00076 const unsigned nCols = hf->getNumColumns(); 00077 const unsigned nRows = hf->getNumRows(); 00078 if (nCols == newDim && nRows == newDim) 00079 return hf; 00080 HeightField* result = new HeightField; 00081 result->allocate(newDim, newDim); 00082 result->setOrigin(hf->getOrigin()); 00083 result->setXInterval(hf->getXInterval() * static_cast<float>(nCols) 00084 / static_cast<float>(newDim)); 00085 result->setYInterval(hf->getYInterval() * static_cast<float>(nRows) 00086 / static_cast<float>(newDim)); 00087 for (unsigned r = 0; r < newDim; ++r) 00088 { 00089 for (unsigned c = 0; c < newDim; ++c) 00090 { 00091 float height 00092 = HeightFieldUtils::getHeightAtNormalizedLocation( 00093 hf, static_cast<double>(c) / (newDim - 1), 00094 static_cast<double>(r) / (newDim - 1), INTERP_BILINEAR); 00095 result->setHeight(c, r, height); 00096 } 00097 } 00098 return result; 00099 } 00100 } 00101 00102 // Hard-wire the screen-space polygon size. 00103 Projected::Projected(const Map* map, 00104 const osgEarth::Drivers::SeamlessOptions& options) 00105 : PatchSet(options) 00106 { 00107 setPrecisionFactor(8); 00108 setMap(map); 00109 { 00110 int maxLevel = 0; 00111 const ElevationLayerVector& elevations = _mapf->elevationLayers(); 00112 for (ElevationLayerVector::const_iterator itr = elevations.begin(), 00113 end = elevations.end(); 00114 itr != end; 00115 ++itr) 00116 { 00117 const TerrainLayerOptions& options 00118 = (*itr)->getTerrainLayerOptions(); 00119 if (options.maxLevel().isSet() 00120 && options.maxLevel().get() > maxLevel) 00121 maxLevel = options.maxLevel().get(); 00122 } 00123 if (maxLevel > 0) 00124 setMaxLevel(maxLevel); 00125 } 00126 } 00127 00128 Transform* Projected::createPatch(const std::string& filename, 00129 PatchOptions* poptions) 00130 { 00131 Patch* patch = new Patch; 00132 patch->setPatchSet(this); 00133 ProjectedOptions* pjoptions = static_cast<ProjectedOptions*>(poptions); 00134 TileKey key 00135 = makeTileKey(static_cast<Projected*>(patch->getPatchSet()), pjoptions); 00136 const GeoExtent& extent = key.getExtent(); 00137 double xMin = extent.xMin(), yMin = extent.yMin(); 00138 double centerX, centerY; 00139 extent.getCentroid(centerX, centerY); 00140 MatrixTransform* transform = new MatrixTransform; 00141 Matrixd mat = Matrixd::translate(centerX, centerY, 0.0); 00142 transform->setMatrix(mat); 00143 transform->addChild(patch); 00144 ref_ptr<HeightField> hf; 00145 GeoImage gimage; 00146 { 00147 _mapf->getHeightField(key, true, hf, 0L, INTERP_BILINEAR); 00148 const ImageLayerVector& layers = _mapf->imageLayers(); 00149 if (!layers.empty()) 00150 gimage = layers[0]->createImage(key); 00151 } 00152 ref_ptr<Patch::Data> data = new Patch::Data; 00153 int patchDim = _resolution + 1; 00154 hf = resampleHeightField(hf, patchDim); 00155 Vec3Array* verts = new Vec3Array(patchDim * patchDim); 00156 Vec3Array* normals = new Vec3Array(patchDim * patchDim); 00157 Vec2f minCoord(xMin - centerX, yMin - centerY); 00158 float xInt = hf->getXInterval(), yInt = hf->getYInterval(); 00159 for (int j = 0; j < patchDim; ++j) 00160 for (int i = 0; i < patchDim; ++i) 00161 { 00162 (*verts)[patchDim * j + i] = Vec3( 00163 minCoord.x() + xInt * i, minCoord.y() + yInt * j, 00164 hf->getHeight(i, j) * getVerticalScale()); 00165 // XXX normals change if verticalScale != 1.0 00166 (*normals)[patchDim * j + i] = hf->getNormal(i, j); 00167 } 00168 data->vertexData.array = verts; 00169 data->vertexData.binding = Geometry::BIND_PER_VERTEX; 00170 data->normalData.array = normals; 00171 data->normalData.binding = Geometry::BIND_PER_VERTEX; 00172 Vec4Array* colors = new Vec4Array(1); 00173 (*colors)[0] = Vec4(1.0, 1.0, 1.0, 1.0); 00174 data->colorData.array = colors; 00175 data->colorData.binding = Geometry::BIND_OVERALL; 00176 if (gimage.valid()) 00177 { 00178 Texture2D* tex = new Texture2D(); 00179 tex->setImage(gimage.getImage()); 00180 tex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE); 00181 tex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE); 00182 tex->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR); 00183 tex->setFilter(Texture::MAG_FILTER, Texture::LINEAR); 00184 StateSet* ss = patch->getOrCreateStateSet(); 00185 ss->setTextureAttributeAndModes(0, tex, StateAttribute::ON); 00186 } 00187 Vec2Array* texCoords = new Vec2Array(patchDim * patchDim); 00188 for (int j = 0; j < patchDim; ++j) 00189 for (int i = 0; i < patchDim; ++i) 00190 (*texCoords)[patchDim * j + i] 00191 = Vec2(static_cast<float>(i) / (patchDim - 1), 00192 static_cast<float>(j) / (patchDim - 1)); 00193 data->texCoordList 00194 .push_back(Geometry::ArrayData(texCoords, Geometry::BIND_PER_VERTEX)); 00195 patch->setData(data); 00196 return transform; 00197 } 00198 }