| 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 |  | 
|---|
| 7 | Copyright (c) 2000-2006 Torus Knot Software Ltd | 
|---|
| 8 | Also see acknowledgements in Readme.html | 
|---|
| 9 |  | 
|---|
| 10 | This program is free software; you can redistribute it and/or modify it under | 
|---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software | 
|---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later | 
|---|
| 13 | version. | 
|---|
| 14 |  | 
|---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. | 
|---|
| 18 |  | 
|---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with | 
|---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
|---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to | 
|---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. | 
|---|
| 23 |  | 
|---|
| 24 | You may alternatively use this source under the terms of a specific version of | 
|---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from | 
|---|
| 26 | Torus Knot Software Ltd. | 
|---|
| 27 | ----------------------------------------------------------------------------- | 
|---|
| 28 | */ | 
|---|
| 29 | #include "OgreBspSceneManager.h" | 
|---|
| 30 | #include "OgreBspResourceManager.h" | 
|---|
| 31 | #include "OgreBspNode.h" | 
|---|
| 32 | #include "OgreException.h" | 
|---|
| 33 | #include "OgreRenderSystem.h" | 
|---|
| 34 | #include "OgreCamera.h" | 
|---|
| 35 | #include "OgreMaterial.h" | 
|---|
| 36 | #include "OgrePatchSurface.h" | 
|---|
| 37 | #include "OgreMesh.h" | 
|---|
| 38 | #include "OgreSubMesh.h" | 
|---|
| 39 | #include "OgreMath.h" | 
|---|
| 40 | #include "OgreControllerManager.h" | 
|---|
| 41 | #include "OgreLogManager.h" | 
|---|
| 42 | #include "OgreBspSceneNode.h" | 
|---|
| 43 | #include "OgreStringConverter.h" | 
|---|
| 44 | #include "OgreLogManager.h" | 
|---|
| 45 | #include "OgreTechnique.h" | 
|---|
| 46 | #include "OgrePass.h" | 
|---|
| 47 | #include "OgreMaterialManager.h" | 
|---|
| 48 |  | 
|---|
| 49 |  | 
|---|
| 50 | #include <fstream> | 
|---|
| 51 |  | 
|---|
| 52 | namespace Ogre { | 
|---|
| 53 |  | 
|---|
| 54 |     //----------------------------------------------------------------------- | 
|---|
| 55 |     BspSceneManager::BspSceneManager(const String& name) | 
|---|
| 56 |                 : SceneManager(name) | 
|---|
| 57 |     { | 
|---|
| 58 |         // Set features for debugging render | 
|---|
| 59 |         mShowNodeAABs = false; | 
|---|
| 60 |  | 
|---|
| 61 |         // No sky by default | 
|---|
| 62 |         mSkyPlaneEnabled = false; | 
|---|
| 63 |         mSkyBoxEnabled = false; | 
|---|
| 64 |         mSkyDomeEnabled = false; | 
|---|
| 65 |  | 
|---|
| 66 |         mLevel.setNull(); | 
|---|
| 67 |  | 
|---|
| 68 |     } | 
|---|
| 69 |         //----------------------------------------------------------------------- | 
|---|
| 70 |         const String& BspSceneManager::getTypeName(void) const | 
|---|
| 71 |         { | 
|---|
| 72 |                 return BspSceneManagerFactory::FACTORY_TYPE_NAME; | 
|---|
| 73 |         } | 
|---|
| 74 |     //----------------------------------------------------------------------- | 
|---|
| 75 |     BspSceneManager::~BspSceneManager() | 
|---|
| 76 |     { | 
|---|
| 77 |         freeMemory(); | 
|---|
| 78 |         mLevel.setNull(); | 
|---|
| 79 |     } | 
|---|
| 80 |     //----------------------------------------------------------------------- | 
|---|
| 81 |     size_t BspSceneManager::estimateWorldGeometry(const String& filename) | 
|---|
| 82 |     { | 
|---|
| 83 |         return BspLevel::calculateLoadingStages(filename); | 
|---|
| 84 |          | 
|---|
| 85 |     } | 
|---|
| 86 |     //----------------------------------------------------------------------- | 
|---|
| 87 |     size_t BspSceneManager::estimateWorldGeometry(DataStreamPtr& stream,  | 
|---|
| 88 |                 const String& typeName) | 
|---|
| 89 |     { | 
|---|
| 90 |         return BspLevel::calculateLoadingStages(stream); | 
|---|
| 91 |          | 
|---|
| 92 |     } | 
|---|
| 93 |     //----------------------------------------------------------------------- | 
|---|
| 94 |     void BspSceneManager::setWorldGeometry(const String& filename) | 
|---|
| 95 |     { | 
|---|
| 96 |         mLevel.setNull(); | 
|---|
| 97 |         // Check extension is .bsp | 
|---|
| 98 |         char extension[6]; | 
|---|
| 99 |         size_t pos = filename.find_last_of("."); | 
|---|
| 100 |                 if( pos == String::npos ) | 
|---|
| 101 |             OGRE_EXCEPT( | 
|---|
| 102 |                                 Exception::ERR_INVALIDPARAMS, | 
|---|
| 103 |                 "Unable to load world geometry. Invalid extension (must be .bsp).", | 
|---|
| 104 |                 "BspSceneManager::setWorldGeometry"); | 
|---|
| 105 |  | 
|---|
| 106 |         strcpy(extension, filename.substr(pos + 1, filename.length() - pos).c_str()); | 
|---|
| 107 |  | 
|---|
| 108 |         if (stricmp(extension, "bsp")) | 
|---|
| 109 |             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, | 
|---|
| 110 |                         "Unable to load world geometry. Invalid extension (must be .bsp).", | 
|---|
| 111 |             "BspSceneManager::setWorldGeometry"); | 
|---|
| 112 |  | 
|---|
| 113 |         // Load using resource manager | 
|---|
| 114 |         mLevel = BspResourceManager::getSingleton().load(filename,  | 
|---|
| 115 |             ResourceGroupManager::getSingleton().getWorldResourceGroupName()); | 
|---|
| 116 |  | 
|---|
| 117 |                 if (mLevel->isSkyEnabled()) | 
|---|
| 118 |                 { | 
|---|
| 119 |                         // Quake3 is always aligned with Z upwards | 
|---|
| 120 |                         Quaternion q; | 
|---|
| 121 |                         q.FromAngleAxis(Radian(Math::HALF_PI), Vector3::UNIT_X); | 
|---|
| 122 |                         // Also draw last, and make close to camera (far clip plane is shorter) | 
|---|
| 123 |                         setSkyDome(true, mLevel->getSkyMaterialName(), | 
|---|
| 124 |                                 mLevel->getSkyCurvature(), 12, 2000, false, q); | 
|---|
| 125 |                 } | 
|---|
| 126 |                 else | 
|---|
| 127 |                 { | 
|---|
| 128 |                         setSkyDome(false, StringUtil::BLANK); | 
|---|
| 129 |                 } | 
|---|
| 130 |  | 
|---|
| 131 |         // Init static render operation | 
|---|
| 132 |         mRenderOp.vertexData = mLevel->mVertexData; | 
|---|
| 133 |         // index data is per-frame | 
|---|
| 134 |         mRenderOp.indexData = new IndexData(); | 
|---|
| 135 |         mRenderOp.indexData->indexStart = 0; | 
|---|
| 136 |         mRenderOp.indexData->indexCount = 0; | 
|---|
| 137 |         // Create enough index space to render whole level | 
|---|
| 138 |         mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton() | 
|---|
| 139 |             .createIndexBuffer( | 
|---|
| 140 |                 HardwareIndexBuffer::IT_32BIT, // always 32-bit | 
|---|
| 141 |                 mLevel->mNumIndexes,  | 
|---|
| 142 |                 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false); | 
|---|
| 143 |  | 
|---|
| 144 |         mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST; | 
|---|
| 145 |         mRenderOp.useIndexes = true; | 
|---|
| 146 |  | 
|---|
| 147 |  | 
|---|
| 148 |     } | 
|---|
| 149 |     //----------------------------------------------------------------------- | 
|---|
| 150 |     void BspSceneManager::setWorldGeometry(DataStreamPtr& stream,  | 
|---|
| 151 |                 const String& typeName) | 
|---|
| 152 |     { | 
|---|
| 153 |         mLevel.setNull(); | 
|---|
| 154 |  | 
|---|
| 155 |         // Load using resource manager | 
|---|
| 156 |         mLevel = BspResourceManager::getSingleton().load(stream,  | 
|---|
| 157 |                         ResourceGroupManager::getSingleton().getWorldResourceGroupName()); | 
|---|
| 158 |  | 
|---|
| 159 |                 if (mLevel->isSkyEnabled()) | 
|---|
| 160 |                 { | 
|---|
| 161 |                         // Quake3 is always aligned with Z upwards | 
|---|
| 162 |                         Quaternion q; | 
|---|
| 163 |                         q.FromAngleAxis(Radian(Math::HALF_PI), Vector3::UNIT_X); | 
|---|
| 164 |                         // Also draw last, and make close to camera (far clip plane is shorter) | 
|---|
| 165 |                         setSkyDome(true, mLevel->getSkyMaterialName(), | 
|---|
| 166 |                                 mLevel->getSkyCurvature(), 12, 2000, false, q); | 
|---|
| 167 |                 } | 
|---|
| 168 |                 else | 
|---|
| 169 |                 { | 
|---|
| 170 |                         setSkyDome(false, StringUtil::BLANK); | 
|---|
| 171 |                 } | 
|---|
| 172 |  | 
|---|
| 173 |         // Init static render operation | 
|---|
| 174 |         mRenderOp.vertexData = mLevel->mVertexData; | 
|---|
| 175 |         // index data is per-frame | 
|---|
| 176 |         mRenderOp.indexData = new IndexData(); | 
|---|
| 177 |         mRenderOp.indexData->indexStart = 0; | 
|---|
| 178 |         mRenderOp.indexData->indexCount = 0; | 
|---|
| 179 |         // Create enough index space to render whole level | 
|---|
| 180 |         mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton() | 
|---|
| 181 |             .createIndexBuffer( | 
|---|
| 182 |                 HardwareIndexBuffer::IT_32BIT, // always 32-bit | 
|---|
| 183 |                 mLevel->mNumIndexes,  | 
|---|
| 184 |                 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false); | 
|---|
| 185 |  | 
|---|
| 186 |         mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST; | 
|---|
| 187 |         mRenderOp.useIndexes = true; | 
|---|
| 188 |  | 
|---|
| 189 |  | 
|---|
| 190 |     } | 
|---|
| 191 |     //----------------------------------------------------------------------- | 
|---|
| 192 |     void BspSceneManager::_findVisibleObjects(Camera* cam,  | 
|---|
| 193 |                 VisibleObjectsBoundsInfo* visibleBounds, bool onlyShadowCasters) | 
|---|
| 194 |     { | 
|---|
| 195 |         // Clear unique list of movables for this frame | 
|---|
| 196 |         mMovablesForRendering.clear(); | 
|---|
| 197 |  | 
|---|
| 198 |                 // Assemble an AAB on the fly which contains the scene elements visible | 
|---|
| 199 |                 // by the camera. | 
|---|
| 200 |                 CamVisibleObjectsMap::iterator findIt = mCamVisibleObjectsMap.find( cam ); | 
|---|
| 201 |  | 
|---|
| 202 |         // Walk the tree, tag static geometry, return camera's node (for info only) | 
|---|
| 203 |         // Movables are now added to the render queue in processVisibleLeaf | 
|---|
| 204 |         walkTree(cam, &(findIt->second), onlyShadowCasters); | 
|---|
| 205 |     } | 
|---|
| 206 |     //----------------------------------------------------------------------- | 
|---|
| 207 |     void BspSceneManager::renderStaticGeometry(void) | 
|---|
| 208 |     { | 
|---|
| 209 |                 // Check we should be rendering | 
|---|
| 210 |                 if (!isRenderQueueToBeProcessed(mWorldGeometryRenderQueue)) | 
|---|
| 211 |                         return; | 
|---|
| 212 |  | 
|---|
| 213 |         // Cache vertex/face data first | 
|---|
| 214 |         std::vector<StaticFaceGroup*>::const_iterator faceGrpi; | 
|---|
| 215 |         static RenderOperation patchOp; | 
|---|
| 216 |          | 
|---|
| 217 |         // no world transform required | 
|---|
| 218 |         mDestRenderSystem->_setWorldMatrix(Matrix4::IDENTITY); | 
|---|
| 219 |         // Set view / proj | 
|---|
| 220 |         mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix(true)); | 
|---|
| 221 |         mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrixRS()); | 
|---|
| 222 |  | 
|---|
| 223 |         // For each material in turn, cache rendering data & render | 
|---|
| 224 |         MaterialFaceGroupMap::const_iterator mati; | 
|---|
| 225 |  | 
|---|
| 226 |         for (mati = mMatFaceGroupMap.begin(); mati != mMatFaceGroupMap.end(); ++mati) | 
|---|
| 227 |         { | 
|---|
| 228 |             // Get Material | 
|---|
| 229 |             Material* thisMaterial = mati->first; | 
|---|
| 230 |  | 
|---|
| 231 |             // Empty existing cache | 
|---|
| 232 |             mRenderOp.indexData->indexCount = 0; | 
|---|
| 233 |             // lock index buffer ready to receive data | 
|---|
| 234 |             unsigned int* pIdx = static_cast<unsigned int*>( | 
|---|
| 235 |                 mRenderOp.indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); | 
|---|
| 236 |  | 
|---|
| 237 |             for (faceGrpi = mati->second.begin(); faceGrpi != mati->second.end(); ++faceGrpi) | 
|---|
| 238 |             { | 
|---|
| 239 |                 // Cache each | 
|---|
| 240 |                 unsigned int numelems = cacheGeometry(pIdx, *faceGrpi); | 
|---|
| 241 |                 mRenderOp.indexData->indexCount += numelems; | 
|---|
| 242 |                 pIdx += numelems; | 
|---|
| 243 |             } | 
|---|
| 244 |             // Unlock the buffer | 
|---|
| 245 |             mRenderOp.indexData->indexBuffer->unlock(); | 
|---|
| 246 |  | 
|---|
| 247 |             // Skip if no faces to process (we're not doing flare types yet) | 
|---|
| 248 |             if (mRenderOp.indexData->indexCount == 0) | 
|---|
| 249 |                 continue; | 
|---|
| 250 |  | 
|---|
| 251 |             Technique::PassIterator pit = thisMaterial->getTechnique(0)->getPassIterator(); | 
|---|
| 252 |  | 
|---|
| 253 |             while (pit.hasMoreElements()) | 
|---|
| 254 |             { | 
|---|
| 255 |                 _setPass(pit.getNext()); | 
|---|
| 256 |  | 
|---|
| 257 |                 mDestRenderSystem->_render(mRenderOp); | 
|---|
| 258 |  | 
|---|
| 259 |  | 
|---|
| 260 |             }  | 
|---|
| 261 |  | 
|---|
| 262 |  | 
|---|
| 263 |         } // for each material | 
|---|
| 264 |  | 
|---|
| 265 |         /* | 
|---|
| 266 |         if (mShowNodeAABs) | 
|---|
| 267 |         { | 
|---|
| 268 |             mDestRenderSystem->_render(mAABGeometry); | 
|---|
| 269 |         } | 
|---|
| 270 |         */ | 
|---|
| 271 |     } | 
|---|
| 272 |     //----------------------------------------------------------------------- | 
|---|
| 273 |     void BspSceneManager::_renderVisibleObjects(void) | 
|---|
| 274 |     { | 
|---|
| 275 |         // Render static level geometry first | 
|---|
| 276 |         renderStaticGeometry(); | 
|---|
| 277 |  | 
|---|
| 278 |         // Call superclass to render the rest | 
|---|
| 279 |         SceneManager::_renderVisibleObjects(); | 
|---|
| 280 |  | 
|---|
| 281 |     } | 
|---|
| 282 |  | 
|---|
| 283 |     //----------------------------------------------------------------------- | 
|---|
| 284 |     // REMOVE THIS CRAP | 
|---|
| 285 |     //----------------------------------------------------------------------- | 
|---|
| 286 |     // Temp debug lines | 
|---|
| 287 |     bool firstTime = true; | 
|---|
| 288 |     std::ofstream of; | 
|---|
| 289 |     //----------------------------------------------------------------------- | 
|---|
| 290 |     //----------------------------------------------------------------------- | 
|---|
| 291 |     //----------------------------------------------------------------------- | 
|---|
| 292 |     BspNode* BspSceneManager::walkTree(Camera* camera,  | 
|---|
| 293 |                 VisibleObjectsBoundsInfo *visibleBounds, bool onlyShadowCasters) | 
|---|
| 294 |     { | 
|---|
| 295 |                 if (mLevel.isNull()) return 0; | 
|---|
| 296 |  | 
|---|
| 297 |         // Locate the leaf node where the camera is located | 
|---|
| 298 |         BspNode* cameraNode = mLevel->findLeaf(camera->getDerivedPosition()); | 
|---|
| 299 |  | 
|---|
| 300 |         mMatFaceGroupMap.clear(); | 
|---|
| 301 |         mFaceGroupSet.clear(); | 
|---|
| 302 |  | 
|---|
| 303 |         // Scan through all the other leaf nodes looking for visibles | 
|---|
| 304 |         int i = mLevel->mNumNodes - mLevel->mLeafStart; | 
|---|
| 305 |         BspNode* nd = mLevel->mRootNode + mLevel->mLeafStart; | 
|---|
| 306 |  | 
|---|
| 307 |         /* | 
|---|
| 308 |         if (firstTime) | 
|---|
| 309 |         { | 
|---|
| 310 |             camera->getViewMatrix(); // Force update view before report | 
|---|
| 311 |             of.open("BspSceneManager.log"); | 
|---|
| 312 |             of << *camera << std::endl; | 
|---|
| 313 |             of << "Camera Node: " << *cameraNode << std::endl; | 
|---|
| 314 |             of << "Vertex Data: " << std::endl; | 
|---|
| 315 |             for (int testi = 0; testi < mLevel->mNumVertices; ++testi) | 
|---|
| 316 |             { | 
|---|
| 317 |                 of << " " << testi << ": pos(" << | 
|---|
| 318 |                   mLevel->mVertices[testi].position[0] << ", " << | 
|---|
| 319 |                     mLevel->mVertices[testi].position[1] << ", " << mLevel->mVertices[testi].position[2] << ")" << | 
|---|
| 320 |                     " uv(" << mLevel->mVertices[testi].texcoords[0] << ", " << mLevel->mVertices[testi].texcoords[1] << ")" << | 
|---|
| 321 |                     " lm(" << mLevel->mVertices[testi].lightmap[0] << ", " << mLevel->mVertices[testi].lightmap[1] << ")" << std::endl; | 
|---|
| 322 |             } | 
|---|
| 323 |             of << "Element data:" << std::endl; | 
|---|
| 324 |             for (testi = 0; testi < mLevel->mNumElements; ++testi) | 
|---|
| 325 |             { | 
|---|
| 326 |                 of << " " << testi << ": " << mLevel->mElements[testi] << std::endl; | 
|---|
| 327 |  | 
|---|
| 328 |             } | 
|---|
| 329 |         } | 
|---|
| 330 |         */ | 
|---|
| 331 |  | 
|---|
| 332 |         while (i--) | 
|---|
| 333 |         { | 
|---|
| 334 |             if (mLevel->isLeafVisible(cameraNode, nd)) | 
|---|
| 335 |             { | 
|---|
| 336 |  | 
|---|
| 337 |                 // Visible according to PVS, check bounding box against frustum | 
|---|
| 338 |                 FrustumPlane plane; | 
|---|
| 339 |                 if (camera->isVisible(nd->getBoundingBox(), &plane)) | 
|---|
| 340 |                 { | 
|---|
| 341 |                     //if (firstTime) | 
|---|
| 342 |                     //{ | 
|---|
| 343 |                     //    of << "Visible Node: " << *nd << std::endl; | 
|---|
| 344 |                     //} | 
|---|
| 345 |                     processVisibleLeaf(nd, camera, visibleBounds, onlyShadowCasters); | 
|---|
| 346 |                     if (mShowNodeAABs) | 
|---|
| 347 |                         addBoundingBox(nd->getBoundingBox(), true); | 
|---|
| 348 |                 } | 
|---|
| 349 |             } | 
|---|
| 350 |             nd++; | 
|---|
| 351 |         } | 
|---|
| 352 |  | 
|---|
| 353 |  | 
|---|
| 354 |         // TEST | 
|---|
| 355 |         //if (firstTime) | 
|---|
| 356 |         //{ | 
|---|
| 357 |         //    of.close(); | 
|---|
| 358 |         //    firstTime = false; | 
|---|
| 359 |         //} | 
|---|
| 360 |         return cameraNode; | 
|---|
| 361 |  | 
|---|
| 362 |     } | 
|---|
| 363 |     //----------------------------------------------------------------------- | 
|---|
| 364 |     void BspSceneManager::processVisibleLeaf(BspNode* leaf, Camera* cam,  | 
|---|
| 365 |                 VisibleObjectsBoundsInfo* visibleBounds, bool onlyShadowCasters) | 
|---|
| 366 |     { | 
|---|
| 367 |         MaterialPtr pMat; | 
|---|
| 368 |         // Skip world geometry if we're only supposed to process shadow casters | 
|---|
| 369 |         // World is pre-lit | 
|---|
| 370 |         if (!onlyShadowCasters) | 
|---|
| 371 |         { | 
|---|
| 372 |             // Parse the leaf node's faces, add face groups to material map | 
|---|
| 373 |             int numGroups = leaf->getNumFaceGroups(); | 
|---|
| 374 |             int idx = leaf->getFaceGroupStart(); | 
|---|
| 375 |  | 
|---|
| 376 |             while (numGroups--) | 
|---|
| 377 |             { | 
|---|
| 378 |                 int realIndex = mLevel->mLeafFaceGroups[idx++]; | 
|---|
| 379 |                 // Check not already included | 
|---|
| 380 |                 if (mFaceGroupSet.find(realIndex) != mFaceGroupSet.end()) | 
|---|
| 381 |                     continue; | 
|---|
| 382 |                 StaticFaceGroup* faceGroup = mLevel->mFaceGroups + realIndex; | 
|---|
| 383 |                 // Get Material pointer by handle | 
|---|
| 384 |                 pMat = MaterialManager::getSingleton().getByHandle(faceGroup->materialHandle); | 
|---|
| 385 |                 assert (!pMat.isNull()); | 
|---|
| 386 |                 // Check normal (manual culling) | 
|---|
| 387 |                 ManualCullingMode cullMode = pMat->getTechnique(0)->getPass(0)->getManualCullingMode(); | 
|---|
| 388 |                 if (cullMode != MANUAL_CULL_NONE) | 
|---|
| 389 |                 { | 
|---|
| 390 |                     Real dist = faceGroup->plane.getDistance(cam->getDerivedPosition()); | 
|---|
| 391 |                     if ( (dist < 0 && cullMode == MANUAL_CULL_BACK) || | 
|---|
| 392 |                         (dist > 0 && cullMode == MANUAL_CULL_FRONT) ) | 
|---|
| 393 |                         continue; // skip | 
|---|
| 394 |                 } | 
|---|
| 395 |                 mFaceGroupSet.insert(realIndex); | 
|---|
| 396 |                 // Try to insert, will find existing if already there | 
|---|
| 397 |                 std::pair<MaterialFaceGroupMap::iterator, bool> matgrpi; | 
|---|
| 398 |                 matgrpi = mMatFaceGroupMap.insert( | 
|---|
| 399 |                     MaterialFaceGroupMap::value_type(pMat.getPointer(), std::vector<StaticFaceGroup*>()) | 
|---|
| 400 |                     ); | 
|---|
| 401 |                 // Whatever happened, matgrpi.first is map iterator | 
|---|
| 402 |                 // Need to get second part of that to get vector | 
|---|
| 403 |                 matgrpi.first->second.push_back(faceGroup); | 
|---|
| 404 |  | 
|---|
| 405 |                 //if (firstTime) | 
|---|
| 406 |                 //{ | 
|---|
| 407 |                 //    of << "  Emitting faceGroup: index=" << realIndex << ", " << *faceGroup << std::endl; | 
|---|
| 408 |                 //} | 
|---|
| 409 |             } | 
|---|
| 410 |         } | 
|---|
| 411 |  | 
|---|
| 412 |         // Add movables to render queue, provided it hasn't been seen already | 
|---|
| 413 |         const BspNode::IntersectingObjectSet& objects = leaf->getObjects(); | 
|---|
| 414 |         BspNode::IntersectingObjectSet::const_iterator oi, oiend; | 
|---|
| 415 |         oiend = objects.end(); | 
|---|
| 416 |         for (oi = objects.begin(); oi != oiend; ++oi) | 
|---|
| 417 |         { | 
|---|
| 418 |             if (mMovablesForRendering.find(*oi) == mMovablesForRendering.end()) | 
|---|
| 419 |             { | 
|---|
| 420 |                 // It hasn't been seen yet | 
|---|
| 421 |                 MovableObject *mov = const_cast<MovableObject*>(*oi); // hacky | 
|---|
| 422 |                 if (mov->isVisible() &&  | 
|---|
| 423 |                     (!onlyShadowCasters || mov->getCastShadows()) &&  | 
|---|
| 424 |                                         cam->isVisible(mov->getWorldBoundingBox())) | 
|---|
| 425 |                 { | 
|---|
| 426 |                     mov->_notifyCurrentCamera(cam); | 
|---|
| 427 |                     mov->_updateRenderQueue(getRenderQueue()); | 
|---|
| 428 |                     // Check if the bounding box should be shown. | 
|---|
| 429 |                     SceneNode* sn = static_cast<SceneNode*>(mov->getParentNode()); | 
|---|
| 430 |                     if (sn->getShowBoundingBox() || mShowBoundingBoxes) | 
|---|
| 431 |                     { | 
|---|
| 432 |                         sn->_addBoundingBoxToQueue(getRenderQueue()); | 
|---|
| 433 |                     } | 
|---|
| 434 |                     mMovablesForRendering.insert(*oi); | 
|---|
| 435 |  | 
|---|
| 436 |                                         // update visible boundaries aab | 
|---|
| 437 |                                         if (visibleBounds) | 
|---|
| 438 |                                         { | 
|---|
| 439 |                                                 visibleBounds->merge((*oi)->getWorldBoundingBox(true),  | 
|---|
| 440 |                                                         (*oi)->getWorldBoundingSphere(true), cam); | 
|---|
| 441 |                                         } | 
|---|
| 442 |                 } | 
|---|
| 443 |  | 
|---|
| 444 |             } | 
|---|
| 445 |         } | 
|---|
| 446 |  | 
|---|
| 447 |  | 
|---|
| 448 |     } | 
|---|
| 449 |     //----------------------------------------------------------------------- | 
|---|
| 450 |     unsigned int BspSceneManager::cacheGeometry(unsigned int* pIndexes,  | 
|---|
| 451 |         const StaticFaceGroup* faceGroup) | 
|---|
| 452 |     { | 
|---|
| 453 |         // Skip sky always | 
|---|
| 454 |         if (faceGroup->isSky) | 
|---|
| 455 |             return 0; | 
|---|
| 456 |  | 
|---|
| 457 |         size_t idxStart, numIdx, vertexStart; | 
|---|
| 458 |  | 
|---|
| 459 |         if (faceGroup->fType == FGT_FACE_LIST) | 
|---|
| 460 |         { | 
|---|
| 461 |             idxStart = faceGroup->elementStart; | 
|---|
| 462 |             numIdx = faceGroup->numElements; | 
|---|
| 463 |             vertexStart = faceGroup->vertexStart; | 
|---|
| 464 |         } | 
|---|
| 465 |         else if (faceGroup->fType == FGT_PATCH) | 
|---|
| 466 |         { | 
|---|
| 467 |  | 
|---|
| 468 |             idxStart = faceGroup->patchSurf->getIndexOffset(); | 
|---|
| 469 |             numIdx = faceGroup->patchSurf->getCurrentIndexCount(); | 
|---|
| 470 |             vertexStart = faceGroup->patchSurf->getVertexOffset(); | 
|---|
| 471 |         } | 
|---|
| 472 |                 else | 
|---|
| 473 |                 { | 
|---|
| 474 |                         // Unsupported face type | 
|---|
| 475 |                         return 0; | 
|---|
| 476 |                 } | 
|---|
| 477 |  | 
|---|
| 478 |  | 
|---|
| 479 |         // Copy index data | 
|---|
| 480 |         unsigned int* pSrc = static_cast<unsigned int*>( | 
|---|
| 481 |             mLevel->mIndexes->lock( | 
|---|
| 482 |                 idxStart * sizeof(unsigned int), | 
|---|
| 483 |                 numIdx * sizeof(unsigned int),  | 
|---|
| 484 |                 HardwareBuffer::HBL_READ_ONLY)); | 
|---|
| 485 |         // Offset the indexes here | 
|---|
| 486 |         // we have to do this now rather than up-front because the  | 
|---|
| 487 |         // indexes are sometimes reused to address different vertex chunks | 
|---|
| 488 |         for (size_t elem = 0; elem < numIdx; ++elem) | 
|---|
| 489 |         { | 
|---|
| 490 |             *pIndexes++ = *pSrc++ + vertexStart; | 
|---|
| 491 |         } | 
|---|
| 492 |         mLevel->mIndexes->unlock(); | 
|---|
| 493 |  | 
|---|
| 494 |         // return number of elements | 
|---|
| 495 |         return static_cast<unsigned int>(numIdx); | 
|---|
| 496 |  | 
|---|
| 497 |  | 
|---|
| 498 |     } | 
|---|
| 499 |  | 
|---|
| 500 |     //----------------------------------------------------------------------- | 
|---|
| 501 |     void BspSceneManager::freeMemory(void) | 
|---|
| 502 |     { | 
|---|
| 503 |         // no need to delete index buffer, will be handled by shared pointer | 
|---|
| 504 |         delete mRenderOp.indexData; | 
|---|
| 505 |                 mRenderOp.indexData = 0; | 
|---|
| 506 |     } | 
|---|
| 507 |     //----------------------------------------------------------------------- | 
|---|
| 508 |     void BspSceneManager::showNodeBoxes(bool show) | 
|---|
| 509 |     { | 
|---|
| 510 |         mShowNodeAABs = show; | 
|---|
| 511 |     } | 
|---|
| 512 |     //----------------------------------------------------------------------- | 
|---|
| 513 |     void BspSceneManager::addBoundingBox(const AxisAlignedBox& aab, bool visible) | 
|---|
| 514 |     { | 
|---|
| 515 |         /* | 
|---|
| 516 |         unsigned long visibleColour; | 
|---|
| 517 |         unsigned long nonVisibleColour; | 
|---|
| 518 |         Root& r = Root::getSingleton(); | 
|---|
| 519 |  | 
|---|
| 520 |         r.convertColourValue(ColourValue::White, &visibleColour); | 
|---|
| 521 |         r.convertColourValue(ColourValue::Blue, &nonVisibleColour); | 
|---|
| 522 |         if (mShowNodeAABs) | 
|---|
| 523 |         { | 
|---|
| 524 |             // Add set of lines | 
|---|
| 525 |             float* pVertices = (float*)mAABGeometry.pVertices + (mAABGeometry.numVertices*3); | 
|---|
| 526 |             unsigned short* pIndexes = mAABGeometry.pIndexes + mAABGeometry.numIndexes; | 
|---|
| 527 |             unsigned long* pColours = (unsigned long*)mAABGeometry.pDiffuseColour + mAABGeometry.numVertices; | 
|---|
| 528 |  | 
|---|
| 529 |             const Vector3* pCorner = aab.getAllCorners(); | 
|---|
| 530 |  | 
|---|
| 531 |             int i; | 
|---|
| 532 |             for (i = 0; i < 8; ++i) | 
|---|
| 533 |             { | 
|---|
| 534 |                 *pVertices++ = pCorner->x; | 
|---|
| 535 |                 *pVertices++ = pCorner->y; | 
|---|
| 536 |                 *pVertices++ = pCorner->z; | 
|---|
| 537 |                 pCorner++; | 
|---|
| 538 |  | 
|---|
| 539 |                 if (visible) | 
|---|
| 540 |                 { | 
|---|
| 541 |                     *pColours++ = visibleColour; | 
|---|
| 542 |                 } | 
|---|
| 543 |                 else | 
|---|
| 544 |                 { | 
|---|
| 545 |                     *pColours++ = nonVisibleColour; | 
|---|
| 546 |                 } | 
|---|
| 547 |  | 
|---|
| 548 |             } | 
|---|
| 549 |  | 
|---|
| 550 |             *pIndexes++ = 0 + mAABGeometry.numVertices; | 
|---|
| 551 |             *pIndexes++ = 1 + mAABGeometry.numVertices; | 
|---|
| 552 |             *pIndexes++ = 1 + mAABGeometry.numVertices; | 
|---|
| 553 |             *pIndexes++ = 2 + mAABGeometry.numVertices; | 
|---|
| 554 |             *pIndexes++ = 2 + mAABGeometry.numVertices; | 
|---|
| 555 |             *pIndexes++ = 3 + mAABGeometry.numVertices; | 
|---|
| 556 |             *pIndexes++ = 3 + mAABGeometry.numVertices; | 
|---|
| 557 |             *pIndexes++ = 1 + mAABGeometry.numVertices; | 
|---|
| 558 |             *pIndexes++ = 4 + mAABGeometry.numVertices; | 
|---|
| 559 |             *pIndexes++ = 5 + mAABGeometry.numVertices; | 
|---|
| 560 |             *pIndexes++ = 5 + mAABGeometry.numVertices; | 
|---|
| 561 |             *pIndexes++ = 6 + mAABGeometry.numVertices; | 
|---|
| 562 |             *pIndexes++ = 6 + mAABGeometry.numVertices; | 
|---|
| 563 |             *pIndexes++ = 7 + mAABGeometry.numVertices; | 
|---|
| 564 |             *pIndexes++ = 7 + mAABGeometry.numVertices; | 
|---|
| 565 |             *pIndexes++ = 4 + mAABGeometry.numVertices; | 
|---|
| 566 |             *pIndexes++ = 1 + mAABGeometry.numVertices; | 
|---|
| 567 |             *pIndexes++ = 5 + mAABGeometry.numVertices; | 
|---|
| 568 |             *pIndexes++ = 2 + mAABGeometry.numVertices; | 
|---|
| 569 |             *pIndexes++ = 4 + mAABGeometry.numVertices; | 
|---|
| 570 |             *pIndexes++ = 0 + mAABGeometry.numVertices; | 
|---|
| 571 |             *pIndexes++ = 6 + mAABGeometry.numVertices; | 
|---|
| 572 |             *pIndexes++ = 3 + mAABGeometry.numVertices; | 
|---|
| 573 |             *pIndexes++ = 7 + mAABGeometry.numVertices; | 
|---|
| 574 |  | 
|---|
| 575 |  | 
|---|
| 576 |             mAABGeometry.numVertices += 8; | 
|---|
| 577 |             mAABGeometry.numIndexes += 24; | 
|---|
| 578 |  | 
|---|
| 579 |  | 
|---|
| 580 |         } | 
|---|
| 581 |         */ | 
|---|
| 582 |  | 
|---|
| 583 |     } | 
|---|
| 584 |     //----------------------------------------------------------------------- | 
|---|
| 585 |     ViewPoint BspSceneManager::getSuggestedViewpoint(bool random) | 
|---|
| 586 |     { | 
|---|
| 587 |         if (mLevel.isNull() || mLevel->mPlayerStarts.size() == 0) | 
|---|
| 588 |         { | 
|---|
| 589 |             // No level, use default | 
|---|
| 590 |             return SceneManager::getSuggestedViewpoint(random); | 
|---|
| 591 |         } | 
|---|
| 592 |         else | 
|---|
| 593 |         { | 
|---|
| 594 |             if (random) | 
|---|
| 595 |             { | 
|---|
| 596 |                 size_t idx = (size_t)( Math::UnitRandom() * mLevel->mPlayerStarts.size() ); | 
|---|
| 597 |                 return mLevel->mPlayerStarts[idx]; | 
|---|
| 598 |             } | 
|---|
| 599 |             else | 
|---|
| 600 |             { | 
|---|
| 601 |                 return mLevel->mPlayerStarts[0]; | 
|---|
| 602 |             } | 
|---|
| 603 |  | 
|---|
| 604 |  | 
|---|
| 605 |         } | 
|---|
| 606 |  | 
|---|
| 607 |     } | 
|---|
| 608 |     //----------------------------------------------------------------------- | 
|---|
| 609 |     SceneNode * BspSceneManager::createSceneNode( void ) | 
|---|
| 610 |     { | 
|---|
| 611 |         BspSceneNode * sn = new BspSceneNode( this ); | 
|---|
| 612 |         mSceneNodes[ sn->getName() ] = sn; | 
|---|
| 613 |         return sn; | 
|---|
| 614 |     } | 
|---|
| 615 |     //----------------------------------------------------------------------- | 
|---|
| 616 |     SceneNode * BspSceneManager::createSceneNode( const String &name ) | 
|---|
| 617 |     { | 
|---|
| 618 |         BspSceneNode * sn = new BspSceneNode( this, name ); | 
|---|
| 619 |         mSceneNodes[ sn->getName() ] = sn; | 
|---|
| 620 |         return sn; | 
|---|
| 621 |     } | 
|---|
| 622 |     //----------------------------------------------------------------------- | 
|---|
| 623 |     void BspSceneManager::_notifyObjectMoved(const MovableObject* mov,  | 
|---|
| 624 |         const Vector3& pos) | 
|---|
| 625 |     { | 
|---|
| 626 |                 if (!mLevel.isNull()) | 
|---|
| 627 |                 { | 
|---|
| 628 |                         mLevel->_notifyObjectMoved(mov, pos); | 
|---|
| 629 |                 } | 
|---|
| 630 |     } | 
|---|
| 631 |     //----------------------------------------------------------------------- | 
|---|
| 632 |         void BspSceneManager::_notifyObjectDetached(const MovableObject* mov) | 
|---|
| 633 |         { | 
|---|
| 634 |                 if (!mLevel.isNull()) | 
|---|
| 635 |                 { | 
|---|
| 636 |                         mLevel->_notifyObjectDetached(mov); | 
|---|
| 637 |                 } | 
|---|
| 638 |         } | 
|---|
| 639 |         //----------------------------------------------------------------------- | 
|---|
| 640 |         void BspSceneManager::clearScene(void) | 
|---|
| 641 |         { | 
|---|
| 642 |                 SceneManager::clearScene(); | 
|---|
| 643 |                 freeMemory(); | 
|---|
| 644 |                 // Clear level | 
|---|
| 645 |                 mLevel.setNull(); | 
|---|
| 646 |         } | 
|---|
| 647 |     //----------------------------------------------------------------------- | 
|---|
| 648 |     /* | 
|---|
| 649 |     AxisAlignedBoxSceneQuery* BspSceneManager:: | 
|---|
| 650 |     createAABBQuery(const AxisAlignedBox& box, unsigned long mask) | 
|---|
| 651 |     { | 
|---|
| 652 |         // TODO | 
|---|
| 653 |         return NULL; | 
|---|
| 654 |     } | 
|---|
| 655 |     //----------------------------------------------------------------------- | 
|---|
| 656 |     SphereSceneQuery* BspSceneManager:: | 
|---|
| 657 |     createSphereQuery(const Sphere& sphere, unsigned long mask) | 
|---|
| 658 |     { | 
|---|
| 659 |         // TODO | 
|---|
| 660 |         return NULL; | 
|---|
| 661 |     } | 
|---|
| 662 |     */ | 
|---|
| 663 |     //----------------------------------------------------------------------- | 
|---|
| 664 |     RaySceneQuery* BspSceneManager:: | 
|---|
| 665 |     createRayQuery(const Ray& ray, unsigned long mask) | 
|---|
| 666 |     { | 
|---|
| 667 |         BspRaySceneQuery* q = new BspRaySceneQuery(this); | 
|---|
| 668 |         q->setRay(ray); | 
|---|
| 669 |         q->setQueryMask(mask); | 
|---|
| 670 |         return q; | 
|---|
| 671 |     } | 
|---|
| 672 |     //----------------------------------------------------------------------- | 
|---|
| 673 |     IntersectionSceneQuery* BspSceneManager:: | 
|---|
| 674 |     createIntersectionQuery(unsigned long mask) | 
|---|
| 675 |     { | 
|---|
| 676 |         BspIntersectionSceneQuery* q = new BspIntersectionSceneQuery(this); | 
|---|
| 677 |         q->setQueryMask(mask); | 
|---|
| 678 |         return q; | 
|---|
| 679 |     } | 
|---|
| 680 |     //----------------------------------------------------------------------- | 
|---|
| 681 |     //----------------------------------------------------------------------- | 
|---|
| 682 |     BspIntersectionSceneQuery::BspIntersectionSceneQuery(SceneManager* creator)  | 
|---|
| 683 |         : DefaultIntersectionSceneQuery(creator) | 
|---|
| 684 |     { | 
|---|
| 685 |         // Add bounds fragment type | 
|---|
| 686 |         mSupportedWorldFragments.insert(SceneQuery::WFT_PLANE_BOUNDED_REGION); | 
|---|
| 687 |          | 
|---|
| 688 |     } | 
|---|
| 689 |     void BspIntersectionSceneQuery::execute(IntersectionSceneQueryListener* listener) | 
|---|
| 690 |     { | 
|---|
| 691 |         /* | 
|---|
| 692 |         Go through each leaf node in BspLevel and check movables against each other and world | 
|---|
| 693 |         Issue: some movable-movable intersections could be reported twice if 2 movables | 
|---|
| 694 |         overlap 2 leaves? | 
|---|
| 695 |         */ | 
|---|
| 696 |         const BspLevelPtr& lvl = ((BspSceneManager*)mParentSceneMgr)->getLevel(); | 
|---|
| 697 |                 if (lvl.isNull()) return; | 
|---|
| 698 |  | 
|---|
| 699 |         BspNode* leaf = lvl->getLeafStart(); | 
|---|
| 700 |         int numLeaves = lvl->getNumLeaves(); | 
|---|
| 701 |          | 
|---|
| 702 |         while (numLeaves--) | 
|---|
| 703 |         { | 
|---|
| 704 |             const BspNode::IntersectingObjectSet& objects = leaf->getObjects(); | 
|---|
| 705 |             int numObjects = (int)objects.size(); | 
|---|
| 706 |  | 
|---|
| 707 |             BspNode::IntersectingObjectSet::const_iterator a, b, theEnd; | 
|---|
| 708 |             theEnd = objects.end(); | 
|---|
| 709 |             a = objects.begin(); | 
|---|
| 710 |             for (int oi = 0; oi < numObjects; ++oi, ++a) | 
|---|
| 711 |             { | 
|---|
| 712 |                 const MovableObject* aObj = *a; | 
|---|
| 713 |                 // Skip this object if collision not enabled | 
|---|
| 714 |                 if (!(aObj->getQueryFlags() & mQueryMask) || | 
|---|
| 715 |                                         !(aObj->getTypeFlags() & mQueryTypeMask) || | 
|---|
| 716 |                                         !aObj->isInScene()) | 
|---|
| 717 |                     continue; | 
|---|
| 718 |  | 
|---|
| 719 |                 if (oi < (numObjects-1)) | 
|---|
| 720 |                 { | 
|---|
| 721 |                     // Check object against others in this node | 
|---|
| 722 |                     b = a; | 
|---|
| 723 |                     for (++b; b != theEnd; ++b) | 
|---|
| 724 |                     { | 
|---|
| 725 |                         const MovableObject* bObj = *b; | 
|---|
| 726 |                         // Apply mask to b (both must pass) | 
|---|
| 727 |                         if ((bObj->getQueryFlags() & mQueryMask) &&  | 
|---|
| 728 |                                                         (bObj->getTypeFlags() & mQueryTypeMask) &&  | 
|---|
| 729 |                                                         bObj->isInScene()) | 
|---|
| 730 |                         { | 
|---|
| 731 |                             const AxisAlignedBox& box1 = aObj->getWorldBoundingBox(); | 
|---|
| 732 |                             const AxisAlignedBox& box2 = bObj->getWorldBoundingBox(); | 
|---|
| 733 |  | 
|---|
| 734 |                             if (box1.intersects(box2)) | 
|---|
| 735 |                             { | 
|---|
| 736 |                                 if (!listener->queryResult(const_cast<MovableObject*>(aObj),  | 
|---|
| 737 |                                     const_cast<MovableObject*>(bObj))) | 
|---|
| 738 |                                                                         return;  | 
|---|
| 739 |                             } | 
|---|
| 740 |                         } | 
|---|
| 741 |                     } | 
|---|
| 742 |                 } | 
|---|
| 743 |                 // Check object against brushes | 
|---|
| 744 |                 if (mQueryTypeMask & SceneManager::WORLD_GEOMETRY_TYPE_MASK) | 
|---|
| 745 |                 { | 
|---|
| 746 |                     const BspNode::NodeBrushList& brushes = leaf->getSolidBrushes(); | 
|---|
| 747 |                     BspNode::NodeBrushList::const_iterator bi, biend; | 
|---|
| 748 |                     biend = brushes.end(); | 
|---|
| 749 |                     Real radius = aObj->getBoundingRadius(); | 
|---|
| 750 |                     const Vector3& pos = aObj->getParentNode()->_getDerivedPosition(); | 
|---|
| 751 |  | 
|---|
| 752 |                     for (bi = brushes.begin(); bi != biend; ++bi) | 
|---|
| 753 |                     { | 
|---|
| 754 |                         std::list<Plane>::const_iterator planeit, planeitend; | 
|---|
| 755 |                         planeitend = (*bi)->planes.end(); | 
|---|
| 756 |                         bool brushIntersect = true; // Assume intersecting for now | 
|---|
| 757 |  | 
|---|
| 758 |                         for (planeit = (*bi)->planes.begin(); planeit != planeitend; ++planeit) | 
|---|
| 759 |                         { | 
|---|
| 760 |                             Real dist = planeit->getDistance(pos); | 
|---|
| 761 |                             if (dist > radius) | 
|---|
| 762 |                             { | 
|---|
| 763 |                                 // Definitely excluded | 
|---|
| 764 |                                 brushIntersect = false; | 
|---|
| 765 |                                 break; | 
|---|
| 766 |                             } | 
|---|
| 767 |                         } | 
|---|
| 768 |                         if (brushIntersect) | 
|---|
| 769 |                         { | 
|---|
| 770 |                             // report this brush as it's WorldFragment | 
|---|
| 771 |                             assert((*bi)->fragment.fragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION); | 
|---|
| 772 |                             if (!listener->queryResult(const_cast<MovableObject*>(aObj),  | 
|---|
| 773 |                                     const_cast<WorldFragment*>(&((*bi)->fragment)))) | 
|---|
| 774 |                                                                 return;  | 
|---|
| 775 |                         } | 
|---|
| 776 |  | 
|---|
| 777 |                     } | 
|---|
| 778 |                 } | 
|---|
| 779 |  | 
|---|
| 780 |  | 
|---|
| 781 |             } | 
|---|
| 782 |  | 
|---|
| 783 |             ++leaf; | 
|---|
| 784 |         } | 
|---|
| 785 |  | 
|---|
| 786 |  | 
|---|
| 787 |  | 
|---|
| 788 |     } | 
|---|
| 789 |     //----------------------------------------------------------------------- | 
|---|
| 790 |     //----------------------------------------------------------------------- | 
|---|
| 791 |     BspRaySceneQuery::BspRaySceneQuery(SceneManager* creator) | 
|---|
| 792 |         :DefaultRaySceneQuery(creator) | 
|---|
| 793 |     { | 
|---|
| 794 |         // Add supported fragment types | 
|---|
| 795 |         mSupportedWorldFragments.insert(SceneQuery::WFT_SINGLE_INTERSECTION); | 
|---|
| 796 |         mSupportedWorldFragments.insert(SceneQuery::WFT_PLANE_BOUNDED_REGION); | 
|---|
| 797 |     } | 
|---|
| 798 |     //----------------------------------------------------------------------- | 
|---|
| 799 |     void BspRaySceneQuery::execute(RaySceneQueryListener* listener) | 
|---|
| 800 |     { | 
|---|
| 801 |         clearTemporaries(); | 
|---|
| 802 |                 BspLevelPtr lvl = static_cast<BspSceneManager*>(mParentSceneMgr)->getLevel(); | 
|---|
| 803 |                 if (!lvl.isNull()) | 
|---|
| 804 |                 { | 
|---|
| 805 |                         processNode( | 
|---|
| 806 |                                 lvl->getRootNode(),  | 
|---|
| 807 |                                 mRay, listener); | 
|---|
| 808 |                 } | 
|---|
| 809 |     } | 
|---|
| 810 |     //----------------------------------------------------------------------- | 
|---|
| 811 |     BspRaySceneQuery::~BspRaySceneQuery() | 
|---|
| 812 |     { | 
|---|
| 813 |         clearTemporaries(); | 
|---|
| 814 |     } | 
|---|
| 815 |     //----------------------------------------------------------------------- | 
|---|
| 816 |     void BspRaySceneQuery::clearTemporaries(void) | 
|---|
| 817 |     { | 
|---|
| 818 |         mObjsThisQuery.clear(); | 
|---|
| 819 |         std::vector<WorldFragment*>::iterator i; | 
|---|
| 820 |         for (i = mSingleIntersections.begin(); i != mSingleIntersections.end(); ++i) | 
|---|
| 821 |         { | 
|---|
| 822 |             delete *i; | 
|---|
| 823 |         } | 
|---|
| 824 |         mSingleIntersections.clear(); | 
|---|
| 825 |     } | 
|---|
| 826 |     //----------------------------------------------------------------------- | 
|---|
| 827 |     bool BspRaySceneQuery::processNode(const BspNode* node, const Ray& tracingRay,  | 
|---|
| 828 |         RaySceneQueryListener* listener, Real maxDistance, Real traceDistance) | 
|---|
| 829 |     { | 
|---|
| 830 |         if (node->isLeaf()) | 
|---|
| 831 |         { | 
|---|
| 832 |             return processLeaf(node, tracingRay, listener, maxDistance, traceDistance); | 
|---|
| 833 |         } | 
|---|
| 834 |  | 
|---|
| 835 |         bool res = true; | 
|---|
| 836 |         std::pair<bool, Real> result = tracingRay.intersects(node->getSplitPlane()); | 
|---|
| 837 |         if (result.first && result.second < maxDistance) | 
|---|
| 838 |         { | 
|---|
| 839 |             // Crosses the split plane, need to perform 2 queries | 
|---|
| 840 |             // Calculate split point ray | 
|---|
| 841 |             Vector3 splitPoint = tracingRay.getOrigin()  | 
|---|
| 842 |                 + tracingRay.getDirection() * result.second; | 
|---|
| 843 |             Ray splitRay(splitPoint, tracingRay.getDirection()); | 
|---|
| 844 |  | 
|---|
| 845 |             if (node->getSide(tracingRay.getOrigin()) == Plane::NEGATIVE_SIDE) | 
|---|
| 846 |             { | 
|---|
| 847 |                 // Intersects from -ve side, so do back then front | 
|---|
| 848 |                 res = processNode( | 
|---|
| 849 |                     node->getBack(), tracingRay, listener, result.second, traceDistance); | 
|---|
| 850 |                 if (!res) return res; | 
|---|
| 851 |                  | 
|---|
| 852 |                 res = processNode( | 
|---|
| 853 |                     node->getFront(), splitRay, listener,  | 
|---|
| 854 |                     maxDistance - result.second,  | 
|---|
| 855 |                     traceDistance + result.second); | 
|---|
| 856 |             } | 
|---|
| 857 |             else | 
|---|
| 858 |             { | 
|---|
| 859 |                 // Intersects from +ve side, so do front then back | 
|---|
| 860 |                 res = processNode(node->getFront(), tracingRay, listener,  | 
|---|
| 861 |                     result.second, traceDistance); | 
|---|
| 862 |                 if (!res) return res; | 
|---|
| 863 |                 res = processNode(node->getBack(), splitRay, listener, | 
|---|
| 864 |                     maxDistance - result.second,  | 
|---|
| 865 |                     traceDistance + result.second); | 
|---|
| 866 |             } | 
|---|
| 867 |         } | 
|---|
| 868 |         else | 
|---|
| 869 |         { | 
|---|
| 870 |             // Does not cross the splitting plane, just cascade down one side | 
|---|
| 871 |             res = processNode(node->getNextNode(tracingRay.getOrigin()), | 
|---|
| 872 |                 tracingRay, listener, maxDistance, traceDistance); | 
|---|
| 873 |         } | 
|---|
| 874 |  | 
|---|
| 875 |         return res; | 
|---|
| 876 |     } | 
|---|
| 877 |     //----------------------------------------------------------------------- | 
|---|
| 878 |     bool BspRaySceneQuery::processLeaf(const BspNode* leaf, const Ray& tracingRay,  | 
|---|
| 879 |         RaySceneQueryListener* listener, Real maxDistance, Real traceDistance) | 
|---|
| 880 |     { | 
|---|
| 881 |         const BspNode::IntersectingObjectSet& objects = leaf->getObjects(); | 
|---|
| 882 |  | 
|---|
| 883 |         BspNode::IntersectingObjectSet::const_iterator i, iend; | 
|---|
| 884 |         iend = objects.end(); | 
|---|
| 885 |         //Check ray against objects | 
|---|
| 886 |         for(i = objects.begin(); i != iend; ++i) | 
|---|
| 887 |         { | 
|---|
| 888 |             // cast away constness, constness of node is nothing to do with objects | 
|---|
| 889 |             MovableObject* obj = const_cast<MovableObject*>(*i); | 
|---|
| 890 |             // Skip this object if not enabled | 
|---|
| 891 |             if(!(obj->getQueryFlags() & mQueryMask) || | 
|---|
| 892 |                                 !((obj->getTypeFlags() & mQueryTypeMask))) | 
|---|
| 893 |                 continue; | 
|---|
| 894 |  | 
|---|
| 895 |             // check we haven't reported this one already | 
|---|
| 896 |             // (objects can be intersecting more than one node) | 
|---|
| 897 |             if (mObjsThisQuery.find(obj) != mObjsThisQuery.end()) | 
|---|
| 898 |                 continue; | 
|---|
| 899 |  | 
|---|
| 900 |             //Test object as bounding box | 
|---|
| 901 |             std::pair<bool, Real> result =  | 
|---|
| 902 |                 tracingRay.intersects(obj->getWorldBoundingBox()); | 
|---|
| 903 |             // if the result came back positive and intersection point is inside | 
|---|
| 904 |             // the node, fire the event handler | 
|---|
| 905 |             if(result.first && result.second <= maxDistance) | 
|---|
| 906 |             { | 
|---|
| 907 |                 if (!listener->queryResult(obj, result.second + traceDistance)) | 
|---|
| 908 |                                         return false; | 
|---|
| 909 |             } | 
|---|
| 910 |         } | 
|---|
| 911 |  | 
|---|
| 912 |  | 
|---|
| 913 |         // Check ray against brushes | 
|---|
| 914 |         if (mQueryTypeMask & SceneManager::WORLD_GEOMETRY_TYPE_MASK) | 
|---|
| 915 |         { | 
|---|
| 916 |             const BspNode::NodeBrushList& brushList = leaf->getSolidBrushes(); | 
|---|
| 917 |             BspNode::NodeBrushList::const_iterator bi, biend; | 
|---|
| 918 |             biend = brushList.end(); | 
|---|
| 919 |             bool intersectedBrush = false; | 
|---|
| 920 |             for (bi = brushList.begin(); bi != biend; ++bi) | 
|---|
| 921 |             { | 
|---|
| 922 |                 BspNode::Brush* brush = *bi; | 
|---|
| 923 |                  | 
|---|
| 924 |  | 
|---|
| 925 |                 std::pair<bool, Real> result = Math::intersects(tracingRay, brush->planes, true); | 
|---|
| 926 |                 // if the result came back positive and intersection point is inside | 
|---|
| 927 |                 // the node, check if this brush is closer | 
|---|
| 928 |                 if(result.first && result.second <= maxDistance) | 
|---|
| 929 |                 { | 
|---|
| 930 |                     intersectedBrush = true; | 
|---|
| 931 |                     if(mWorldFragmentType == SceneQuery::WFT_SINGLE_INTERSECTION) | 
|---|
| 932 |                     { | 
|---|
| 933 |                         // We're interested in a single intersection | 
|---|
| 934 |                         // Have to create these  | 
|---|
| 935 |                         SceneQuery::WorldFragment* wf = new SceneQuery::WorldFragment(); | 
|---|
| 936 |                         wf->fragmentType = SceneQuery::WFT_SINGLE_INTERSECTION; | 
|---|
| 937 |                         wf->singleIntersection = tracingRay.getPoint(result.second); | 
|---|
| 938 |                         // save this so we can clean up later | 
|---|
| 939 |                         mSingleIntersections.push_back(wf); | 
|---|
| 940 |                         if (!listener->queryResult(wf, result.second + traceDistance)) | 
|---|
| 941 |                                                         return false; | 
|---|
| 942 |                     } | 
|---|
| 943 |                     else if (mWorldFragmentType ==  SceneQuery::WFT_PLANE_BOUNDED_REGION) | 
|---|
| 944 |                     { | 
|---|
| 945 |                         // We want the whole bounded volume | 
|---|
| 946 |                         assert((*bi)->fragment.fragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION); | 
|---|
| 947 |                         if (!listener->queryResult(const_cast<WorldFragment*>(&(brush->fragment)),  | 
|---|
| 948 |                             result.second + traceDistance)) | 
|---|
| 949 |                                                         return false;  | 
|---|
| 950 |  | 
|---|
| 951 |                     } | 
|---|
| 952 |                 } | 
|---|
| 953 |             } | 
|---|
| 954 |             if (intersectedBrush) | 
|---|
| 955 |             { | 
|---|
| 956 |                 return false; // stop here | 
|---|
| 957 |             } | 
|---|
| 958 |         } | 
|---|
| 959 |  | 
|---|
| 960 |         return true; | 
|---|
| 961 |  | 
|---|
| 962 |     }  | 
|---|
| 963 |     //----------------------------------------------------------------------- | 
|---|
| 964 |         //----------------------------------------------------------------------- | 
|---|
| 965 |         const String BspSceneManagerFactory::FACTORY_TYPE_NAME = "BspSceneManager"; | 
|---|
| 966 |         //----------------------------------------------------------------------- | 
|---|
| 967 |         void BspSceneManagerFactory::initMetaData(void) const | 
|---|
| 968 |         { | 
|---|
| 969 |                 mMetaData.typeName = FACTORY_TYPE_NAME; | 
|---|
| 970 |                 mMetaData.description = "Scene manager for loading Quake3 .bsp files."; | 
|---|
| 971 |                 mMetaData.sceneTypeMask = ST_INTERIOR; | 
|---|
| 972 |                 mMetaData.worldGeometrySupported = true; | 
|---|
| 973 |         } | 
|---|
| 974 |         //----------------------------------------------------------------------- | 
|---|
| 975 |         SceneManager* BspSceneManagerFactory::createInstance( | 
|---|
| 976 |                 const String& instanceName) | 
|---|
| 977 |         { | 
|---|
| 978 |                 return new BspSceneManager(instanceName); | 
|---|
| 979 |         } | 
|---|
| 980 |         //----------------------------------------------------------------------- | 
|---|
| 981 |         void BspSceneManagerFactory::destroyInstance(SceneManager* instance) | 
|---|
| 982 |         { | 
|---|
| 983 |                 delete instance; | 
|---|
| 984 |         } | 
|---|
| 985 |  | 
|---|
| 986 | } | 
|---|
| 987 |  | 
|---|