1
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
2
* Copyright 2010 Pelican Ventures, Inc.
5
* osgEarth is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU Lesser General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>
24
#include <osg/MatrixTransform>
25
#include <osg/StateSet>
26
#include <osg/Texture2D>
28
#include <osgEarth/GeoData>
29
#include <osgEarth/HeightFieldUtils>
30
#include <osgEarth/ThreadingUtils>
36
using namespace osgEarth;
38
class ProjectedOptions : public PatchOptions
44
ProjectedOptions(string& str)
48
ProjectedOptions(const ProjectedOptions& rhs,
49
const CopyOp& copyop = CopyOp::SHALLOW_COPY)
50
: PatchOptions(rhs, copyop)
58
// Create a tile key for the map using the normalized patch
59
// extents. This might look a little dicey, but there is enough
60
// precision in the extents to recover the integer tile key
61
// coordinates up to a LOD of 56. That should be sufficient :)
63
TileKey makeTileKey(const Projected* ps, const ProjectedOptions* pjoptions)
66
pjoptions->getPatchExtents(ll, ur);
67
double levelFactor = pow(2.0, pjoptions->getPatchLevel());
68
int x = static_cast<int>(ll.x() * levelFactor);
69
int y = static_cast<int>(ll.y() * levelFactor);
70
return TileKey(pjoptions->getPatchLevel(), x, y,
71
ps->getMap()->getProfile());
74
HeightField* resampleHeightField(HeightField* hf, unsigned newDim)
76
const unsigned nCols = hf->getNumColumns();
77
const unsigned nRows = hf->getNumRows();
78
if (nCols == newDim && nRows == newDim)
80
HeightField* result = new HeightField;
81
result->allocate(newDim, newDim);
82
result->setOrigin(hf->getOrigin());
83
result->setXInterval(hf->getXInterval() * static_cast<float>(nCols)
84
/ static_cast<float>(newDim));
85
result->setYInterval(hf->getYInterval() * static_cast<float>(nRows)
86
/ static_cast<float>(newDim));
87
for (unsigned r = 0; r < newDim; ++r)
89
for (unsigned c = 0; c < newDim; ++c)
92
= HeightFieldUtils::getHeightAtNormalizedLocation(
93
hf, static_cast<double>(c) / (newDim - 1),
94
static_cast<double>(r) / (newDim - 1), INTERP_BILINEAR);
95
result->setHeight(c, r, height);
102
// Hard-wire the screen-space polygon size.
103
Projected::Projected(const Map* map,
104
const osgEarth::Drivers::SeamlessOptions& options)
107
setPrecisionFactor(8);
111
const ElevationLayerVector& elevations = _mapf->elevationLayers();
112
for (ElevationLayerVector::const_iterator itr = elevations.begin(),
113
end = elevations.end();
117
const TerrainLayerOptions& options
118
= (*itr)->getTerrainLayerOptions();
119
if (options.maxLevel().isSet()
120
&& options.maxLevel().get() > maxLevel)
121
maxLevel = options.maxLevel().get();
124
setMaxLevel(maxLevel);
128
Transform* Projected::createPatch(const std::string& filename,
129
PatchOptions* poptions)
131
Patch* patch = new Patch;
132
patch->setPatchSet(this);
133
ProjectedOptions* pjoptions = static_cast<ProjectedOptions*>(poptions);
135
= makeTileKey(static_cast<Projected*>(patch->getPatchSet()), pjoptions);
136
const GeoExtent& extent = key.getExtent();
137
double xMin = extent.xMin(), yMin = extent.yMin();
138
double centerX, centerY;
139
extent.getCentroid(centerX, centerY);
140
MatrixTransform* transform = new MatrixTransform;
141
Matrixd mat = Matrixd::translate(centerX, centerY, 0.0);
142
transform->setMatrix(mat);
143
transform->addChild(patch);
144
ref_ptr<HeightField> hf;
147
_mapf->getHeightField(key, true, hf, INTERP_BILINEAR);
148
const ImageLayerVector& layers = _mapf->imageLayers();
150
gimage = layers[0]->createImage(key);
152
ref_ptr<Patch::Data> data = new Patch::Data;
153
int patchDim = _resolution + 1;
154
hf = resampleHeightField(hf, patchDim);
155
Vec3Array* verts = new Vec3Array(patchDim * patchDim);
156
Vec3Array* normals = new Vec3Array(patchDim * patchDim);
157
Vec2f minCoord(xMin - centerX, yMin - centerY);
158
float xInt = hf->getXInterval(), yInt = hf->getYInterval();
159
for (int j = 0; j < patchDim; ++j)
160
for (int i = 0; i < patchDim; ++i)
162
(*verts)[patchDim * j + i] = Vec3(
163
minCoord.x() + xInt * i, minCoord.y() + yInt * j,
164
hf->getHeight(i, j) * getVerticalScale());
165
// XXX normals change if verticalScale != 1.0
166
(*normals)[patchDim * j + i] = hf->getNormal(i, j);
168
data->vertexData.array = verts;
169
data->vertexData.binding = Geometry::BIND_PER_VERTEX;
170
data->normalData.array = normals;
171
data->normalData.binding = Geometry::BIND_PER_VERTEX;
172
Vec4Array* colors = new Vec4Array(1);
173
(*colors)[0] = Vec4(1.0, 1.0, 1.0, 1.0);
174
data->colorData.array = colors;
175
data->colorData.binding = Geometry::BIND_OVERALL;
178
Texture2D* tex = new Texture2D();
179
tex->setImage(gimage.getImage());
180
tex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
181
tex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
182
tex->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR);
183
tex->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
184
StateSet* ss = patch->getOrCreateStateSet();
185
ss->setTextureAttributeAndModes(0, tex, StateAttribute::ON);
187
Vec2Array* texCoords = new Vec2Array(patchDim * patchDim);
188
for (int j = 0; j < patchDim; ++j)
189
for (int i = 0; i < patchDim; ++i)
190
(*texCoords)[patchDim * j + i]
191
= Vec2(static_cast<float>(i) / (patchDim - 1),
192
static_cast<float>(j) / (patchDim - 1));
194
.push_back(Geometry::ArrayData(texCoords, Geometry::BIND_PER_VERTEX));
195
patch->setData(data);