root/OpenSceneGraph/trunk/src/osgPlugins/txp/TXPNode.cpp @ 11122

Revision 11122, 9.8 kB (checked in by robert, 4 years ago)

From Ryan Kawicki, "I guess I missed these during my testing, but if the database pager has outstanding requests while the application is shutting down, the archive can become invalidated through unsafe calls to ReaderWriterTXP::getArchive. I've made this function return a ref_ptr and change other locations to as needed to conform to the change. I've tested this and no more crashes.

Following files from revision 11057 have been attached."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Notify>
2#include <osg/BoundingBox>
3#include <osg/PagedLOD>
4#include <osg/Timer>
5#include <osg/MatrixTransform>
6#include <osgUtil/CullVisitor>
7#include <osgDB/Registry>
8#include <osgDB/ReaderWriter>
9
10#include <iostream>
11#include <vector>
12#include <algorithm>
13#include <stdio.h>
14
15#include "TileMapper.h"
16#include "TXPNode.h"
17#include "TXPPagedLOD.h"
18#include "ReaderWriterTXP.h"
19
20
21using namespace txp;
22using namespace osg;
23
24
25
26class RetestCallback : public osg::NodeCallback
27{
28
29public:
30    RetestCallback()
31    {
32        timer = osg::Timer::instance(); // get static timer
33        prevTime = 0; // should this be instantiated with current time?
34    }
35
36    virtual void operator () ( osg::Node * node, osg::NodeVisitor * nv )
37    {
38        osg::Group *pLOD = (osg::Group *) node;
39        osg::Group *n = NULL;
40        if ((pLOD->getNumChildren() > 0) &&
41            (n = (osg::Group *) pLOD->getChild(0)) &&
42            (n->getNumChildren() == 0))
43        {
44            osg::Timer_t curTime = timer->tick();
45            if ((prevTime + 2.0/timer->getSecondsPerTick() ) < curTime)
46            {
47                prevTime = curTime;
48                pLOD->removeChildren( 0, pLOD->getNumChildren());
49            }
50        }
51
52        NodeCallback::traverse( node, nv );
53    }
54
55protected:
56    const osg::Timer* timer;
57    osg::Timer_t prevTime;
58};
59
60
61
62#define TXPNodeERROR(s) osg::notify(osg::NOTICE) << "txp::TXPNode::" << (s) << " error: "
63
64TXPNode::TXPNode():
65osg::Group(),
66_originX(0.0),
67_originY(0.0)
68{
69    setNumChildrenRequiringUpdateTraversal(1);
70    setCullingActive(false);
71}
72           
73TXPNode::TXPNode(const TXPNode& txpNode,const osg::CopyOp& copyop):
74osg::Group(txpNode,copyop),
75_originX(txpNode._originX),
76_originY(txpNode._originY)
77{
78    setNumChildrenRequiringUpdateTraversal(1);
79}
80
81TXPNode::~TXPNode()
82{
83   if (_archive.get())
84   {
85      if (osgDB::ReaderWriter * rw =
86          osgDB::Registry::instance()->getReaderWriterForExtension("txp"))
87      {
88         if (ReaderWriterTXP * rwTXP =
89             dynamic_cast< ReaderWriterTXP * >(rw))
90         {
91            const int id = _archive->getId();
92            if (!rwTXP->removeArchive(id))
93            {
94               TXPNodeERROR("Failed to remove archive ") << id << std::endl;
95            }
96         }
97      }
98   }
99}
100
101void TXPNode::traverse(osg::NodeVisitor& nv)
102{
103    switch(nv.getVisitorType())
104    {
105    case osg::NodeVisitor::CULL_VISITOR:
106    {
107
108        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
109               
110        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
111        if (cv)
112        {
113//#define PRINT_TILEMAPP_TIMEINFO
114#ifdef PRINT_TILEMAPP_TIMEINFO
115            const osg::Timer& timer = *osg::Timer::instance();
116            osg::Timer_t start = timer.tick();
117            std::cout<<"Doing visible tile search"<<std::endl;
118#endif // PRINT_TILEMAPP_TIMEINFO
119       
120            osg::ref_ptr<TileMapper> tileMapper = new TileMapper;
121            tileMapper->setLODScale(cv->getLODScale());
122            tileMapper->pushReferenceViewPoint(cv->getReferenceViewPoint());
123            tileMapper->pushViewport(cv->getViewport());
124            tileMapper->pushProjectionMatrix((cv->getProjectionMatrix()));
125            tileMapper->pushModelViewMatrix((cv->getModelViewMatrix()), osg::Transform::RELATIVE_RF);
126
127            // traverse the scene graph to search for valid tiles
128            accept(*tileMapper);
129
130            tileMapper->popModelViewMatrix();
131            tileMapper->popProjectionMatrix();
132            tileMapper->popViewport();
133            tileMapper->popReferenceViewPoint();
134
135            //std::cout<<"   found " << tileMapper._tileMap.size() << std::endl;
136           
137            tileMapper->checkValidityOfAllVisibleTiles();
138           
139            cv->setUserData(tileMapper.get());
140
141#ifdef PRINT_TILEMAPP_TIMEINFO       
142            std::cout<<"Completed visible tile search in "<<timer.delta_m(start,timer.tick())<<std::endl;
143#endif // PRINT_TILEMAPP_TIMEINFO       
144
145        }       
146   
147        updateEye(nv);
148        break;
149    }
150    case osg::NodeVisitor::UPDATE_VISITOR:
151    {
152        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
153
154        updateSceneGraph();
155        break;
156    }
157    default:
158        break;
159    }
160    Group::traverse(nv);
161}
162
163osg::BoundingSphere TXPNode::computeBound() const
164{
165#if 1
166
167    // Steve Lunsford 10/28/05 : - Had to avoid using the child group nodes for bounds calculation
168    // because apparently the loader doesn't load all the sub-tiles for this node, resulting in a Group::computeBounds
169    // call which returns a size smaller than the actual size represented by this node so consequently this node gets culled out.
170    // note, submission merged and rearranged by Robert Osfield as an #if #else just in case we need to revert.
171    return osg::BoundingSphere( _extents );
172#else
173    // original code which uses the extents of the children when one is available.
174    if (getNumChildren() == 0)
175    {
176        return osg::BoundingSphere( _extents );
177    }
178    return Group::computeBound();
179#endif
180}
181
182void TXPNode::setArchiveName(const std::string& archiveName)
183{
184    _archiveName = archiveName;
185}
186
187void TXPNode::setOptions(const std::string& options)
188{
189    _options = options;
190}
191
192const std::string& TXPNode::getOptions() const
193{
194    return _options;
195}
196
197const std::string& TXPNode::getArchiveName() const
198{
199    return _archiveName;
200}
201
202bool TXPNode::loadArchive(TXPArchive* archive)
203{
204    //if (_archive.get())
205    //{
206    //    TXPNodeERROR("loadArchive()") << "archive already open" << std::endl;
207    //    return false;
208    //}
209
210
211   //modified by Brad Anderegg on May-27-08
212   //if NULL is passed in we will create a new archive and open the database
213   //otherwise we will use the archive provided which should have already been loaded
214   //by ReaderWriterTXP::getArchive(). See line 57-77 of ReaderWriterTXP.cpp.
215   if(archive == NULL)
216   {
217       _archive = new TXPArchive;
218       if (_archive->openFile(_archiveName) == false)
219       {
220           TXPNodeERROR("loadArchive()") << "failed to load archive: \"" << _archiveName << "\"" << std::endl;
221           return false;
222       }
223   }
224   else
225   {
226      _archive = archive;
227   }
228
229    _archive->getOrigin(_originX,_originY);
230    _archive->getExtents(_extents);
231
232    int32 numLod;
233    _archive->GetHeader()->GetNumLods(numLod);
234
235    trpg2iPoint tileSize;
236    _archive->GetHeader()->GetLodSize(0,tileSize);
237
238    _pageManager = new TXPPageManager;
239
240    // We are going to use _pageManager to manage lod 0 only, all other lod
241    // are managed by this OSG plugin
242    _pageManager->Init(_archive.get(), 1);
243
244    return true;
245}
246
247void TXPNode::updateEye(osg::NodeVisitor& nv)
248{
249    if (!_pageManager)
250    {
251        osg::notify(osg::NOTICE)<<"TXPNode::updateEye() no pageManager created"<<std::endl;
252        return;
253    }
254
255    trpg2dPoint loc;
256    loc.x = nv.getEyePoint().x() - _originX;
257    loc.y = nv.getEyePoint().y() - _originY;
258
259    if (_pageManager->SetLocation(loc))
260    {
261        trpgManagedTile *tile=NULL;
262
263        while((tile = _pageManager->GetNextUnload()))
264        {
265            int x,y,lod;
266            tile->GetTileLoc(x,y,lod);
267            if (lod == 0)
268            {
269                osg::Node* node = (osg::Node*)(tile->GetLocalData());
270                _nodesToRemove.push_back(node);
271
272                //osg::notify(osg::NOTICE) << "Tile unload: " << x << " " << y << " " << lod << std::endl;
273            }
274            _pageManager->AckUnload();
275        }
276
277        while ((tile = _pageManager->GetNextLoad()))
278        {
279            int x,y,lod;
280            tile->GetTileLoc(x,y,lod);
281            if (lod==0)
282            {
283                osg::Node* node = addPagedLODTile(x,y);
284                tile->SetLocalData(node);
285                //osg::notify(osg::NOTICE) << "Tile load: " << x << " " << y << " " << lod << std::endl;
286            }
287            _pageManager->AckLoad();
288           
289        }
290    }
291}
292
293osg::Node* TXPNode::addPagedLODTile(int x, int y)
294{
295    // For TerraPage 2.1 and over this method must only be use with lod = 0.
296    // If you look at the code that calls it, it is effectively called only when
297    // lod = 0. So all is OK
298    int lod = 0;
299    char pagedLODfile[1024];
300    sprintf(pagedLODfile,"%s\\tile%d_%dx%d_%d.txp",_archive->getDir(),lod,x,y,_archive->getId());
301
302
303    TXPArchive::TileInfo info;
304    _archive->getTileInfo(x,y,lod,info);
305
306    osg::PagedLOD* pagedLOD = new osg::PagedLOD;
307    pagedLOD->setFileName(0,pagedLODfile);
308    pagedLOD->setPriorityOffset(0,_archive->getNumLODs());
309    pagedLOD->setPriorityScale(0,1.0f);
310    pagedLOD->setRange(0,0.0,info.maxRange);
311    pagedLOD->setCenter(info.center);
312    pagedLOD->setRadius(info.radius);
313    pagedLOD->setNumChildrenThatCannotBeExpired(1);
314    pagedLOD->setUpdateCallback(new RetestCallback);
315
316    const trpgHeader* header = _archive->GetHeader();
317    trpgHeader::trpgTileType tileType;
318    header->GetTileOriginType(tileType);
319    if(tileType == trpgHeader::TileLocal)
320    {
321        // add in MatrixTransform node with Matrixd offsets
322        // get offsets from tile.bbox
323        osg::Vec3d sw(info.bbox._min);
324        sw[2] = 0.0;
325        osg::Matrix offset;
326        offset.setTrans(sw);
327        osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
328        pagedLOD->setCenter(info.center - sw);
329        tform->addChild(pagedLOD);
330        _nodesToAdd.push_back(tform);
331        return tform;
332    }
333    else
334    {
335    _nodesToAdd.push_back(pagedLOD);
336   
337    return pagedLOD;
338}
339}
340
341void TXPNode::updateSceneGraph()
342{
343    if (!_nodesToRemove.empty())
344    {
345        for (unsigned int i = 0; i < _nodesToRemove.size(); i++)
346        {
347            removeChild(_nodesToRemove[i]);
348        }
349        _nodesToRemove.clear();
350    }
351
352    if (!_nodesToAdd.empty())
353    {
354        for (unsigned int i = 0; i < _nodesToAdd.size(); i++)
355        {
356            addChild(_nodesToAdd[i]);
357        }
358        _nodesToAdd.clear();
359       
360    }   
361}
362
Note: See TracBrowser for help on using the browser.