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 "PatchGroup" 00020 00021 #include <osg/Array> 00022 #include <osg/Geometry> 00023 #include <osg/Notify> 00024 #include <osg/Transform> 00025 #include <osgDB/FileNameUtils> 00026 #include <osgDB/Registry> 00027 00028 #include "Patch" 00029 #include "PatchSet" 00030 00031 namespace seamless 00032 { 00033 using namespace std; 00034 using namespace osg; 00035 00036 PatchGroup::PatchGroup() 00037 { 00038 setRangeMode(LOD::PIXEL_SIZE_ON_SCREEN); 00039 } 00040 00041 PatchGroup::PatchGroup(const PatchGroup& rhs, const CopyOp& copyop) 00042 : PagedLOD(rhs, copyop) 00043 { 00044 setRangeMode(LOD::PIXEL_SIZE_ON_SCREEN); 00045 } 00046 00047 PatchGroup::~PatchGroup() 00048 { 00049 } 00050 00051 // Work around for an interface change in osgDB::DatabasePager 00052 struct NodePathProxy 00053 { 00054 NodePathProxy(Group* group_, NodeVisitor& nv_) 00055 : group(group_), nv(nv_) 00056 { 00057 } 00058 operator Group* () { return group; } 00059 operator NodePath& () { return nv.getNodePath(); } 00060 Group* group; 00061 NodeVisitor& nv; 00062 }; 00063 00064 void PatchGroup::getPatchExtents(Vec2d& lowerLeft, Vec2d& upperRight) const 00065 { 00066 const PatchOptions* poptions = getOptions(); 00067 if (!poptions) 00068 { 00069 lowerLeft = Vec2d(0.0, 0.0); 00070 upperRight = Vec2d(1.0, 1.0); 00071 } 00072 else 00073 { 00074 poptions->getPatchExtents(lowerLeft, upperRight); 00075 } 00076 } 00077 00078 // Child 0 is the patch for this LOD. Child 1 is a group of the 4 00079 // patches for the next level. 00080 00081 // Copied and edited from PagedLOD::traverse. 00082 void PatchGroup::traverse(NodeVisitor& nv) 00083 { 00084 // set the frame number of the traversal so that external nodes can find out how active this 00085 // node is. 00086 if (nv.getFrameStamp() && 00087 nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) 00088 { 00089 setFrameNumberOfLastTraversal(nv.getFrameStamp()->getFrameNumber()); 00090 } 00091 00092 double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0; 00093 int frameNumber = nv.getFrameStamp()?nv.getFrameStamp()->getFrameNumber():0; 00094 bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR; 00095 00096 switch(nv.getTraversalMode()) 00097 { 00098 case(NodeVisitor::TRAVERSE_ALL_CHILDREN): 00099 std::for_each(_children.begin(),_children.end(),NodeAcceptOp(nv)); 00100 break; 00101 case(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN): 00102 { 00103 Vec3 eye = nv.getViewPoint(); 00104 if (_children.empty()) 00105 return; 00106 Transform* tform = static_cast<Transform*>(_children[0].get()); 00107 if (tform->getNumChildren() == 0) 00108 return; 00109 Matrix localMat; 00110 tform->computeWorldToLocalMatrix(localMat, &nv); 00111 eye = eye * localMat; 00112 Patch* patch = static_cast<Patch*>(tform->getChild(0)); 00113 float epsilon = patch->getPatchError(eye); 00114 00115 int lastChildTraversed = -1; 00116 bool needToLoadChild = false; 00117 // Range list is set up so that the error is [0,1] for the 00118 // patch at this level and (1, 1e10) for the next level. 00119 for(unsigned int i=0;i<_rangeList.size();++i) 00120 { 00121 if (_rangeList[i].first <= epsilon 00122 && epsilon < _rangeList[i].second) 00123 { 00124 if (i<_children.size()) 00125 { 00126 if (updateTimeStamp) 00127 { 00128 _perRangeDataList[i]._timeStamp=timeStamp; 00129 _perRangeDataList[i]._frameNumber=frameNumber; 00130 } 00131 00132 _children[i]->accept(nv); 00133 lastChildTraversed = (int)i; 00134 } 00135 else 00136 { 00137 needToLoadChild = true; 00138 } 00139 } 00140 } 00141 00142 if (needToLoadChild) 00143 { 00144 unsigned int numChildren = _children.size(); 00145 00146 // select the last valid child. 00147 if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed) 00148 { 00149 if (updateTimeStamp) 00150 { 00151 _perRangeDataList[numChildren-1]._timeStamp=timeStamp; 00152 _perRangeDataList[numChildren-1]._frameNumber=frameNumber; 00153 } 00154 _children[numChildren-1]->accept(nv); 00155 } 00156 00157 // now request the loading of the next unloaded child. 00158 if (!_disableExternalChildrenPaging && 00159 nv.getDatabaseRequestHandler() && 00160 numChildren<_perRangeDataList.size()) 00161 { 00162 // compute priority from where abouts in the required range the distance falls. 00163 float priority = (_rangeList[numChildren].second - epsilon)/(_rangeList[numChildren].second-_rangeList[numChildren].first); 00164 00165 // invert priority for PIXEL_SIZE_ON_SCREEN mode 00166 priority = -priority; 00167 00168 // modify the priority according to the child's priority offset and scale. 00169 priority = _perRangeDataList[numChildren]._priorityOffset + priority * _perRangeDataList[numChildren]._priorityScale; 00170 00171 if (_databasePath.empty()) 00172 { 00173 nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,NodePathProxy(this, nv),priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get()); 00174 } 00175 else 00176 { 00177 // prepend the databasePath to the child's filename. 00178 nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,NodePathProxy(this, nv),priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get()); 00179 } 00180 } 00181 00182 } 00183 break; 00184 } 00185 default: 00186 break; 00187 } 00188 } 00189 00190 PatchOptions::PatchOptions() 00191 : _lowerLeft(0.0, 0.0), _upperRight(1.0, 1.0), _level(0), 00192 _tileKey(osgEarth::TileKey::INVALID) 00193 { 00194 } 00195 00196 PatchOptions::PatchOptions(const std::string& str) 00197 : osgDB::Options(str), _lowerLeft(0.0, 0.0), _upperRight(1.0, 1.0), 00198 _level(0), _tileKey(osgEarth::TileKey::INVALID) 00199 { 00200 } 00201 00202 PatchOptions::PatchOptions(const PatchOptions& rhs, const CopyOp& copyop) 00203 : osgDB::Options(rhs, copyop), _lowerLeft(rhs._lowerLeft), 00204 _upperRight(rhs._upperRight), _level(rhs._level), _tileKey(rhs._tileKey) 00205 { 00206 _patchSet = static_cast<PatchSet*>(copyop(rhs._patchSet.get())); 00207 } 00208 00209 PatchOptions::~PatchOptions() 00210 { 00211 } 00212 00213 void PatchOptions::setPatchSet(PatchSet* patchSet) 00214 { 00215 _patchSet = patchSet; 00216 } 00217 00218 PatchSet* PatchOptions::getPatchSet() const 00219 { 00220 return _patchSet.get(); 00221 } 00222 00223 00224 }