PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/game-ui-solution/OGRE-1.7.2/PlugIns/OctreeZone/src/OgreOctreeZone.cpp

http://game-ui-solution.googlecode.com/
C++ | 1322 lines | 912 code | 137 blank | 273 comment | 243 complexity | 6d28046b1d49651c8987d80dad287717 MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.1, ISC, Unlicense, MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, MIT, LGPL-3.0
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org/
  6. Copyright (c) 2000-2009 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. OctreeZone.cpp - Octree Zone implementation
  24. -----------------------------------------------------------------------------
  25. begin : Tue Feb 20 2007
  26. author : Eric Cha
  27. email : ericc@xenopi.com
  28. -----------------------------------------------------------------------------
  29. */
  30. #include "OgreOctreeZone.h"
  31. #include "OgreSceneNode.h"
  32. #include "OgrePortal.h"
  33. #include "OgrePCZSceneNode.h"
  34. #include "OgrePCZSceneManager.h"
  35. #include "OgrePCZLight.h"
  36. #include "OgreEntity.h"
  37. namespace Ogre
  38. {
  39. OctreeZone::OctreeZone( PCZSceneManager * creator, const String& name )
  40. : PCZone(creator, name)
  41. {
  42. mZoneTypeName = "ZoneType_Octree";
  43. // init octree
  44. AxisAlignedBox b( -10000, -10000, -10000, 10000, 10000, 10000 );
  45. int depth = 8;
  46. mOctree = 0;
  47. init( b, depth );
  48. }
  49. OctreeZone::~OctreeZone()
  50. {
  51. // portals & nodelist are deleted in PCZone destructor.
  52. // delete octree
  53. if ( mOctree )
  54. {
  55. OGRE_DELETE mOctree;
  56. mOctree = 0;
  57. }
  58. }
  59. /** Set the enclosure node for this OctreeZone
  60. */
  61. void OctreeZone::setEnclosureNode(PCZSceneNode * node)
  62. {
  63. mEnclosureNode = node;
  64. if (node)
  65. {
  66. // anchor the node to this zone
  67. node->anchorToHomeZone(this);
  68. // make sure node world bounds are up to date
  69. node->_updateBounds();
  70. // resize the octree to the same size as the enclosure node bounding box
  71. resize(node->_getWorldAABB());
  72. }
  73. }
  74. // this call adds the given node to either the zone's list
  75. // of nodes at home in the zone, or to the list of visiting nodes
  76. // NOTE: The list is decided by the node's homeZone value, so
  77. // that must be set correctly before calling this function.
  78. void OctreeZone::_addNode( PCZSceneNode * n )
  79. {
  80. if (n->getHomeZone() == this)
  81. {
  82. // add a reference to this node in the "nodes at home in this zone" list
  83. mHomeNodeList.insert( n );
  84. }
  85. else
  86. {
  87. // add a reference to this node in the "nodes visiting this zone" list
  88. mVisitorNodeList.insert( n );
  89. }
  90. }
  91. void OctreeZone::removeNode( PCZSceneNode * n )
  92. {
  93. if ( n != 0 )
  94. removeNodeFromOctree( n );
  95. if (n->getHomeZone() == this)
  96. {
  97. mHomeNodeList.erase( n );
  98. }
  99. else
  100. {
  101. mVisitorNodeList.erase( n );
  102. }
  103. }
  104. /** Remove all nodes from the node reference list and clear it
  105. */
  106. void OctreeZone::_clearNodeLists(short nodeListTypes)
  107. {
  108. if (nodeListTypes & HOME_NODE_LIST)
  109. {
  110. PCZSceneNodeList::iterator it = mHomeNodeList.begin();
  111. while( it != mHomeNodeList.end())
  112. {
  113. PCZSceneNode * sn = *it;
  114. removeNodeFromOctree( sn );
  115. ++it;
  116. }
  117. mHomeNodeList.clear();
  118. }
  119. if (nodeListTypes & VISITOR_NODE_LIST)
  120. {
  121. PCZSceneNodeList::iterator it = mVisitorNodeList.begin();
  122. while( it != mVisitorNodeList.end())
  123. {
  124. PCZSceneNode * sn = *it;
  125. removeNodeFromOctree( sn );
  126. ++it;
  127. }
  128. mVisitorNodeList.clear();
  129. }
  130. }
  131. /** Indicates whether or not this zone requires zone-specific data for
  132. * each scene node
  133. */
  134. bool OctreeZone::requiresZoneSpecificNodeData(void)
  135. {
  136. // Octree Zones have zone specific node data
  137. return true;
  138. }
  139. /** create zone specific data for a node
  140. */
  141. void OctreeZone::createNodeZoneData(PCZSceneNode * node)
  142. {
  143. OctreeZoneData * ozd = OGRE_NEW OctreeZoneData(node, this);
  144. if (ozd)
  145. {
  146. node->setZoneData(this, ozd);
  147. }
  148. }
  149. /* Recursively check for intersection of the given scene node
  150. * with zone portals. If the node touches a portal, then the
  151. * connected zone is assumed to be touched. The zone adds
  152. * the node to its node list and the node adds the zone to
  153. * its visiting zone list.
  154. *
  155. * NOTE: This function assumes that the home zone of the node
  156. * is correct. The function "_updateHomeZone" in PCZSceneManager
  157. * takes care of this and should have been called before
  158. * this function.
  159. */
  160. void OctreeZone::_checkNodeAgainstPortals(PCZSceneNode * pczsn, Portal * ignorePortal)
  161. {
  162. if (pczsn == mEnclosureNode ||
  163. pczsn->allowedToVisit() == false)
  164. {
  165. // don't do any checking of enclosure node versus portals
  166. return;
  167. }
  168. PCZone * connectedZone;
  169. for ( PortalList::iterator it = mPortals.begin(); it != mPortals.end(); ++it )
  170. {
  171. Portal * p = *it;
  172. //Check if the portal intersects the node
  173. if (p != ignorePortal && p->intersects(pczsn) != Portal::NO_INTERSECT)
  174. {
  175. // node is touching this portal
  176. connectedZone = p->getTargetZone();
  177. // add zone to the nodes visiting zone list unless it is the home zone of the node
  178. if (connectedZone != pczsn->getHomeZone() &&
  179. !pczsn->isVisitingZone(connectedZone))
  180. {
  181. pczsn->addZoneToVisitingZonesMap(connectedZone);
  182. // tell the connected zone that the node is visiting it
  183. connectedZone->_addNode(pczsn);
  184. //recurse into the connected zone
  185. connectedZone->_checkNodeAgainstPortals(pczsn, p->getTargetPortal());
  186. }
  187. }
  188. }
  189. }
  190. /** (recursive) check the given light against all portals in the zone
  191. * NOTE: This is the default implementation, which doesn't take advantage
  192. * of any zone-specific optimizations for checking portal visibility
  193. */
  194. void OctreeZone::_checkLightAgainstPortals(PCZLight *light,
  195. unsigned long frameCount,
  196. PCZFrustum *portalFrustum,
  197. Portal * ignorePortal)
  198. {
  199. for ( PortalList::iterator it = mPortals.begin(); it != mPortals.end(); ++it )
  200. {
  201. Portal * p = *it;
  202. if (p != ignorePortal)
  203. {
  204. // calculate the direction vector from light to portal
  205. Vector3 lightToPortal = p->getDerivedCP() - light->getDerivedPosition();
  206. if (portalFrustum->isVisible(p))
  207. {
  208. // portal is facing the light, but some light types need to
  209. // check illumination radius too.
  210. PCZone * targetZone = p->getTargetZone();
  211. switch(light->getType())
  212. {
  213. case Light::LT_POINT:
  214. // point lights - just check if within illumination range
  215. if (lightToPortal.length() <= light->getAttenuationRange())
  216. {
  217. // if portal is quad portal it must be pointing towards the light
  218. if ((p->getType() == Portal::PORTAL_TYPE_QUAD && lightToPortal.dotProduct(p->getDerivedDirection()) < 0.0) ||
  219. (p->getType() != Portal::PORTAL_TYPE_QUAD))
  220. {
  221. if (!light->affectsZone(targetZone))
  222. {
  223. light->addZoneToAffectedZonesList(targetZone);
  224. if (targetZone->getLastVisibleFrame() == frameCount)
  225. {
  226. light->setAffectsVisibleZone(true);
  227. }
  228. // set culling frustum from the portal
  229. portalFrustum->addPortalCullingPlanes(p);
  230. // recurse into the target zone of the portal
  231. p->getTargetZone()->_checkLightAgainstPortals(light,
  232. frameCount,
  233. portalFrustum,
  234. p->getTargetPortal());
  235. // remove the planes added by this portal
  236. portalFrustum->removePortalCullingPlanes(p);
  237. }
  238. }
  239. }
  240. break;
  241. case Light::LT_DIRECTIONAL:
  242. // directionals have infinite range, so just make sure
  243. // the direction is facing the portal
  244. if (lightToPortal.dotProduct(light->getDerivedDirection()) >= 0.0)
  245. {
  246. // if portal is quad portal it must be pointing towards the light
  247. if ((p->getType() == Portal::PORTAL_TYPE_QUAD && lightToPortal.dotProduct(p->getDerivedDirection()) < 0.0) ||
  248. (p->getType() != Portal::PORTAL_TYPE_QUAD))
  249. {
  250. if (!light->affectsZone(targetZone))
  251. {
  252. light->addZoneToAffectedZonesList(targetZone);
  253. if (targetZone->getLastVisibleFrame() == frameCount)
  254. {
  255. light->setAffectsVisibleZone(true);
  256. }
  257. // set culling frustum from the portal
  258. portalFrustum->addPortalCullingPlanes(p);
  259. // recurse into the target zone of the portal
  260. p->getTargetZone()->_checkLightAgainstPortals(light,
  261. frameCount,
  262. portalFrustum,
  263. p->getTargetPortal());
  264. // remove the planes added by this portal
  265. portalFrustum->removePortalCullingPlanes(p);
  266. }
  267. }
  268. }
  269. break;
  270. case Light::LT_SPOTLIGHT:
  271. // spotlights - just check if within illumination range
  272. // Technically, we should check if the portal is within
  273. // the cone of illumination, but for now, we'll leave that
  274. // as a future optimisation.
  275. if (lightToPortal.length() <= light->getAttenuationRange())
  276. {
  277. // if portal is quad portal it must be pointing towards the light
  278. if ((p->getType() == Portal::PORTAL_TYPE_QUAD && lightToPortal.dotProduct(p->getDerivedDirection()) < 0.0) ||
  279. (p->getType() != Portal::PORTAL_TYPE_QUAD))
  280. {
  281. if (!light->affectsZone(targetZone))
  282. {
  283. light->addZoneToAffectedZonesList(targetZone);
  284. if (targetZone->getLastVisibleFrame() == frameCount)
  285. {
  286. light->setAffectsVisibleZone(true);
  287. }
  288. // set culling frustum from the portal
  289. portalFrustum->addPortalCullingPlanes(p);
  290. // recurse into the target zone of the portal
  291. p->getTargetZone()->_checkLightAgainstPortals(light,
  292. frameCount,
  293. portalFrustum,
  294. p->getTargetPortal());
  295. // remove the planes added by this portal
  296. portalFrustum->removePortalCullingPlanes(p);
  297. }
  298. }
  299. }
  300. break;
  301. }
  302. }
  303. }
  304. }
  305. }
  306. /** Update the zone data for the portals in the zone
  307. * NOTE: All portal spatial data must be up-to-date before calling this routine.
  308. */
  309. void OctreeZone::updatePortalsZoneData(void)
  310. {
  311. PortalList transferPortalList;
  312. AntiPortalList transferAntiPortalList;
  313. // check each portal to see if it's intersecting another portal of smaller size
  314. for ( PortalList::iterator it = mPortals.begin(); it != mPortals.end(); ++it )
  315. {
  316. Portal * p = *it;
  317. bool portalNeedUpdate = p->needUpdate();
  318. Real pRadius = p->getRadius();
  319. // First we check against portals in the SAME zone (and only if they have a
  320. // target zone different from the home zone)
  321. // Here we check only against portals that moved and of smaller size.
  322. // We do not need to check portal againts previous portals
  323. // since it would have been already checked.
  324. // Hence we start with the next portal after the current portal.
  325. PortalList::iterator it2 = it;
  326. for ( ++it2; it2 != mPortals.end(); ++it2 )
  327. {
  328. Portal * p2 = (*it2);
  329. // Skip portal if it doesn't need updating.
  330. // If both portals are not moving, then there's no need to check between them.
  331. if (!portalNeedUpdate && !p2->needUpdate()) continue;
  332. // Skip portal if it's not pointing to another zone.
  333. if (p2->getTargetZone() == this) continue;
  334. // Skip portal if it's pointing to the same target zone as this portal points to
  335. if (p2->getTargetZone() == p->getTargetZone()) continue;
  336. if (pRadius > p2->getRadius())
  337. {
  338. // Portal#1 is bigger than Portal#2, check for crossing
  339. if (p2->getCurrentHomeZone() != p->getTargetZone() && p2->crossedPortal(p))
  340. {
  341. // portal#2 crossed portal#1 - flag portal#2 to be moved to portal#1's target zone
  342. p2->setNewHomeZone(p->getTargetZone());
  343. transferPortalList.push_back(p2);
  344. }
  345. }
  346. else if (pRadius < p2->getRadius())
  347. {
  348. // Portal #2 is bigger than Portal #1, check for crossing
  349. if (p->getCurrentHomeZone() != p2->getTargetZone() && p->crossedPortal(p2))
  350. {
  351. // portal#1 crossed portal#2 - flag portal#1 to be moved to portal#2's target zone
  352. p->setNewHomeZone(p2->getTargetZone());
  353. transferPortalList.push_back(p);
  354. continue;
  355. }
  356. }
  357. }
  358. // Secondly we check againts the antiportals of this zone.
  359. for (AntiPortalList::iterator ait = mAntiPortals.begin(); ait != mAntiPortals.end(); ++ait)
  360. {
  361. AntiPortal* ap = (*ait);
  362. // Skip portal if it doesn't need updating.
  363. // If both portals are not moving, then there's no need to check between them.
  364. if (!portalNeedUpdate && !ap->needUpdate()) continue;
  365. // only check for crossing if AntiPortal smaller than portal.
  366. if (pRadius > ap->getRadius())
  367. {
  368. // Portal#1 is bigger than AntiPortal, check for crossing
  369. if (ap->crossedPortal(p))
  370. {
  371. // AntiPortal crossed Portal#1 - flag AntiPortal to be moved to Portal#1's target zone
  372. ap->setNewHomeZone(p->getTargetZone());
  373. transferAntiPortalList.push_back(ap);
  374. }
  375. }
  376. }
  377. // Skip portal if it doesn't need updating.
  378. if (!portalNeedUpdate) continue;
  379. // Thirdly we check against portals in the target zone (and only if that target
  380. // zone is different from the home zone)
  381. PCZone * tzone = p->getTargetZone();
  382. if (tzone != this)
  383. {
  384. for ( PortalList::iterator it3 = tzone->mPortals.begin(); it3 != tzone->mPortals.end(); ++it3 )
  385. {
  386. Portal * p3 = (*it3);
  387. // only check against bigger regular portals
  388. if (pRadius < p3->getRadius())
  389. {
  390. // Portal#3 is bigger than Portal#1, check for crossing
  391. if (p->getCurrentHomeZone() != p3->getTargetZone() && p->crossedPortal(p3))
  392. {
  393. // Portal#1 crossed Portal#3 - switch target zones for Portal#1
  394. p->setTargetZone(p3->getTargetZone());
  395. break;
  396. }
  397. }
  398. }
  399. }
  400. }
  401. // transfer any portals to new zones that have been flagged
  402. for ( PortalList::iterator it = transferPortalList.begin(); it != transferPortalList.end(); ++it )
  403. {
  404. Portal * p = *it;
  405. if (p->getNewHomeZone() != 0)
  406. {
  407. _removePortal(p);
  408. p->getNewHomeZone()->_addPortal(p);
  409. p->setNewHomeZone(0);
  410. }
  411. }
  412. // transfer any anti portals to new zones that have been flagged
  413. for (AntiPortalList::iterator it = transferAntiPortalList.begin(); it != transferAntiPortalList.end(); ++it)
  414. {
  415. AntiPortal* p = *it;
  416. if (p->getNewHomeZone() != 0)
  417. {
  418. _removeAntiPortal(p);
  419. p->getNewHomeZone()->_addAntiPortal(p);
  420. p->setNewHomeZone(0);
  421. }
  422. }
  423. }
  424. /** Mark nodes dirty base on moving portals. */
  425. void OctreeZone::dirtyNodeByMovingPortals(void)
  426. {
  427. // Octree zone is a space partitioned zone.
  428. // Hence we can smartly grab nodes of interest and flag them.
  429. for ( PortalList::iterator it = mPortals.begin(); it != mPortals.end(); ++it )
  430. {
  431. Portal* p = *it;
  432. if (p->needUpdate())
  433. {
  434. PCZSceneNodeList nodeList;
  435. mOctree->_findNodes(p->getAAB(), nodeList, NULL, true, false);
  436. PCZSceneNodeList::iterator i = nodeList.begin();
  437. while ( i != nodeList.end() )
  438. {
  439. (*i)->setMoved(true);
  440. ++i;
  441. }
  442. }
  443. }
  444. }
  445. /* The following function checks if a node has left it's current home zone.
  446. * This is done by checking each portal in the zone. If the node has crossed
  447. * the portal, then the current zone is no longer the home zone of the node. The
  448. * function then recurses into the connected zones. Once a zone is found where
  449. * the node does NOT cross out through a portal, that zone is the new home zone.
  450. NOTE: For this function to work, the node must start out in the proper zone to
  451. begin with!
  452. */
  453. PCZone* OctreeZone::updateNodeHomeZone( PCZSceneNode * pczsn, bool allowBackTouches )
  454. {
  455. // default to newHomeZone being the current home zone
  456. PCZone * newHomeZone = pczsn->getHomeZone();
  457. // Check all portals of the start zone for crossings!
  458. Portal* portal;
  459. PortalList::iterator pi, piend;
  460. piend = mPortals.end();
  461. for (pi = mPortals.begin(); pi != piend; pi++)
  462. {
  463. portal = *pi;
  464. Portal::PortalIntersectResult pir = portal->intersects(pczsn);
  465. switch (pir)
  466. {
  467. default:
  468. case Portal::NO_INTERSECT: // node does not intersect portal - do nothing
  469. case Portal::INTERSECT_NO_CROSS:// node intersects but does not cross portal - do nothing
  470. break;
  471. case Portal::INTERSECT_BACK_NO_CROSS:// node intersects but on the back of the portal
  472. if (allowBackTouches)
  473. {
  474. // node is on wrong side of the portal - fix if we're allowing backside touches
  475. if (portal->getTargetZone() != this &&
  476. portal->getTargetZone() != pczsn->getHomeZone())
  477. {
  478. // set the home zone of the node to the target zone of the portal
  479. pczsn->setHomeZone(portal->getTargetZone());
  480. // continue checking for portal crossings in the new zone
  481. newHomeZone = portal->getTargetZone()->updateNodeHomeZone(pczsn, false);
  482. }
  483. }
  484. break;
  485. case Portal::INTERSECT_CROSS:
  486. // node intersects and crosses the portal - recurse into that zone as new home zone
  487. if (portal->getTargetZone() != this &&
  488. portal->getTargetZone() != pczsn->getHomeZone())
  489. {
  490. // set the home zone of the node to the target zone of the portal
  491. pczsn->setHomeZone(portal->getTargetZone());
  492. // continue checking for portal crossings in the new zone
  493. newHomeZone = portal->getTargetZone()->updateNodeHomeZone(pczsn, true);
  494. }
  495. break;
  496. }
  497. }
  498. // return the new home zone
  499. return newHomeZone;
  500. }
  501. /*
  502. // Recursively walk the zones, adding all visible SceneNodes to the list of visible nodes.
  503. */
  504. void OctreeZone::findVisibleNodes(PCZCamera *camera,
  505. NodeList & visibleNodeList,
  506. RenderQueue * queue,
  507. VisibleObjectsBoundsInfo* visibleBounds,
  508. bool onlyShadowCasters,
  509. bool displayNodes,
  510. bool showBoundingBoxes)
  511. {
  512. //return immediately if nothing is in the zone.
  513. if (mHomeNodeList.size() == 0 &&
  514. mVisitorNodeList.size() == 0 &&
  515. mPortals.size() == 0)
  516. return ;
  517. // Else, the zone is automatically assumed to be visible since either
  518. // it is the camera the zone is in, or it was reached because
  519. // a connecting portal was deemed visible to the camera.
  520. // enable sky if called to do so for this zone
  521. if (mHasSky)
  522. {
  523. // enable sky
  524. mPCZSM->enableSky(true);
  525. }
  526. // Recursively find visible nodes in the zone
  527. walkOctree(camera,
  528. visibleNodeList,
  529. queue,
  530. mOctree,
  531. visibleBounds,
  532. false,
  533. onlyShadowCasters,
  534. displayNodes,
  535. showBoundingBoxes);
  536. // Here we merge both portal and antiportal visible to the camera into one list.
  537. // Then we sort them in the order from nearest to furthest from camera.
  538. PortalBaseList sortedPortalList;
  539. for (AntiPortalList::iterator iter = mAntiPortals.begin(); iter != mAntiPortals.end(); ++iter)
  540. {
  541. AntiPortal* portal = *iter;
  542. if (camera->isVisible(portal))
  543. {
  544. sortedPortalList.push_back(portal);
  545. }
  546. }
  547. for (PortalList::iterator iter = mPortals.begin(); iter != mPortals.end(); ++iter)
  548. {
  549. Portal* portal = *iter;
  550. if (camera->isVisible(portal))
  551. {
  552. sortedPortalList.push_back(portal);
  553. }
  554. }
  555. const Vector3& cameraOrigin(camera->getDerivedPosition());
  556. std::sort(sortedPortalList.begin(), sortedPortalList.end(),
  557. PortalSortDistance(cameraOrigin));
  558. // create a standalone frustum for anti portal use.
  559. // we're doing this instead of using camera because we don't need
  560. // to do camera frustum check again.
  561. PCZFrustum antiPortalFrustum;
  562. antiPortalFrustum.setOrigin(cameraOrigin);
  563. antiPortalFrustum.setProjectionType(camera->getProjectionType());
  564. // now we do culling check and remove hidden portals.
  565. // whenever we get a portal in the main loop, we can be sure that it is not
  566. // occluded by AntiPortal. So we do traversal right there and then.
  567. // This is because the portal list has been sorted.
  568. size_t sortedPortalListCount = sortedPortalList.size();
  569. for (size_t i = 0; i < sortedPortalListCount; ++i)
  570. {
  571. PortalBase* portalBase = sortedPortalList[i];
  572. if (!portalBase) continue; // skip removed portal.
  573. if (portalBase->getTypeFlags() == PortalFactory::FACTORY_TYPE_FLAG)
  574. {
  575. Portal* portal = static_cast<Portal*>(portalBase);
  576. // portal is visible. Add the portal as extra culling planes to camera
  577. int planes_added = camera->addPortalCullingPlanes(portal);
  578. // tell target zone it's visible this frame
  579. portal->getTargetZone()->setLastVisibleFrame(mLastVisibleFrame);
  580. portal->getTargetZone()->setLastVisibleFromCamera(camera);
  581. // recurse into the connected zone
  582. portal->getTargetZone()->findVisibleNodes(camera,
  583. visibleNodeList,
  584. queue,
  585. visibleBounds,
  586. onlyShadowCasters,
  587. displayNodes,
  588. showBoundingBoxes);
  589. if (planes_added > 0)
  590. {
  591. // Then remove the extra culling planes added before going to the next portal in the list.
  592. camera->removePortalCullingPlanes(portal);
  593. }
  594. }
  595. else if (i < sortedPortalListCount) // skip antiportal test if it is the last item in the list.
  596. {
  597. // this is an anti portal. So we use it to test preceding portals in the list.
  598. AntiPortal* antiPortal = static_cast<AntiPortal*>(portalBase);
  599. int planes_added = antiPortalFrustum.addPortalCullingPlanes(antiPortal);
  600. for (size_t j = i + 1; j < sortedPortalListCount; ++j)
  601. {
  602. PortalBase* otherPortal = sortedPortalList[j];
  603. // Since this is an antiportal, we are doing the inverse of the test.
  604. // Here if the portal is fully visible in the anti portal fustrum, it means it's hidden.
  605. if (otherPortal && antiPortalFrustum.isFullyVisible(otherPortal))
  606. sortedPortalList[j] = NULL;
  607. }
  608. if (planes_added > 0)
  609. {
  610. // Then remove the extra culling planes added before going to the next portal in the list.
  611. antiPortalFrustum.removePortalCullingPlanes(antiPortal);
  612. }
  613. }
  614. }
  615. }
  616. void OctreeZone::walkOctree(PCZCamera *camera,
  617. NodeList & visibleNodeList,
  618. RenderQueue *queue,
  619. Octree *octant,
  620. VisibleObjectsBoundsInfo* visibleBounds,
  621. bool foundvisible,
  622. bool onlyShadowCasters,
  623. bool displayNodes,
  624. bool showBoundingBoxes)
  625. {
  626. //return immediately if nothing is in the node.
  627. if ( octant -> numNodes() == 0 )
  628. return ;
  629. PCZCamera::Visibility v = PCZCamera::NONE;
  630. if ( foundvisible )
  631. {
  632. v = PCZCamera::FULL;
  633. }
  634. else if ( octant == mOctree )
  635. {
  636. v = PCZCamera::PARTIAL;
  637. }
  638. else
  639. {
  640. AxisAlignedBox box;
  641. octant -> _getCullBounds( &box );
  642. v = camera -> getVisibility( box );
  643. }
  644. // if the octant is visible, or if it's the root node...
  645. if ( v != PCZCamera::NONE )
  646. {
  647. //Add stuff to be rendered;
  648. PCZSceneNodeList::iterator it = octant -> mNodes.begin();
  649. bool vis = true;
  650. while ( it != octant -> mNodes.end() )
  651. {
  652. PCZSceneNode * sn = *it;
  653. // if the scene node is already visible, then we can skip it
  654. if (sn->getLastVisibleFrame() != mLastVisibleFrame ||
  655. sn->getLastVisibleFromCamera() != camera)
  656. {
  657. // if this octree is partially visible, manually cull all
  658. // scene nodes attached directly to this level.
  659. if ( v == PCZCamera::PARTIAL )
  660. {
  661. vis = camera -> isVisible( sn -> _getWorldAABB() );
  662. }
  663. if ( vis )
  664. {
  665. // add the node to the render queue
  666. sn -> _addToRenderQueue(camera, queue, onlyShadowCasters, visibleBounds );
  667. // add it to the list of visible nodes
  668. visibleNodeList.push_back( sn );
  669. // if we are displaying nodes, add the node renderable to the queue
  670. if ( displayNodes )
  671. {
  672. queue -> addRenderable( sn->getDebugRenderable() );
  673. }
  674. // if the scene manager or the node wants the bounding box shown, add it to the queue
  675. if (sn->getShowBoundingBox() || showBoundingBoxes)
  676. {
  677. sn->_addBoundingBoxToQueue(queue);
  678. }
  679. // flag the node as being visible this frame
  680. sn->setLastVisibleFrame(mLastVisibleFrame);
  681. sn->setLastVisibleFromCamera(camera);
  682. }
  683. }
  684. ++it;
  685. }
  686. Octree* child;
  687. bool childfoundvisible = (v == PCZCamera::FULL);
  688. if ( (child = octant -> mChildren[ 0 ][ 0 ][ 0 ]) != 0 )
  689. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  690. if ( (child = octant -> mChildren[ 1 ][ 0 ][ 0 ]) != 0 )
  691. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  692. if ( (child = octant -> mChildren[ 0 ][ 1 ][ 0 ]) != 0 )
  693. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  694. if ( (child = octant -> mChildren[ 1 ][ 1 ][ 0 ]) != 0 )
  695. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  696. if ( (child = octant -> mChildren[ 0 ][ 0 ][ 1 ]) != 0 )
  697. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  698. if ( (child = octant -> mChildren[ 1 ][ 0 ][ 1 ]) != 0 )
  699. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  700. if ( (child = octant -> mChildren[ 0 ][ 1 ][ 1 ]) != 0 )
  701. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  702. if ( (child = octant -> mChildren[ 1 ][ 1 ][ 1 ]) != 0 )
  703. walkOctree( camera, visibleNodeList, queue, child, visibleBounds, childfoundvisible, onlyShadowCasters, displayNodes, showBoundingBoxes );
  704. }
  705. }
  706. // --- find nodes which intersect various types of BV's ---
  707. void OctreeZone::_findNodes(const AxisAlignedBox &t,
  708. PCZSceneNodeList &list,
  709. PortalList &visitedPortals,
  710. bool includeVisitors,
  711. bool recurseThruPortals,
  712. PCZSceneNode *exclude )
  713. {
  714. // if this zone has an enclosure, check against the enclosure AABB first
  715. if (mEnclosureNode)
  716. {
  717. if (!mEnclosureNode->_getWorldAABB().intersects(t))
  718. {
  719. // AABB of zone does not intersect t, just return.
  720. return;
  721. }
  722. }
  723. // use the Octree to more efficiently find nodes intersecting the aab
  724. mOctree->_findNodes(t, list, exclude, includeVisitors, false);
  725. // if asked to, recurse through portals
  726. if (recurseThruPortals)
  727. {
  728. PortalList::iterator pit = mPortals.begin();
  729. while ( pit != mPortals.end() )
  730. {
  731. Portal * portal = *pit;
  732. // check portal versus boundign box
  733. if (portal->intersects(t))
  734. {
  735. // make sure portal hasn't already been recursed through
  736. PortalList::iterator pit2 = std::find(visitedPortals.begin(), visitedPortals.end(), portal);
  737. if (pit2 == visitedPortals.end())
  738. {
  739. // save portal to the visitedPortals list
  740. visitedPortals.push_front(portal);
  741. // recurse into the connected zone
  742. portal->getTargetZone()->_findNodes(t,
  743. list,
  744. visitedPortals,
  745. includeVisitors,
  746. recurseThruPortals,
  747. exclude);
  748. }
  749. }
  750. pit++;
  751. }
  752. }
  753. }
  754. void OctreeZone::_findNodes(const Sphere &t,
  755. PCZSceneNodeList &list,
  756. PortalList &visitedPortals,
  757. bool includeVisitors,
  758. bool recurseThruPortals,
  759. PCZSceneNode *exclude )
  760. {
  761. // if this zone has an enclosure, check against the enclosure AABB first
  762. if (mEnclosureNode)
  763. {
  764. if (!mEnclosureNode->_getWorldAABB().intersects(t))
  765. {
  766. // AABB of zone does not intersect t, just return.
  767. return;
  768. }
  769. }
  770. // use the Octree to more efficiently find nodes intersecting the sphere
  771. mOctree->_findNodes(t, list, exclude, includeVisitors, false);
  772. // if asked to, recurse through portals
  773. if (recurseThruPortals)
  774. {
  775. PortalList::iterator pit = mPortals.begin();
  776. while ( pit != mPortals.end() )
  777. {
  778. Portal * portal = *pit;
  779. // check portal versus boundign box
  780. if (portal->intersects(t))
  781. {
  782. // make sure portal hasn't already been recursed through
  783. PortalList::iterator pit2 = std::find(visitedPortals.begin(), visitedPortals.end(), portal);
  784. if (pit2 == visitedPortals.end())
  785. {
  786. // save portal to the visitedPortals list
  787. visitedPortals.push_front(portal);
  788. // recurse into the connected zone
  789. portal->getTargetZone()->_findNodes(t,
  790. list,
  791. visitedPortals,
  792. includeVisitors,
  793. recurseThruPortals,
  794. exclude);
  795. }
  796. }
  797. pit++;
  798. }
  799. }
  800. }
  801. void OctreeZone::_findNodes(const PlaneBoundedVolume &t,
  802. PCZSceneNodeList &list,
  803. PortalList &visitedPortals,
  804. bool includeVisitors,
  805. bool recurseThruPortals,
  806. PCZSceneNode *exclude)
  807. {
  808. // if this zone has an enclosure, check against the enclosure AABB first
  809. if (mEnclosureNode)
  810. {
  811. if (!t.intersects(mEnclosureNode->_getWorldAABB()))
  812. {
  813. // AABB of zone does not intersect t, just return.
  814. return;
  815. }
  816. }
  817. // use the Octree to more efficiently find nodes intersecting the plane bounded volume
  818. mOctree->_findNodes(t, list, exclude, includeVisitors, false);
  819. // if asked to, recurse through portals
  820. if (recurseThruPortals)
  821. {
  822. PortalList::iterator pit = mPortals.begin();
  823. while ( pit != mPortals.end() )
  824. {
  825. Portal * portal = *pit;
  826. // check portal versus boundign box
  827. if (portal->intersects(t))
  828. {
  829. // make sure portal hasn't already been recursed through
  830. PortalList::iterator pit2 = std::find(visitedPortals.begin(), visitedPortals.end(), portal);
  831. if (pit2 == visitedPortals.end())
  832. {
  833. // save portal to the visitedPortals list
  834. visitedPortals.push_front(portal);
  835. // recurse into the connected zone
  836. portal->getTargetZone()->_findNodes(t,
  837. list,
  838. visitedPortals,
  839. includeVisitors,
  840. recurseThruPortals,
  841. exclude);
  842. }
  843. }
  844. pit++;
  845. }
  846. }
  847. }
  848. void OctreeZone::_findNodes(const Ray &t,
  849. PCZSceneNodeList &list,
  850. PortalList &visitedPortals,
  851. bool includeVisitors,
  852. bool recurseThruPortals,
  853. PCZSceneNode *exclude )
  854. {
  855. // if this zone has an enclosure, check against the enclosure AABB first
  856. if (mEnclosureNode)
  857. {
  858. std::pair<bool, Real> nsect = t.intersects(mEnclosureNode->_getWorldAABB());
  859. if (!nsect.first)
  860. {
  861. // AABB of zone does not intersect t, just return.
  862. return;
  863. }
  864. }
  865. // use the Octree to more efficiently find nodes intersecting the ray
  866. mOctree->_findNodes(t, list, exclude, includeVisitors, false);
  867. // if asked to, recurse through portals
  868. if (recurseThruPortals)
  869. {
  870. PortalList::iterator pit = mPortals.begin();
  871. while ( pit != mPortals.end() )
  872. {
  873. Portal * portal = *pit;
  874. // check portal versus boundign box
  875. if (portal->intersects(t))
  876. {
  877. // make sure portal hasn't already been recursed through
  878. PortalList::iterator pit2 = std::find(visitedPortals.begin(), visitedPortals.end(), portal);
  879. if (pit2 == visitedPortals.end())
  880. {
  881. // save portal to the visitedPortals list
  882. visitedPortals.push_front(portal);
  883. // recurse into the connected zone
  884. portal->getTargetZone()->_findNodes(t,
  885. list,
  886. visitedPortals,
  887. includeVisitors,
  888. recurseThruPortals,
  889. exclude);
  890. }
  891. }
  892. pit++;
  893. }
  894. }
  895. }
  896. /** called when the scene manager creates a camera because
  897. some zone managers (like TerrainZone) need the camera info.
  898. */
  899. void OctreeZone::notifyCameraCreated( Camera* c )
  900. {
  901. }
  902. //-------------------------------------------------------------------------
  903. void OctreeZone::notifyWorldGeometryRenderQueue(uint8 qid)
  904. {
  905. }
  906. //-------------------------------------------------------------------------
  907. void OctreeZone::notifyBeginRenderScene(void)
  908. {
  909. }
  910. //-------------------------------------------------------------------------
  911. void OctreeZone::setZoneGeometry(const String &filename, PCZSceneNode * parentNode)
  912. {
  913. String entityName, nodeName;
  914. entityName = this->getName() + "_entity";
  915. nodeName = this->getName() + "_Node";
  916. Entity *ent = mPCZSM->createEntity(entityName , filename );
  917. // create a node for the entity
  918. PCZSceneNode * node;
  919. node = (PCZSceneNode*)(parentNode->createChildSceneNode(nodeName));
  920. // attach the entity to the node
  921. node->attachObject(ent);
  922. // set the node as the enclosure node
  923. setEnclosureNode(node);
  924. }
  925. //-------------------------------------------------------------------------
  926. void OctreeZone::getAABB(AxisAlignedBox & aabb)
  927. {
  928. // get the Octree bounding box
  929. aabb = mOctree->mBox;
  930. }
  931. //-------------------------------------------------------------------------
  932. void OctreeZone::init(AxisAlignedBox &box, int depth)
  933. {
  934. if ( mOctree != 0 )
  935. OGRE_DELETE mOctree;
  936. mOctree = OGRE_NEW Octree( this, 0 );
  937. mMaxDepth = depth;
  938. mBox = box;
  939. mOctree -> mBox = box;
  940. Vector3 min = box.getMinimum();
  941. Vector3 max = box.getMaximum();
  942. mOctree -> mHalfSize = ( max - min ) / 2;
  943. }
  944. void OctreeZone::resize( const AxisAlignedBox &box )
  945. {
  946. // delete the octree
  947. OGRE_DELETE mOctree;
  948. // create a new octree
  949. mOctree = OGRE_NEW Octree( this, 0 );
  950. // set the octree bounding box
  951. mOctree->mBox = box;
  952. const Vector3 min = box.getMinimum();
  953. const Vector3 max = box.getMaximum();
  954. mOctree->mHalfSize = ( max - min ) * 0.5f;
  955. OctreeZoneData * ozd;
  956. PCZSceneNodeList::iterator it = mHomeNodeList.begin();
  957. while ( it != mHomeNodeList.end() )
  958. {
  959. PCZSceneNode * on = ( *it );
  960. ozd = (OctreeZoneData*)(on->getZoneData(this));
  961. ozd -> setOctant( 0 );
  962. updateNodeOctant( ozd );
  963. ++it;
  964. }
  965. it = mVisitorNodeList.begin();
  966. while ( it != mVisitorNodeList.end() )
  967. {
  968. PCZSceneNode * on = ( *it );
  969. ozd = (OctreeZoneData*)(on->getZoneData(this));
  970. ozd -> setOctant( 0 );
  971. updateNodeOctant( ozd );
  972. ++it;
  973. }
  974. }
  975. bool OctreeZone::setOption( const String & key, const void * val )
  976. {
  977. if ( key == "Size" )
  978. {
  979. resize( * static_cast < const AxisAlignedBox * > ( val ) );
  980. return true;
  981. }
  982. else if ( key == "Depth" )
  983. {
  984. mMaxDepth = * static_cast < const int * > ( val );
  985. // copy the box since resize will delete mOctree and reference won't work
  986. AxisAlignedBox box = mOctree->mBox;
  987. resize(box);
  988. return true;
  989. }
  990. /* else if ( key == "ShowOctree" )
  991. {
  992. mShowBoxes = * static_cast < const bool * > ( val );
  993. return true;
  994. }*/
  995. return false;
  996. }
  997. void OctreeZone::updateNodeOctant( OctreeZoneData * zoneData )
  998. {
  999. const AxisAlignedBox& box = zoneData -> mOctreeWorldAABB;
  1000. if ( box.isNull() )
  1001. return ;
  1002. // Skip if octree has been destroyed (shutdown conditions)
  1003. if (!mOctree)
  1004. return;
  1005. PCZSceneNode* node = zoneData->mAssociatedNode;
  1006. if ( zoneData->getOctant() == 0 )
  1007. {
  1008. //if outside the octree, force into the root node.
  1009. if ( ! zoneData->_isIn( mOctree -> mBox ) )
  1010. mOctree->_addNode( node );
  1011. else
  1012. addNodeToOctree( node, mOctree );
  1013. return ;
  1014. }
  1015. if ( ! zoneData->_isIn( zoneData->getOctant()->mBox ) )
  1016. {
  1017. //if outside the octree, force into the root node.
  1018. if ( !zoneData->_isIn( mOctree -> mBox ) )
  1019. {
  1020. // skip if it's already in the root node.
  1021. if (((OctreeZoneData*)node->getZoneData(this))->getOctant() == mOctree)
  1022. return;
  1023. removeNodeFromOctree( node );
  1024. mOctree->_addNode( node );
  1025. }
  1026. else
  1027. addNodeToOctree( node, mOctree );
  1028. }
  1029. }
  1030. /** Only removes the node from the octree. It leaves the octree, even if it's empty.
  1031. */
  1032. void OctreeZone::removeNodeFromOctree( PCZSceneNode * n )
  1033. {
  1034. // Skip if octree has been destroyed (shutdown conditions)
  1035. if (!mOctree)
  1036. return;
  1037. Octree * oct = ((OctreeZoneData*)n->getZoneData(this)) -> getOctant();
  1038. if ( oct )
  1039. {
  1040. oct -> _removeNode( n );
  1041. }
  1042. ((OctreeZoneData*)n->getZoneData(this))->setOctant(0);
  1043. }
  1044. void OctreeZone::addNodeToOctree( PCZSceneNode * n, Octree *octant, int depth )
  1045. {
  1046. // Skip if octree has been destroyed (shutdown conditions)
  1047. if (!mOctree)
  1048. return;
  1049. const AxisAlignedBox& bx = n -> _getWorldAABB();
  1050. //if the octree is twice as big as the scene node,
  1051. //we will add it to a child.
  1052. if ( ( depth < mMaxDepth ) && octant -> _isTwiceSize( bx ) )
  1053. {
  1054. int x, y, z;
  1055. octant -> _getChildIndexes( bx, &x, &y, &z );
  1056. if ( octant -> mChildren[ x ][ y ][ z ] == 0 )
  1057. {
  1058. octant -> mChildren[ x ][ y ][ z ] = OGRE_NEW Octree( this, octant );
  1059. const Vector3& octantMin = octant -> mBox.getMinimum();
  1060. const Vector3& octantMax = octant -> mBox.getMaximum();
  1061. Vector3 min, max;
  1062. if ( x == 0 )
  1063. {
  1064. min.x = octantMin.x;
  1065. max.x = ( octantMin.x + octantMax.x ) / 2;
  1066. }
  1067. else
  1068. {
  1069. min.x = ( octantMin.x + octantMax.x ) / 2;
  1070. max.x = octantMax.x;
  1071. }
  1072. if ( y == 0 )
  1073. {
  1074. min.y = octantMin.y;
  1075. max.y = ( octantMin.y + octantMax.y ) / 2;
  1076. }
  1077. else
  1078. {
  1079. min.y = ( octantMin.y + octantMax.y ) / 2;
  1080. max.y = octantMax.y;
  1081. }
  1082. if ( z == 0 )
  1083. {
  1084. min.z = octantMin.z;
  1085. max.z = ( octantMin.z + octantMax.z ) / 2;
  1086. }
  1087. else
  1088. {
  1089. min.z = ( octantMin.z + octantMax.z ) / 2;
  1090. max.z = octantMax.z;
  1091. }
  1092. octant -> mChildren[ x ][ y ][ z ] -> mBox.setExtents( min, max );
  1093. octant -> mChildren[ x ][ y ][ z ] -> mHalfSize = ( max - min ) / 2;
  1094. }
  1095. addNodeToOctree( n, octant -> mChildren[ x ][ y ][ z ], ++depth );
  1096. }
  1097. else
  1098. {
  1099. if (((OctreeZoneData*)n->getZoneData(this))->getOctant() == octant)
  1100. return;
  1101. removeNodeFromOctree( n );
  1102. octant -> _addNode( n );
  1103. }
  1104. }
  1105. /***********************************************************************\
  1106. OctreeZoneData - OctreeZone-specific Data structure for Scene Nodes
  1107. ************************************************************************/
  1108. OctreeZoneData::OctreeZoneData(PCZSceneNode * node, PCZone * zone)
  1109. : ZoneData(node, zone)
  1110. {
  1111. mOctant = 0;
  1112. }
  1113. OctreeZoneData::~OctreeZoneData()
  1114. {
  1115. }
  1116. /* Update the octreezone specific data for a node */
  1117. void OctreeZoneData::update(void)
  1118. {
  1119. mOctreeWorldAABB.setNull();
  1120. // need to use object iterator here.
  1121. SceneNode::ObjectIterator oit = mAssociatedNode->getAttachedObjectIterator();
  1122. while( oit.hasMoreElements() )
  1123. {
  1124. MovableObject * m = oit.getNext();
  1125. // merge world bounds of object
  1126. mOctreeWorldAABB.merge( m->getWorldBoundingBox(true) );
  1127. }
  1128. // update the Octant for the node because things might have moved.
  1129. // if it hasn't been added to the octree, add it, and if has moved
  1130. // enough to leave it's current node, we'll update it.
  1131. if ( ! mOctreeWorldAABB.isNull() )
  1132. {
  1133. static_cast < OctreeZone * > ( mAssociatedZone ) -> updateNodeOctant( this );
  1134. }
  1135. }
  1136. /** Since we are loose, only check the center.
  1137. */
  1138. bool OctreeZoneData::_isIn( AxisAlignedBox &box )
  1139. {
  1140. // Always fail if not in the scene graph or box is null
  1141. if (!mAssociatedNode->isInSceneGraph() || box.isNull()) return false;
  1142. // Always succeed if AABB is infinite
  1143. if (box.isInfinite())
  1144. return true;
  1145. Vector3 center = mAssociatedNode->_getWorldAABB().getMaximum().midPoint( mAssociatedNode->_getWorldAABB().getMinimum() );
  1146. Vector3 bmin = box.getMinimum();
  1147. Vector3 bmax = box.getMaximum();
  1148. bool centre = ( bmax > center && bmin < center );
  1149. if (!centre)
  1150. return false;
  1151. // Even if covering the centre line, need to make sure this BB is not large
  1152. // enough to require being moved up into parent. When added, bboxes would
  1153. // end up in parent due to cascade but when updating need to deal with
  1154. // bbox growing too large for this child
  1155. Vector3 octreeSize = bmax - bmin;
  1156. Vector3 nodeSize = mAssociatedNode->_getWorldAABB().getMaximum() - mAssociatedNode->_getWorldAABB().getMinimum();
  1157. return nodeSize < octreeSize;
  1158. }
  1159. //-------------------------------------------------------------------------
  1160. // OctreeZoneFactory functions
  1161. //String octreeZoneString = String("ZoneType_Octree");
  1162. OctreeZoneFactory::OctreeZoneFactory() : PCZoneFactory("ZoneType_Octree")
  1163. {
  1164. }
  1165. OctreeZoneFactory::~OctreeZoneFactory()
  1166. {
  1167. }
  1168. bool OctreeZoneFactory::supportsPCZoneType(const String& zoneType)
  1169. {
  1170. if (mFactoryTypeName == zoneType)
  1171. {
  1172. return true;
  1173. }
  1174. return false;
  1175. }
  1176. PCZone* OctreeZoneFactory::createPCZone(PCZSceneManager * pczsm, const String& zoneName)
  1177. {
  1178. return OGRE_NEW OctreeZone(pczsm, zoneName);
  1179. }
  1180. }