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/>
25
#include <OpenThreads/Mutex>
26
#include <OpenThreads/ScopedLock>
34
class MyNodeAcceptOp : public NodeAcceptOp
37
MyNodeAcceptOp(NodeVisitor& nv) : NodeAcceptOp(nv) {}
38
MyNodeAcceptOp(const NodeAcceptOp& naop) : NodeAcceptOp(naop) {}
40
void operator()(T node) { return node->accept(_nv); }
44
: _errorThreshold(.5f)
48
Patch::Patch(const Patch& rhs, const CopyOp& copyop)
49
: Node(rhs, copyop), _errorThreshold(rhs._errorThreshold)
51
for (int res = 0; res < 2; ++res)
52
for (int i = 0; i < 4; ++i)
54
= static_cast<Geode*>(copyop(rhs._trile[res][i].get()));
55
for (int strip = 0; strip < 4; ++strip)
56
for (int i = 0; i < 4; ++i)
58
= static_cast<Geode*>(copyop(rhs._strip[strip][i].get()));
59
_data =static_cast<Data*>(copyop(rhs._data.get()));
60
_patchSet = static_cast<PatchSet*>(copyop(rhs._patchSet.get()));
71
Patch::Data::Data(const Patch::Data& rhs, const osg::CopyOp& copyop)
72
: vertexData(rhs.vertexData, copyop), normalData(rhs.normalData, copyop),
73
colorData(rhs.colorData, copyop),
74
secondaryColorData(rhs.secondaryColorData, copyop),
75
fogCoordData(rhs.fogCoordData, copyop)
77
for (Geometry::ArrayDataList::const_iterator
78
itr = rhs.texCoordList.begin(), end = rhs.texCoordList.end();
81
texCoordList.push_back(Geometry::ArrayData(*itr, copyop));
82
for (Geometry::ArrayDataList::const_iterator
83
itr = rhs.vertexAttribList.begin(),
84
end = rhs.vertexAttribList.end();
87
vertexAttribList.push_back(Geometry::ArrayData(*itr, copyop));
90
void Patch::dirtyVertexData()
92
Geometry::ArrayData& vdata = _data->vertexData;
93
if (vdata.array.valid())
97
void Patch::Data::getGeometryAttributes(const Geometry* geom)
99
vertexData = geom->getVertexData();
100
normalData = geom->getNormalData();
101
colorData = geom->getColorData();
102
secondaryColorData = geom->getSecondaryColorData();
103
fogCoordData = geom->getFogCoordData();
104
texCoordList.clear();
105
const Geometry::ArrayDataList& texList = geom->getTexCoordArrayList();
106
std::copy(texList.begin(), texList.end(), std::back_inserter(texCoordList));
107
vertexAttribList.clear();
108
const Geometry::ArrayDataList& vaList = geom->getVertexAttribArrayList();
109
std::copy(vaList.begin(), vaList.end(),
110
std::back_inserter(vertexAttribList));
113
void Patch::Data::setGeometryAttributes(Geometry* geom)
115
geom->setVertexData(vertexData);
116
geom->setNormalData(normalData);
117
geom->setColorData(colorData);
118
geom->setSecondaryColorData(secondaryColorData);
119
geom->setFogCoordData(fogCoordData);
120
const Geometry::ArrayData emptyData;
121
unsigned numTexCoords = geom->getNumTexCoordArrays();
122
for (unsigned i = 0; i < texCoordList.size(); ++i)
123
geom->setTexCoordData(i, texCoordList[i]);
124
for (unsigned i = texCoordList.size(); i < numTexCoords; ++i)
125
geom->setTexCoordData(i, emptyData);
126
unsigned numVertAttribs = geom->getNumVertexAttribArrays();
127
for (unsigned i = vertexAttribList.size(); i < vertexAttribList.size(); ++i)
128
geom->setVertexAttribData(i, vertexAttribList[i]);
129
for (unsigned i = vertexAttribList.size(); i < numVertAttribs; ++i)
130
geom->setVertexAttribData(i, emptyData);
135
for (int res = 0; res < 2; ++res)
137
for (int trile = 0; trile < 4; ++trile)
139
Geometry* geom = new Geometry;
140
geom->setUseVertexBufferObjects(true);
141
_data->setGeometryAttributes(geom);
142
geom->addPrimitiveSet(_patchSet->trilePset[res][trile]);
143
_trile[res][trile] = new Geode;
144
_trile[res][trile]->addDrawable(geom);
147
for (int j = 0; j < 4; ++j)
149
for (int i = 0; i < 4; ++i)
151
Geometry* geom = new Geometry;
152
geom->setUseVertexBufferObjects(true);
153
_data->setGeometryAttributes(geom);
154
geom->addPrimitiveSet(_patchSet->stripPset[j][i]);
155
_strip[j][i] = new Geode;
156
_strip[j][i]->addDrawable(geom);
161
// Find the point closest to P3 on the line segment from P1 to P2
162
Vec3 closestPointOnSegment(const Vec3& p1, const Vec3& p2, const Vec3& p3)
165
float len2 = vec.length2();
166
if (equivalent(len2, 0))
168
float u = ((p3 - p1) * vec) / len2;
177
float distanceToSegment(const Vec3& p1, const Vec3& p2, const Vec3& p3)
179
Vec3 pt = closestPointOnSegment(p1, p2, p3);
180
return (p3 - pt).length();
185
// Map from edge number to grid coordinates at the end points. The
186
// values are multiplied by the patch resolution.
187
int edgeCoords[4][2][2] = {{{0, 0}, {1, 0}},
192
// Get the geometric coordinates of edge end points.
193
inline void getEdge(const Patch* patch, Vec3& p1, Vec3& p2, int edgeNo)
195
PatchSet* ps = patch->getPatchSet();
196
int psRes = ps->getResolution(); // patch dimension - 1
198
for (int j = 0; j < 2; ++j)
199
for (int i = 0; i < 2; ++i)
200
coords[j][i] = edgeCoords[edgeNo][j][i] * psRes;
202
= static_cast<Vec3Array*>(patch->getData()->vertexData.array.get());
203
p1 = (*verts)[ps->makeIndex(coords[0][0], coords[0][1])];
204
p2 = (*verts)[ps->makeIndex(coords[1][0], coords[1][1])];
208
float Patch::getEdgeError(const Vec3& eye, int edge)
211
getEdge(this, p1, p2, edge);
212
float len = (p2 - p1).length();
213
Vec3 closestPt = closestPointOnSegment(p1, p2, eye);
214
float d = (closestPt - eye).length();
215
return _patchSet->getPrecisionFactor() * len / d;
218
float Patch::getPatchError(const Vec3& eye)
220
float epsilon = getEdgeError(eye, 0);
221
for (int i = 1; i < 4; ++i)
222
epsilon = maximum(epsilon, getEdgeError(eye, i));
225
void Patch::traverse(NodeVisitor& nv)
227
if (!_trile[0][0].valid())
229
if (nv.getTraversalMode() == NodeVisitor::TRAVERSE_ALL_CHILDREN)
231
std::for_each(&_trile[0][0], &_trile[1][3] + 1, MyNodeAcceptOp(nv));
232
std::for_each(&_strip[0][0], &_strip[3][3] + 1, MyNodeAcceptOp(nv));
235
if (nv.getTraversalMode() != NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
238
int res[4]; // Resolution of each edge / trile.
239
// Get error value for edges
240
Vec3 eye = nv.getViewPoint();
241
for (int i = 0; i < 4; ++i)
243
epsilon[i] = getEdgeError(eye, i);
244
if (epsilon[i] > _errorThreshold)
250
for (int i = 0; i < 4; ++i)
251
_trile[res[i]][i]->accept(nv);
252
// Now choose a strip
253
for (int i = 0; i < 4; ++i)
255
// One neighbor is trile i; the other is clockwise.
256
int neighbor = (i - 1 + 4) % 4;
257
int strip = res[neighbor] * 2 + res[i];
258
_strip[strip][i]->accept(nv);
262
BoundingSphere Patch::computeBound() const
264
BoundingSphere bsphere;
265
if (!_trile[0][0].valid())
269
for (int res = 0; res < 2; ++res)
270
for (int i = 0; i < 4; ++i)
271
bb.expandBy(_trile[res][i]->getBoundingBox());
272
for (int strip = 0; strip < 4; ++strip)
273
for (int i = 0; i < 4; ++i)
274
bb.expandBy(_strip[strip][i]->getBoundingBox());
277
bsphere.expandBy(bb);
281
void Patch::resizeGLObjectBuffers(unsigned int maxSize)
283
Node::resizeGLObjectBuffers(maxSize);
285
if (!_trile[0][0].valid())
287
for (int res = 0; res < 2; ++res)
288
for (int i = 0; i < 4; ++i)
289
_trile[res][i]->resizeGLObjectBuffers(maxSize);
292
void Patch::releaseGLObjects(State* state) const
294
Node::releaseGLObjects(state);
295
if (!_trile[0][0].valid())
297
for (int res = 0; res < 2; ++res)
298
for (int i = 0; i < 4; ++i)
299
_trile[res][i]->releaseGLObjects(state);
302
void Patch::setPatchSet(PatchSet* patchSet)
304
_patchSet = patchSet;
307
PatchSet* Patch::getPatchSet() const
309
return _patchSet.get();