// delete a portal instance by pointer void PCZSceneManager::destroyPortal(const String & portalName) { // find the portal from the master portal list Portal * p; Portal * thePortal = 0; PortalList::iterator it = mPortals.begin(); while (it != mPortals.end()) { p = *it; if (p->getName() == portalName) { thePortal = p; // erase entry in the master list mPortals.erase(it); break; } it++; } if (thePortal) { // remove the portal from it's target portal Portal * targetPortal = thePortal->getTargetPortal(); if (targetPortal) { targetPortal->setTargetPortal(0); // the targetPortal will still have targetZone value, but targetPortal will be invalid } // remove the Portal from it's home zone PCZone * homeZone = thePortal->getCurrentHomeZone(); if (homeZone) { // inform zone of portal change homeZone->setPortalsUpdated(true); homeZone->_removePortal(thePortal); } // delete the portal instance OGRE_DELETE thePortal; } }
/** Update the zone data for the portals in the zone * NOTE: All portal spatial data must be up-to-date before calling this routine. */ void DefaultZone::updatePortalsZoneData(void) { PortalList transferPortalList; AntiPortalList transferAntiPortalList; // check each portal to see if it's intersecting another portal of smaller size for ( PortalList::iterator it = mPortals.begin(); it != mPortals.end(); ++it ) { Portal * p = *it; bool portalNeedUpdate = p->needUpdate(); Real pRadius = p->getRadius(); // First we check against portals in the SAME zone (and only if they have a // target zone different from the home zone) // Here we check only against portals that moved and of smaller size. // We do not need to check portal againts previous portals // since it would have been already checked. // Hence we start with the next portal after the current portal. PortalList::iterator it2 = it; for ( ++it2; it2 != mPortals.end(); ++it2 ) { Portal * p2 = (*it2); // Skip portal if it doesn't need updating. // If both portals are not moving, then there's no need to check between them. if (!portalNeedUpdate && !p2->needUpdate()) continue; // Skip portal if it's not pointing to another zone. if (p2->getTargetZone() == this) continue; // Skip portal if it's pointing to the same target zone as this portal points to if (p2->getTargetZone() == p->getTargetZone()) continue; if (pRadius > p2->getRadius()) { // Portal#1 is bigger than Portal#2, check for crossing if (p2->getCurrentHomeZone() != p->getTargetZone() && p2->crossedPortal(p)) { // portal#2 crossed portal#1 - flag portal#2 to be moved to portal#1's target zone p2->setNewHomeZone(p->getTargetZone()); transferPortalList.push_back(p2); } } else if (pRadius < p2->getRadius()) { // Portal #2 is bigger than Portal #1, check for crossing if (p->getCurrentHomeZone() != p2->getTargetZone() && p->crossedPortal(p2)) { // portal#1 crossed portal#2 - flag portal#1 to be moved to portal#2's target zone p->setNewHomeZone(p2->getTargetZone()); transferPortalList.push_back(p); continue; } } } // Secondly we check againts the antiportals of this zone. for (AntiPortalList::iterator ait = mAntiPortals.begin(); ait != mAntiPortals.end(); ++ait) { AntiPortal* ap = (*ait); // Skip portal if it doesn't need updating. // If both portals are not moving, then there's no need to check between them. if (!portalNeedUpdate && !ap->needUpdate()) continue; // only check for crossing if AntiPortal smaller than portal. if (pRadius > ap->getRadius()) { // Portal#1 is bigger than AntiPortal, check for crossing if (ap->crossedPortal(p)) { // AntiPortal crossed Portal#1 - flag AntiPortal to be moved to Portal#1's target zone ap->setNewHomeZone(p->getTargetZone()); transferAntiPortalList.push_back(ap); } } } // Skip portal if it doesn't need updating. if (!portalNeedUpdate) continue; // Thirdly we check against portals in the target zone (and only if that target // zone is different from the home zone) PCZone * tzone = p->getTargetZone(); if (tzone != this) { for ( PortalList::iterator it3 = tzone->mPortals.begin(); it3 != tzone->mPortals.end(); ++it3 ) { Portal * p3 = (*it3); // only check against bigger regular portals if (pRadius < p3->getRadius()) { // Portal#3 is bigger than Portal#1, check for crossing if (p->getCurrentHomeZone() != p3->getTargetZone() && p->crossedPortal(p3)) { // Portal#1 crossed Portal#3 - switch target zones for Portal#1 p->setTargetZone(p3->getTargetZone()); break; } } } } } // transfer any portals to new zones that have been flagged for ( PortalList::iterator it = transferPortalList.begin(); it != transferPortalList.end(); ++it ) { Portal * p = *it; if (p->getNewHomeZone() != 0) { _removePortal(p); p->getNewHomeZone()->_addPortal(p); p->setNewHomeZone(0); } } // transfer any anti portals to new zones that have been flagged for (AntiPortalList::iterator it = transferAntiPortalList.begin(); it != transferAntiPortalList.end(); ++it) { AntiPortal* p = *it; if (p->getNewHomeZone() != 0) { _removeAntiPortal(p); p->getNewHomeZone()->_addAntiPortal(p); p->setNewHomeZone(0); } } }