/* Attempt to automatically connect unconnected portals to proper target zones * by looking for matching portals in other zones which are at the same location */ void PCZSceneManager::connectPortalsToTargetZonesByLocation(void) { // go through every zone to find portals ZoneMap::iterator i, iend; PCZone* zone; iend = mZones.end(); bool foundMatch; for (i = mZones.begin(); i != iend; i++) { zone = i->second; // go through all the portals in the zone Portal* portal; PortalList::iterator pi, piend; piend = zone->mPortals.end(); for (pi = zone->mPortals.begin(); pi != piend; pi++) { portal = *pi; //portal->updateDerivedValues(); if (portal->getTargetZone() == 0) { // this is a portal without a connected zone - look for // a matching portal in another zone PCZone* zone2; ZoneMap::iterator j= mZones.begin(); foundMatch = false; while (!foundMatch && j != mZones.end()) { zone2 = j->second; if (zone2 != zone) // make sure we don't look in the same zone { Portal * portal2 = zone2->findMatchingPortal(portal); if (portal2) { // found a match! Ogre::LogManager::getSingletonPtr()->logMessage("Connecting portal "+portal->getName()+" to portal "+portal2->getName()); foundMatch = true; portal->setTargetZone(zone2); portal->setTargetPortal(portal2); portal2->setTargetZone(zone); portal2->setTargetPortal(portal); } } j++; } if (foundMatch == false) { // error, didn't find a matching portal! OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Could not find matching portal for portal " + portal->getName(), "PCZSceneManager::connectPortalsToTargetZonesByLocation"); } } } } }
/** 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); } } }