1
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
3
* This library is open source and may be redistributed and/or modified under
4
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5
* (at your option) any later version. The full license is in LICENSE file
6
* included with this distribution, and on the openscenegraph.org website.
8
* This library is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* OpenSceneGraph Public License for more details.
14
#include <osgDB/ImagePager>
15
#include <osgDB/ReadFile>
18
#include <osg/ImageSequence>
20
using namespace osgDB;
23
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
25
// SortFileRequestFunctor
27
struct ImagePager::SortFileRequestFunctor
29
bool operator() (const osg::ref_ptr<ImagePager::ImageRequest>& lhs,const osg::ref_ptr<ImagePager::ImageRequest>& rhs) const
31
return (lhs->_timeToMergeBy < rhs->_timeToMergeBy);
36
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
40
void ImagePager::RequestQueue::sort()
42
std::sort(_requestList.begin(),_requestList.end(),SortFileRequestFunctor());
46
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
50
ImagePager::ReadQueue::ReadQueue(ImagePager* pager, const std::string& name):
54
_block = new osg::RefBlock;
57
void ImagePager::ReadQueue::clear()
59
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
61
for(RequestList::iterator citr = _requestList.begin();
62
citr != _requestList.end();
65
(*citr)->_attachmentPoint = 0;
66
(*citr)->_requestQueue = 0;
74
void ImagePager::ReadQueue::add(ImagePager::ImageRequest* databaseRequest)
76
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
77
_requestList.push_back(databaseRequest);
78
databaseRequest->_requestQueue = this;
83
void ImagePager::ReadQueue::takeFirst(osg::ref_ptr<ImageRequest>& databaseRequest)
85
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
87
if (!_requestList.empty())
91
databaseRequest = _requestList.front();
92
databaseRequest->_requestQueue = 0;
93
_requestList.erase(_requestList.begin());
99
//////////////////////////////////////////////////////////////////////////////////////
103
ImagePager::ImageThread::ImageThread(ImagePager* pager, Mode mode, const std::string& name):
111
ImagePager::ImageThread::ImageThread(const ImageThread& dt, ImagePager* pager):
119
ImagePager::ImageThread::~ImageThread()
123
int ImagePager::ImageThread::cancel()
134
case(HANDLE_ALL_REQUESTS):
135
_pager->_readQueue->release();
137
case(HANDLE_NON_HTTP):
138
_pager->_readQueue->release();
140
case(HANDLE_ONLY_HTTP):
141
_pager->_readQueue->release();
145
// release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
146
// _databasePagerThreadBlock->release();
148
// then wait for the the thread to stop running.
151
// commenting out debug info as it was cashing crash on exit, presumable
152
// due to osg::notify or std::cout destructing earlier than this destructor.
153
// osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"<<std::endl;
154
OpenThreads::Thread::YieldCurrentThread();
157
// _startThreadCalled = false;
159
//std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
163
void ImagePager::ImageThread::run()
165
osg::notify(osg::INFO)<<"ImagePager::ImageThread::run() "<<this<<std::endl;
166
bool firstTime = true;
168
osg::ref_ptr<ImagePager::ReadQueue> read_queue;
172
case(HANDLE_ALL_REQUESTS):
173
read_queue = _pager->_readQueue;
175
case(HANDLE_NON_HTTP):
176
read_queue = _pager->_readQueue;
178
case(HANDLE_ONLY_HTTP):
179
read_queue = _pager->_readQueue;
187
osg::ref_ptr<ImageRequest> imageRequest;
188
read_queue->takeFirst(imageRequest);
190
if (imageRequest.valid())
192
osg::ref_ptr<osg::Image> image = osgDB::readImageFile(imageRequest->_fileName);
195
osg::ImageSequence* is = dynamic_cast<osg::ImageSequence*>(imageRequest->_attachmentPoint.get());
198
if (imageRequest->_attachmentIndex >= 0)
200
is->setImage(imageRequest->_attachmentIndex, image.get());
204
is->addImage(image.get());
209
imageRequest->_loadedImage = image;
211
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_pager->_completedQueue->_requestMutex);
212
_pager->_completedQueue->_requestList.push_back(imageRequest);
219
OpenThreads::Thread::YieldCurrentThread();
223
// go to sleep till our the next time our thread gets scheduled.
227
// do a yield to get round a peculiar thread hang when testCancel() is called
228
// in certain circumstances - of which there is no particular pattern.
229
YieldCurrentThread();
233
} while (!testCancel() && !_done);
235
osg::notify(osg::INFO)<<"ImagePager::ImageThread::done()"<<std::endl;
239
//////////////////////////////////////////////////////////////////////////////////////
243
ImagePager::ImagePager():
246
_startThreadCalled = false;
247
_databasePagerThreadPaused = false;
249
_readQueue = new ReadQueue(this,"Image Queue");
250
_completedQueue = new RequestQueue;
251
_imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 1"));
252
//_imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 2"));
253
//_imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 3"));
259
ImagePager::~ImagePager()
264
int ImagePager::cancel()
268
for(ImageThreads::iterator itr = _imageThreads.begin();
269
itr != _imageThreads.end();
272
(*itr)->setDone(true);
275
// release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
276
_readQueue->release();
278
for(ImageThreads::iterator itr = _imageThreads.begin();
279
itr != _imageThreads.end();
286
_startThreadCalled = false;
288
//std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
292
osg::Image* ImagePager::readImageFile(const std::string& fileName)
294
return osgDB::readImageFile(fileName);
297
void ImagePager::requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp*)
299
osg::notify(osg::INFO)<<"ImagePager::requestNodeFile("<<fileName<<")"<<std::endl;
301
osg::ref_ptr<ImageRequest> request = new ImageRequest;
302
request->_timeToMergeBy = timeToMergeBy;
303
request->_fileName = fileName;
304
request->_attachmentPoint = attachmentPoint;
305
request->_attachmentIndex = attachmentIndex;
306
request->_requestQueue = _readQueue.get();
308
_readQueue->add(request.get());
310
if (!_startThreadCalled)
312
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex);
314
if (!_startThreadCalled)
316
_startThreadCalled = true;
319
for(ImageThreads::iterator itr = _imageThreads.begin();
320
itr != _imageThreads.end();
323
(*itr)->startThread();
330
bool ImagePager::requiresUpdateSceneGraph() const
332
//osg::notify(osg::NOTICE)<<"ImagePager::requiresUpdateSceneGraph()"<<std::endl;
333
return !(_completedQueue->_requestList.empty());
336
void ImagePager::updateSceneGraph(const osg::FrameStamp&)
338
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_completedQueue->_requestMutex);
340
for(RequestQueue::RequestList::iterator itr = _completedQueue->_requestList.begin();
341
itr != _completedQueue->_requestList.end();
344
ImageRequest* imageRequest = itr->get();
345
osg::Texture* texture = dynamic_cast<osg::Texture*>(imageRequest->_attachmentPoint.get());
348
int attachmentIndex = imageRequest->_attachmentIndex > 0 ? imageRequest->_attachmentIndex : 0;
349
texture->setImage(attachmentIndex, imageRequest->_loadedImage.get());
353
osg::notify(osg::NOTICE)<<"ImagePager::updateSceneGraph() : error, image request attachment type not handled yet."<<std::endl;
357
_completedQueue->_requestList.clear();