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 "Patch" 00020 #include "PatchSet" 00021 00022 #include <algorithm> 00023 #include <iterator> 00024 00025 #include <OpenThreads/Mutex> 00026 #include <OpenThreads/ScopedLock> 00027 00028 #include <osg/Vec3d> 00029 00030 namespace seamless 00031 { 00032 using namespace osg; 00033 00034 class MyNodeAcceptOp : public NodeAcceptOp 00035 { 00036 public: 00037 MyNodeAcceptOp(NodeVisitor& nv) : NodeAcceptOp(nv) {} 00038 MyNodeAcceptOp(const NodeAcceptOp& naop) : NodeAcceptOp(naop) {} 00039 template<typename T> 00040 void operator()(T node) { return node->accept(_nv); } 00041 }; 00042 00043 Patch::Patch() 00044 : _errorThreshold(.5f) 00045 { 00046 } 00047 00048 Patch::Patch(const Patch& rhs, const CopyOp& copyop) 00049 : Node(rhs, copyop), _errorThreshold(rhs._errorThreshold) 00050 { 00051 for (int res = 0; res < 2; ++res) 00052 for (int i = 0; i < 4; ++i) 00053 _trile[res][i] 00054 = static_cast<Geode*>(copyop(rhs._trile[res][i].get())); 00055 for (int strip = 0; strip < 4; ++strip) 00056 for (int i = 0; i < 4; ++i) 00057 _strip[strip][i] 00058 = static_cast<Geode*>(copyop(rhs._strip[strip][i].get())); 00059 _data =static_cast<Data*>(copyop(rhs._data.get())); 00060 _patchSet = static_cast<PatchSet*>(copyop(rhs._patchSet.get())); 00061 } 00062 00063 Patch::~Patch() 00064 { 00065 } 00066 00067 Patch::Data::Data() 00068 { 00069 } 00070 00071 Patch::Data::Data(const Patch::Data& rhs, const osg::CopyOp& copyop) 00072 : vertexData(rhs.vertexData, copyop), normalData(rhs.normalData, copyop), 00073 colorData(rhs.colorData, copyop), 00074 secondaryColorData(rhs.secondaryColorData, copyop), 00075 fogCoordData(rhs.fogCoordData, copyop) 00076 { 00077 for (Geometry::ArrayDataList::const_iterator 00078 itr = rhs.texCoordList.begin(), end = rhs.texCoordList.end(); 00079 itr !=end; 00080 ++itr) 00081 texCoordList.push_back(Geometry::ArrayData(*itr, copyop)); 00082 for (Geometry::ArrayDataList::const_iterator 00083 itr = rhs.vertexAttribList.begin(), 00084 end = rhs.vertexAttribList.end(); 00085 itr !=end; 00086 ++itr) 00087 vertexAttribList.push_back(Geometry::ArrayData(*itr, copyop)); 00088 } 00089 00090 void Patch::dirtyVertexData() 00091 { 00092 Geometry::ArrayData& vdata = _data->vertexData; 00093 if (vdata.array.valid()) 00094 vdata.array->dirty(); 00095 } 00096 00097 void Patch::Data::getGeometryAttributes(const Geometry* geom) 00098 { 00099 vertexData = geom->getVertexData(); 00100 normalData = geom->getNormalData(); 00101 colorData = geom->getColorData(); 00102 secondaryColorData = geom->getSecondaryColorData(); 00103 fogCoordData = geom->getFogCoordData(); 00104 texCoordList.clear(); 00105 const Geometry::ArrayDataList& texList = geom->getTexCoordArrayList(); 00106 std::copy(texList.begin(), texList.end(), std::back_inserter(texCoordList)); 00107 vertexAttribList.clear(); 00108 const Geometry::ArrayDataList& vaList = geom->getVertexAttribArrayList(); 00109 std::copy(vaList.begin(), vaList.end(), 00110 std::back_inserter(vertexAttribList)); 00111 } 00112 00113 void Patch::Data::setGeometryAttributes(Geometry* geom) 00114 { 00115 geom->setVertexData(vertexData); 00116 geom->setNormalData(normalData); 00117 geom->setColorData(colorData); 00118 geom->setSecondaryColorData(secondaryColorData); 00119 geom->setFogCoordData(fogCoordData); 00120 const Geometry::ArrayData emptyData; 00121 unsigned numTexCoords = geom->getNumTexCoordArrays(); 00122 for (unsigned i = 0; i < texCoordList.size(); ++i) 00123 geom->setTexCoordData(i, texCoordList[i]); 00124 for (unsigned i = texCoordList.size(); i < numTexCoords; ++i) 00125 geom->setTexCoordData(i, emptyData); 00126 unsigned numVertAttribs = geom->getNumVertexAttribArrays(); 00127 for (unsigned i = vertexAttribList.size(); i < vertexAttribList.size(); ++i) 00128 geom->setVertexAttribData(i, vertexAttribList[i]); 00129 for (unsigned i = vertexAttribList.size(); i < numVertAttribs; ++i) 00130 geom->setVertexAttribData(i, emptyData); 00131 } 00132 00133 void Patch::init() 00134 { 00135 for (int res = 0; res < 2; ++res) 00136 { 00137 for (int trile = 0; trile < 4; ++trile) 00138 { 00139 Geometry* geom = new Geometry; 00140 geom->setUseVertexBufferObjects(true); 00141 _data->setGeometryAttributes(geom); 00142 geom->addPrimitiveSet(_patchSet->trilePset[res][trile]); 00143 _trile[res][trile] = new Geode; 00144 _trile[res][trile]->addDrawable(geom); 00145 } 00146 } 00147 for (int j = 0; j < 4; ++j) 00148 { 00149 for (int i = 0; i < 4; ++i) 00150 { 00151 Geometry* geom = new Geometry; 00152 geom->setUseVertexBufferObjects(true); 00153 _data->setGeometryAttributes(geom); 00154 geom->addPrimitiveSet(_patchSet->stripPset[j][i]); 00155 _strip[j][i] = new Geode; 00156 _strip[j][i]->addDrawable(geom); 00157 } 00158 } 00159 } 00160 00161 // Find the point closest to P3 on the line segment from P1 to P2 00162 Vec3 closestPointOnSegment(const Vec3& p1, const Vec3& p2, const Vec3& p3) 00163 { 00164 Vec3 vec = p2 - p1; 00165 float len2 = vec.length2(); 00166 if (equivalent(len2, 0)) 00167 return p1; 00168 float u = ((p3 - p1) * vec) / len2; 00169 if (u <= 0.0) 00170 return p1; 00171 else if (u >= 1.0) 00172 return p2; 00173 else 00174 return p1 + vec * u; 00175 } 00176 00177 float distanceToSegment(const Vec3& p1, const Vec3& p2, const Vec3& p3) 00178 { 00179 Vec3 pt = closestPointOnSegment(p1, p2, p3); 00180 return (p3 - pt).length(); 00181 } 00182 00183 namespace 00184 { 00185 // Map from edge number to grid coordinates at the end points. The 00186 // values are multiplied by the patch resolution. 00187 int edgeCoords[4][2][2] = {{{0, 0}, {1, 0}}, 00188 {{1, 0}, {1, 1}}, 00189 {{1, 1}, {0, 1}}, 00190 {{0, 1}, {0,0}}}; 00191 00192 // Get the geometric coordinates of edge end points. 00193 inline void getEdge(const Patch* patch, Vec3& p1, Vec3& p2, int edgeNo) 00194 { 00195 PatchSet* ps = patch->getPatchSet(); 00196 int psRes = ps->getResolution(); // patch dimension - 1 00197 int coords[2][2]; 00198 for (int j = 0; j < 2; ++j) 00199 for (int i = 0; i < 2; ++i) 00200 coords[j][i] = edgeCoords[edgeNo][j][i] * psRes; 00201 Vec3Array* verts 00202 = static_cast<Vec3Array*>(patch->getData()->vertexData.array.get()); 00203 p1 = (*verts)[ps->makeIndex(coords[0][0], coords[0][1])]; 00204 p2 = (*verts)[ps->makeIndex(coords[1][0], coords[1][1])]; 00205 } 00206 } 00207 00208 float Patch::getEdgeError(const Vec3& eye, int edge) 00209 { 00210 Vec3 p1, p2; 00211 getEdge(this, p1, p2, edge); 00212 float len = (p2 - p1).length(); 00213 Vec3 closestPt = closestPointOnSegment(p1, p2, eye); 00214 float d = (closestPt - eye).length(); 00215 return _patchSet->getPrecisionFactor() * len / d; 00216 } 00217 00218 float Patch::getPatchError(const Vec3& eye) 00219 { 00220 float epsilon = getEdgeError(eye, 0); 00221 for (int i = 1; i < 4; ++i) 00222 epsilon = maximum(epsilon, getEdgeError(eye, i)); 00223 return epsilon; 00224 } 00225 void Patch::traverse(NodeVisitor& nv) 00226 { 00227 if (!_trile[0][0].valid()) 00228 return; 00229 if (nv.getTraversalMode() == NodeVisitor::TRAVERSE_ALL_CHILDREN) 00230 { 00231 std::for_each(&_trile[0][0], &_trile[1][3] + 1, MyNodeAcceptOp(nv)); 00232 std::for_each(&_strip[0][0], &_strip[3][3] + 1, MyNodeAcceptOp(nv)); 00233 return; 00234 } 00235 if (nv.getTraversalMode() != NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) 00236 return; 00237 float epsilon[4]; 00238 int res[4]; // Resolution of each edge / trile. 00239 // Get error value for edges 00240 Vec3 eye = nv.getViewPoint(); 00241 for (int i = 0; i < 4; ++i) 00242 { 00243 epsilon[i] = getEdgeError(eye, i); 00244 if (epsilon[i] > _errorThreshold) 00245 res[i] = 1; 00246 else 00247 res[i] = 0; 00248 } 00249 00250 for (int i = 0; i < 4; ++i) 00251 _trile[res[i]][i]->accept(nv); 00252 // Now choose a strip 00253 for (int i = 0; i < 4; ++i) 00254 { 00255 // One neighbor is trile i; the other is clockwise. 00256 int neighbor = (i - 1 + 4) % 4; 00257 int strip = res[neighbor] * 2 + res[i]; 00258 _strip[strip][i]->accept(nv); 00259 } 00260 } 00261 00262 BoundingSphere Patch::computeBound() const 00263 { 00264 BoundingSphere bsphere; 00265 if (!_trile[0][0].valid()) 00266 return bsphere; 00267 BoundingBox bb; 00268 bb.init(); 00269 for (int res = 0; res < 2; ++res) 00270 for (int i = 0; i < 4; ++i) 00271 bb.expandBy(_trile[res][i]->getBoundingBox()); 00272 for (int strip = 0; strip < 4; ++strip) 00273 for (int i = 0; i < 4; ++i) 00274 bb.expandBy(_strip[strip][i]->getBoundingBox()); 00275 if (!bb.valid()) 00276 return bsphere; 00277 bsphere.expandBy(bb); 00278 return bsphere; 00279 } 00280 00281 void Patch::resizeGLObjectBuffers(unsigned int maxSize) 00282 { 00283 Node::resizeGLObjectBuffers(maxSize); 00284 00285 if (!_trile[0][0].valid()) 00286 return; 00287 for (int res = 0; res < 2; ++res) 00288 for (int i = 0; i < 4; ++i) 00289 _trile[res][i]->resizeGLObjectBuffers(maxSize); 00290 } 00291 00292 void Patch::releaseGLObjects(State* state) const 00293 { 00294 Node::releaseGLObjects(state); 00295 if (!_trile[0][0].valid()) 00296 return; 00297 for (int res = 0; res < 2; ++res) 00298 for (int i = 0; i < 4; ++i) 00299 _trile[res][i]->releaseGLObjects(state); 00300 } 00301 00302 void Patch::setPatchSet(PatchSet* patchSet) 00303 { 00304 _patchSet = patchSet; 00305 } 00306 00307 PatchSet* Patch::getPatchSet() const 00308 { 00309 return _patchSet.get(); 00310 } 00311 00312 }