00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <PVLE/3D/LightSourceManager.h>
00028 #include <PVLE/Util/Math.h>
00029
00030 #include <boost/integer_traits.hpp>
00031
00032
00033
00034 const LightSourceManager::Priority MIN_PRIORITY = std::numeric_limits<LightSourceManager::Priority>::is_integer ? (std::numeric_limits<LightSourceManager::Priority>::min)() : -(std::numeric_limits<LightSourceManager::Priority>::max)();
00035 const LightSourceManager::Priority MAX_PRIORITY = (std::numeric_limits<LightSourceManager::Priority>::max)();
00036
00037 UINT LightSourceManager::request(osg::Referenced * pNewUser, Priority priority, LightSourceUserCallback * pUserCB, bool enqueue) {
00038
00039 Priority minPriority = MAX_PRIORITY;
00040 User * pMinPriorityUser = NULL;
00041 UINT minPriorityLightNumber = UINT_MAX;
00042 for(UINT i=firstManagedLight; i<lastManagedLight; ++i) {
00043 User & user = users[i];
00044 if (user.check()) {
00045
00046 clampu(minPriority, user.priority);
00047 pMinPriorityUser = &user;
00048 minPriorityLightNumber = i;
00049 continue;
00050 }
00051
00052
00053 user.pUserObject = pNewUser;
00054 user.priority = priority;
00055 user.pUserCB = pUserCB;
00056 return i;
00057 }
00058
00059
00060 if (pMinPriorityUser && minPriority < priority) {
00061
00062 unManage(minPriorityLightNumber, true);
00063
00064 pMinPriorityUser->pUserObject = pNewUser;
00065 pMinPriorityUser->priority = priority;
00066 pMinPriorityUser->pUserCB = pUserCB;
00067 return minPriorityLightNumber;
00068 }
00069
00070
00071 if (enqueue) doEnqueue(pNewUser, priority, pUserCB);
00072 return UINT_MAX;
00073 }
00074
00075
00076 void LightSourceManager::doEnqueue(osg::Referenced * pNewUser, Priority priority, LightSourceUserCallback * pUserCB) {
00077 ASSERT(pUserCB);
00078 if (!pUserCB) return;
00079
00080 cleanQueue();
00081 User tmpUser;
00082 tmpUser.pUserObject = pNewUser;
00083 tmpUser.priority = priority;
00084 tmpUser.pUserCB = pUserCB;
00085 usersQueue.push_back(tmpUser);
00086 }
00087
00088
00089 void LightSourceManager::remove(osg::Referenced * pUserObject) {
00090
00091 for(UINT i=firstManagedLight; i<lastManagedLight; ++i) {
00092 User & user = users[i];
00093 if (!user.check()) lightAvailable(&user);
00094 else if (pUserObject == user.pUserObject.get()) {
00095 unManage(i, false);
00096 lightAvailable(i);
00097 return;
00098 }
00099 }
00100
00101
00102 for(std::vector<User>::iterator it=usersQueue.begin(), itEnd=usersQueue.end(); it!=itEnd; ++it) {
00103
00104 if (!it->check()) {
00105 it = usersQueue.erase(it);
00106 continue;
00107 }
00108
00109 if (it->pUserObject == pUserObject) {
00110 if (it->pUserCB.valid()) it->pUserCB->onUserDropped(this, it->pUserObject.get());
00111 it = usersQueue.erase(it);
00112 return;
00113 }
00114 }
00115
00116 THROW_TRACED_EXCEPTION("User object not found");
00117 }
00118
00119
00120 void LightSourceManager::clear() {
00121 for(UINT i=firstManagedLight; i<lastManagedLight; ++i) {
00122 if (users[i].check()) unManage(i, false);
00123 }
00124 for(std::vector<User>::iterator it=usersQueue.begin(), itEnd=usersQueue.end(); it!=itEnd; ++it) {
00125 if (!it->check() && it->pUserCB.valid()) it->pUserCB->onUserDropped(this, it->pUserObject.get());
00126 }
00127 usersQueue.clear();
00128 }
00129
00130
00131 void LightSourceManager::checkForAvailableLights() {
00132 if (usersQueue.empty()) return;
00133
00134 std::vector<User>::iterator itBestCandidate = usersQueue.end();
00135 for(UINT i=firstManagedLight; i<lastManagedLight; ++i) {
00136 User & user = users[i];
00137
00138 if (!user.check()) {
00139 lightAvailable(i);
00140 if (usersQueue.empty()) return;
00141 } else {
00142
00143 if (itBestCandidate == usersQueue.end()) {
00144
00145 itBestCandidate = getBestEnqueuedCandidate();
00146 }
00147 if (itBestCandidate != usersQueue.end() && user.priority < itBestCandidate->priority) {
00148 unManage(i, true);
00149
00150 lightAvailable(i);
00151 itBestCandidate = usersQueue.end();
00152 }
00153
00154 if (usersQueue.empty()) return;
00155 }
00156 }
00157 }
00158
00159
00160 void LightSourceManager::cleanQueue() {
00161 for(std::vector<User>::iterator it=usersQueue.begin(), itEnd=usersQueue.end(); it!=itEnd; ++it) {
00162 if (!it->check()) it = usersQueue.erase(it);
00163 }
00164 }
00165
00166
00167 LightSourceManager::User * LightSourceManager::getUser(const osg::Referenced * pUserObject) {
00168
00169 for(UINT i=firstManagedLight; i<lastManagedLight; ++i) {
00170 User & user = users[i];
00171 if (!user.check()) lightAvailable(&user);
00172 else if (pUserObject == user.pUserObject.get()) return &user;
00173 }
00174
00175
00176 cleanQueue();
00177 BOOST_FOREACH(User & user, usersQueue) {
00178 ASSERT(user.check());
00179 if (pUserObject == user.pUserObject.get()) return &user;
00180 }
00181
00182 THROW_TRACED_EXCEPTION("User object not found");
00183 }
00184
00185
00186 const LightSourceManager::User * LightSourceManager::getUser(const osg::Referenced * pUserObject) const {
00187
00188 for(UINT i=firstManagedLight; i<lastManagedLight; ++i) {
00189 const User & user = users[i];
00190 if (!user.pUserObject.valid()) continue;
00191 else if (pUserObject == user.pUserObject.get()) return &user;
00192 }
00193
00194
00195 BOOST_FOREACH(const User & user, usersQueue) {
00196 ASSERT(user.pUserObject.valid());
00197 if (pUserObject == user.pUserObject.get()) return &user;
00198 }
00199
00200 THROW_TRACED_EXCEPTION("User object not found");
00201 }
00202
00203
00204 void LightSourceManager::lightAvailable(UINT lightNumber) {
00205 if (usersQueue.empty()) return;
00206 std::vector<User>::iterator it = getBestEnqueuedCandidate();
00207 lightAvailable(lightNumber, it);
00208 }
00209
00210 void LightSourceManager::lightAvailable(UINT lightNumber, std::vector<User>::iterator & itBestCandidate) {
00211 if (usersQueue.empty()) return;
00212
00213 ASSERT(itBestCandidate != usersQueue.end());
00214
00215 User & newUser = users[lightNumber];
00216 newUser = *itBestCandidate;
00217
00218 usersQueue.erase(itBestCandidate);
00219
00220 ASSERT(newUser.pUserCB.valid());
00221 if (!newUser.pUserCB->onSourceAvailable(this, newUser.pUserObject.get(), lightNumber)) {
00222
00223 newUser.reset();
00224 lightAvailable(lightNumber);
00225 }
00226 }
00227
00228
00229 std::vector<LightSourceManager::User>::iterator LightSourceManager::getBestEnqueuedCandidate() {
00230 std::vector<User>::iterator itBestCandidate = usersQueue.end();
00231 Priority maxPriority = MIN_PRIORITY;
00232 for(std::vector<User>::iterator it=usersQueue.begin(), itEnd=usersQueue.end(); it!=itEnd; ++it) {
00233
00234 if (!it->check()) {
00235 it = usersQueue.erase(it);
00236 continue;
00237 }
00238 ASSERT(it->pUserCB.valid());
00240
00241
00242
00243
00244
00245
00246
00247 if (itBestCandidate == usersQueue.end() || it->priority > maxPriority) {
00248 maxPriority = it->priority;
00249 itBestCandidate = it;
00250 }
00251 }
00252 return itBestCandidate;
00253 }
00254
00255
00256 void LightSourceManager::setManagedLights(UINT _firstManagedLight, UINT _lastManagedLight) {
00257 ASSERT(_firstManagedLight >= 0);
00258 ASSERT(_lastManagedLight <= MAX_LIGHT);
00259 ASSERT(_firstManagedLight <_lastManagedLight);
00260
00261
00262 for(UINT i=firstManagedLight; i<_firstManagedLight; ++i) unManage(i, true);
00263 for(UINT i=_lastManagedLight; i<lastManagedLight; ++i) unManage(i, true);
00264
00265
00266 if (!usersQueue.empty()) {
00267 for(UINT i=_firstManagedLight; i<firstManagedLight; ++i) {
00268 users[i].reset();
00269 lightAvailable(i);
00270 }
00271 for(UINT i=lastManagedLight; i<_lastManagedLight; ++i) {
00272 users[i].reset();
00273 lightAvailable(i);
00274 }
00275 }
00276
00277 firstManagedLight = _firstManagedLight;
00278 lastManagedLight = _lastManagedLight;
00279 }
00280
00281
00282 void LightSourceManager::unManage(UINT i, bool canEnqueue) {
00283 User & user = users[i];
00284 if (!user.check()) return;
00285 if (user.pUserCB.valid()) {
00286 if (user.pUserCB->onSourceTaken(this, user.pUserObject.get(), i)) {
00287
00288 if (canEnqueue) doEnqueue(&user);
00289 }
00290 if (!canEnqueue) user.pUserCB->onUserDropped(this, user.pUserObject.get());
00291 }
00292 user.reset();
00293 }