| [1] | 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 | |
|---|