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-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 #include "OgreStaticGeometry.h" 30 #include "OgreEntity.h" 31 #include "OgreSubEntity.h" 32 #include "OgreSceneNode.h" 33 #include "OgreException.h" 34 #include "OgreMesh.h" 35 #include "OgreSubMesh.h" 36 #include "OgreLogManager.h" 37 #include "OgreSceneManager.h" 38 #include "OgreCamera.h" 39 #include "OgreMaterialManager.h" 40 #include "OgreRoot.h" 41 #include "OgreRenderSystem.h" 42 #include "OgreEdgeListBuilder.h" 43 44 namespace Ogre { 45 46 #define REGION_RANGE 1024 47 #define REGION_HALF_RANGE 512 48 #define REGION_MAX_INDEX 511 49 #define REGION_MIN_INDEX -512 50 51 //-------------------------------------------------------------------------- StaticGeometry(SceneManager * owner,const String & name)52 StaticGeometry::StaticGeometry(SceneManager* owner, const String& name): 53 mOwner(owner), 54 mName(name), 55 mBuilt(false), 56 mUpperDistance(0.0f), 57 mSquaredUpperDistance(0.0f), 58 mCastShadows(false), 59 mRegionDimensions(Vector3(1000,1000,1000)), 60 mHalfRegionDimensions(Vector3(500,500,500)), 61 mOrigin(Vector3(0,0,0)), 62 mVisible(true), 63 mRenderQueueID(RENDER_QUEUE_MAIN), 64 mRenderQueueIDSet(false), 65 mVisibilityFlags(Ogre::MovableObject::getDefaultVisibilityFlags()) 66 { 67 } 68 //-------------------------------------------------------------------------- ~StaticGeometry()69 StaticGeometry::~StaticGeometry() 70 { 71 reset(); 72 } 73 //-------------------------------------------------------------------------- getRegion(const AxisAlignedBox & bounds,bool autoCreate)74 StaticGeometry::Region* StaticGeometry::getRegion(const AxisAlignedBox& bounds, 75 bool autoCreate) 76 { 77 if (bounds.isNull()) 78 return 0; 79 80 // Get the region which has the largest overlapping volume 81 const Vector3 min = bounds.getMinimum(); 82 const Vector3 max = bounds.getMaximum(); 83 84 // Get the min and max region indexes 85 ushort minx, miny, minz; 86 ushort maxx, maxy, maxz; 87 getRegionIndexes(min, minx, miny, minz); 88 getRegionIndexes(max, maxx, maxy, maxz); 89 Real maxVolume = 0.0f; 90 ushort finalx = 0, finaly = 0, finalz = 0; 91 for (ushort x = minx; x <= maxx; ++x) 92 { 93 for (ushort y = miny; y <= maxy; ++y) 94 { 95 for (ushort z = minz; z <= maxz; ++z) 96 { 97 Real vol = getVolumeIntersection(bounds, x, y, z); 98 if (vol > maxVolume) 99 { 100 maxVolume = vol; 101 finalx = x; 102 finaly = y; 103 finalz = z; 104 } 105 106 } 107 } 108 } 109 110 assert(maxVolume > 0.0f && 111 "Static geometry: Problem determining closest volume match!"); 112 113 return getRegion(finalx, finaly, finalz, autoCreate); 114 115 } 116 //-------------------------------------------------------------------------- getVolumeIntersection(const AxisAlignedBox & box,ushort x,ushort y,ushort z)117 Real StaticGeometry::getVolumeIntersection(const AxisAlignedBox& box, 118 ushort x, ushort y, ushort z) 119 { 120 // Get bounds of indexed region 121 AxisAlignedBox regionBounds = getRegionBounds(x, y, z); 122 AxisAlignedBox intersectBox = regionBounds.intersection(box); 123 // return a 'volume' which ignores zero dimensions 124 // since we only use this for relative comparisons of the same bounds 125 // this will still be internally consistent 126 Vector3 boxdiff = box.getMaximum() - box.getMinimum(); 127 Vector3 intersectDiff = intersectBox.getMaximum() - intersectBox.getMinimum(); 128 129 return (boxdiff.x == 0 ? 1 : intersectDiff.x) * 130 (boxdiff.y == 0 ? 1 : intersectDiff.y) * 131 (boxdiff.z == 0 ? 1 : intersectDiff.z); 132 133 } 134 //-------------------------------------------------------------------------- getRegionBounds(ushort x,ushort y,ushort z)135 AxisAlignedBox StaticGeometry::getRegionBounds(ushort x, ushort y, ushort z) 136 { 137 Vector3 min( 138 ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x, 139 ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y, 140 ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z 141 ); 142 Vector3 max = min + mRegionDimensions; 143 return AxisAlignedBox(min, max); 144 } 145 //-------------------------------------------------------------------------- getRegionCentre(ushort x,ushort y,ushort z)146 Vector3 StaticGeometry::getRegionCentre(ushort x, ushort y, ushort z) 147 { 148 return Vector3( 149 ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x 150 + mHalfRegionDimensions.x, 151 ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y 152 + mHalfRegionDimensions.y, 153 ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z 154 + mHalfRegionDimensions.z 155 ); 156 } 157 //-------------------------------------------------------------------------- getRegion(ushort x,ushort y,ushort z,bool autoCreate)158 StaticGeometry::Region* StaticGeometry::getRegion( 159 ushort x, ushort y, ushort z, bool autoCreate) 160 { 161 uint32 index = packIndex(x, y, z); 162 Region* ret = getRegion(index); 163 if (!ret && autoCreate) 164 { 165 // Make a name 166 StringUtil::StrStreamType str; 167 str << mName << ":" << index; 168 // Calculate the region centre 169 Vector3 centre = getRegionCentre(x, y, z); 170 ret = OGRE_NEW Region(this, str.str(), mOwner, index, centre); 171 mOwner->injectMovableObject(ret); 172 ret->setVisible(mVisible); 173 ret->setCastShadows(mCastShadows); 174 if (mRenderQueueIDSet) 175 { 176 ret->setRenderQueueGroup(mRenderQueueID); 177 } 178 mRegionMap[index] = ret; 179 } 180 return ret; 181 } 182 //-------------------------------------------------------------------------- getRegion(uint32 index)183 StaticGeometry::Region* StaticGeometry::getRegion(uint32 index) 184 { 185 RegionMap::iterator i = mRegionMap.find(index); 186 if (i != mRegionMap.end()) 187 { 188 return i->second; 189 } 190 else 191 { 192 return 0; 193 } 194 195 } 196 //-------------------------------------------------------------------------- getRegionIndexes(const Vector3 & point,ushort & x,ushort & y,ushort & z)197 void StaticGeometry::getRegionIndexes(const Vector3& point, 198 ushort& x, ushort& y, ushort& z) 199 { 200 // Scale the point into multiples of region and adjust for origin 201 Vector3 scaledPoint = (point - mOrigin) / mRegionDimensions; 202 203 // Round down to 'bottom left' point which represents the cell index 204 int ix = Math::IFloor(scaledPoint.x); 205 int iy = Math::IFloor(scaledPoint.y); 206 int iz = Math::IFloor(scaledPoint.z); 207 208 // Check bounds 209 if (ix < REGION_MIN_INDEX || ix > REGION_MAX_INDEX 210 || iy < REGION_MIN_INDEX || iy > REGION_MAX_INDEX 211 || iz < REGION_MIN_INDEX || iz > REGION_MAX_INDEX) 212 { 213 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 214 "Point out of bounds", 215 "StaticGeometry::getRegionIndexes"); 216 } 217 // Adjust for the fact that we use unsigned values for simplicity 218 // (requires less faffing about for negatives give 10-bit packing 219 x = static_cast<ushort>(ix + REGION_HALF_RANGE); 220 y = static_cast<ushort>(iy + REGION_HALF_RANGE); 221 z = static_cast<ushort>(iz + REGION_HALF_RANGE); 222 223 224 } 225 //-------------------------------------------------------------------------- packIndex(ushort x,ushort y,ushort z)226 uint32 StaticGeometry::packIndex(ushort x, ushort y, ushort z) 227 { 228 return x + (y << 10) + (z << 20); 229 } 230 //-------------------------------------------------------------------------- getRegion(const Vector3 & point,bool autoCreate)231 StaticGeometry::Region* StaticGeometry::getRegion(const Vector3& point, 232 bool autoCreate) 233 { 234 ushort x, y, z; 235 getRegionIndexes(point, x, y, z); 236 return getRegion(x, y, z, autoCreate); 237 } 238 //-------------------------------------------------------------------------- calculateBounds(VertexData * vertexData,const Vector3 & position,const Quaternion & orientation,const Vector3 & scale)239 AxisAlignedBox StaticGeometry::calculateBounds(VertexData* vertexData, 240 const Vector3& position, const Quaternion& orientation, 241 const Vector3& scale) 242 { 243 const VertexElement* posElem = 244 vertexData->vertexDeclaration->findElementBySemantic( 245 VES_POSITION); 246 HardwareVertexBufferSharedPtr vbuf = 247 vertexData->vertexBufferBinding->getBuffer(posElem->getSource()); 248 unsigned char* vertex = 249 static_cast<unsigned char*>( 250 vbuf->lock(HardwareBuffer::HBL_READ_ONLY)); 251 float* pFloat; 252 253 Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE; 254 bool first = true; 255 256 for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize()) 257 { 258 posElem->baseVertexPointerToElement(vertex, &pFloat); 259 260 Vector3 pt; 261 262 pt.x = (*pFloat++); 263 pt.y = (*pFloat++); 264 pt.z = (*pFloat++); 265 // Transform to world (scale, rotate, translate) 266 pt = (orientation * (pt * scale)) + position; 267 if (first) 268 { 269 min = max = pt; 270 first = false; 271 } 272 else 273 { 274 min.makeFloor(pt); 275 max.makeCeil(pt); 276 } 277 278 } 279 vbuf->unlock(); 280 return AxisAlignedBox(min, max); 281 } 282 //-------------------------------------------------------------------------- addEntity(Entity * ent,const Vector3 & position,const Quaternion & orientation,const Vector3 & scale)283 void StaticGeometry::addEntity(Entity* ent, const Vector3& position, 284 const Quaternion& orientation, const Vector3& scale) 285 { 286 const MeshPtr& msh = ent->getMesh(); 287 // Validate 288 if (msh->isLodManual()) 289 { 290 LogManager::getSingleton().logMessage( 291 "WARNING (StaticGeometry): Manual LOD is not supported. " 292 "Using only highest LOD level for mesh " + msh->getName(), LML_CRITICAL); 293 } 294 295 AxisAlignedBox sharedWorldBounds; 296 // queue this entities submeshes and choice of material 297 // also build the lists of geometry to be used for the source of lods 298 for (uint i = 0; i < ent->getNumSubEntities(); ++i) 299 { 300 SubEntity* se = ent->getSubEntity(i); 301 QueuedSubMesh* q = OGRE_NEW QueuedSubMesh(); 302 303 // Get the geometry for this SubMesh 304 q->submesh = se->getSubMesh(); 305 q->geometryLodList = determineGeometry(q->submesh); 306 q->materialName = se->getMaterialName(); 307 q->orientation = orientation; 308 q->position = position; 309 q->scale = scale; 310 // Determine the bounds based on the highest LOD 311 q->worldBounds = calculateBounds( 312 (*q->geometryLodList)[0].vertexData, 313 position, orientation, scale); 314 315 mQueuedSubMeshes.push_back(q); 316 } 317 } 318 //-------------------------------------------------------------------------- 319 StaticGeometry::SubMeshLodGeometryLinkList* determineGeometry(SubMesh * sm)320 StaticGeometry::determineGeometry(SubMesh* sm) 321 { 322 // First, determine if we've already seen this submesh before 323 SubMeshGeometryLookup::iterator i = 324 mSubMeshGeometryLookup.find(sm); 325 if (i != mSubMeshGeometryLookup.end()) 326 { 327 return i->second; 328 } 329 // Otherwise, we have to create a new one 330 SubMeshLodGeometryLinkList* lodList = OGRE_NEW_T(SubMeshLodGeometryLinkList, MEMCATEGORY_GEOMETRY)(); 331 mSubMeshGeometryLookup[sm] = lodList; 332 ushort numLods = sm->parent->isLodManual() ? 1 : 333 sm->parent->getNumLodLevels(); 334 lodList->resize(numLods); 335 for (ushort lod = 0; lod < numLods; ++lod) 336 { 337 SubMeshLodGeometryLink& geomLink = (*lodList)[lod]; 338 IndexData *lodIndexData; 339 if (lod == 0) 340 { 341 lodIndexData = sm->indexData; 342 } 343 else 344 { 345 lodIndexData = sm->mLodFaceList[lod - 1]; 346 } 347 // Can use the original mesh geometry? 348 if (sm->useSharedVertices) 349 { 350 if (sm->parent->getNumSubMeshes() == 1) 351 { 352 // Ok, this is actually our own anyway 353 geomLink.vertexData = sm->parent->sharedVertexData; 354 geomLink.indexData = lodIndexData; 355 } 356 else 357 { 358 // We have to split it 359 splitGeometry(sm->parent->sharedVertexData, 360 lodIndexData, &geomLink); 361 } 362 } 363 else 364 { 365 if (lod == 0) 366 { 367 // Ok, we can use the existing geometry; should be in full 368 // use by just this SubMesh 369 geomLink.vertexData = sm->vertexData; 370 geomLink.indexData = sm->indexData; 371 } 372 else 373 { 374 // We have to split it 375 splitGeometry(sm->vertexData, 376 lodIndexData, &geomLink); 377 } 378 } 379 assert (geomLink.vertexData->vertexStart == 0 && 380 "Cannot use vertexStart > 0 on indexed geometry due to " 381 "rendersystem incompatibilities - see the docs!"); 382 } 383 384 385 return lodList; 386 } 387 //-------------------------------------------------------------------------- splitGeometry(VertexData * vd,IndexData * id,StaticGeometry::SubMeshLodGeometryLink * targetGeomLink)388 void StaticGeometry::splitGeometry(VertexData* vd, IndexData* id, 389 StaticGeometry::SubMeshLodGeometryLink* targetGeomLink) 390 { 391 // Firstly we need to scan to see how many vertices are being used 392 // and while we're at it, build the remap we can use later 393 bool use32bitIndexes = 394 id->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT; 395 IndexRemap indexRemap; 396 if (use32bitIndexes) 397 { 398 uint32 *p32 = static_cast<uint32*>(id->indexBuffer->lock( 399 id->indexStart, 400 id->indexCount * id->indexBuffer->getIndexSize(), 401 HardwareBuffer::HBL_READ_ONLY)); 402 buildIndexRemap(p32, id->indexCount, indexRemap); 403 id->indexBuffer->unlock(); 404 } 405 else 406 { 407 uint16 *p16 = static_cast<uint16*>(id->indexBuffer->lock( 408 id->indexStart, 409 id->indexCount * id->indexBuffer->getIndexSize(), 410 HardwareBuffer::HBL_READ_ONLY)); 411 buildIndexRemap(p16, id->indexCount, indexRemap); 412 id->indexBuffer->unlock(); 413 } 414 if (indexRemap.size() == vd->vertexCount) 415 { 416 // ha, complete usage after all 417 targetGeomLink->vertexData = vd; 418 targetGeomLink->indexData = id; 419 return; 420 } 421 422 423 // Create the new vertex data records 424 targetGeomLink->vertexData = vd->clone(false); 425 // Convenience 426 VertexData* newvd = targetGeomLink->vertexData; 427 //IndexData* newid = targetGeomLink->indexData; 428 // Update the vertex count 429 newvd->vertexCount = indexRemap.size(); 430 431 size_t numvbufs = vd->vertexBufferBinding->getBufferCount(); 432 // Copy buffers from old to new 433 for (unsigned short b = 0; b < numvbufs; ++b) 434 { 435 // Lock old buffer 436 HardwareVertexBufferSharedPtr oldBuf = 437 vd->vertexBufferBinding->getBuffer(b); 438 // Create new buffer 439 HardwareVertexBufferSharedPtr newBuf = 440 HardwareBufferManager::getSingleton().createVertexBuffer( 441 oldBuf->getVertexSize(), 442 indexRemap.size(), 443 HardwareBuffer::HBU_STATIC); 444 // rebind 445 newvd->vertexBufferBinding->setBinding(b, newBuf); 446 447 // Copy all the elements of the buffer across, by iterating over 448 // the IndexRemap which describes how to move the old vertices 449 // to the new ones. By nature of the map the remap is in order of 450 // indexes in the old buffer, but note that we're not guaranteed to 451 // address every vertex (which is kinda why we're here) 452 uchar* pSrcBase = static_cast<uchar*>( 453 oldBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 454 uchar* pDstBase = static_cast<uchar*>( 455 newBuf->lock(HardwareBuffer::HBL_DISCARD)); 456 size_t vertexSize = oldBuf->getVertexSize(); 457 // Buffers should be the same size 458 assert (vertexSize == newBuf->getVertexSize()); 459 460 for (IndexRemap::iterator r = indexRemap.begin(); 461 r != indexRemap.end(); ++r) 462 { 463 assert (r->first < oldBuf->getNumVertices()); 464 assert (r->second < newBuf->getNumVertices()); 465 466 uchar* pSrc = pSrcBase + r->first * vertexSize; 467 uchar* pDst = pDstBase + r->second * vertexSize; 468 memcpy(pDst, pSrc, vertexSize); 469 } 470 // unlock 471 oldBuf->unlock(); 472 newBuf->unlock(); 473 474 } 475 476 // Now create a new index buffer 477 HardwareIndexBufferSharedPtr ibuf = 478 HardwareBufferManager::getSingleton().createIndexBuffer( 479 id->indexBuffer->getType(), id->indexCount, 480 HardwareBuffer::HBU_STATIC); 481 482 if (use32bitIndexes) 483 { 484 uint32 *pSrc32, *pDst32; 485 pSrc32 = static_cast<uint32*>(id->indexBuffer->lock( 486 id->indexStart, 487 id->indexCount * id->indexBuffer->getIndexSize(), 488 HardwareBuffer::HBL_READ_ONLY)); 489 pDst32 = static_cast<uint32*>(ibuf->lock( 490 HardwareBuffer::HBL_DISCARD)); 491 remapIndexes(pSrc32, pDst32, indexRemap, id->indexCount); 492 id->indexBuffer->unlock(); 493 ibuf->unlock(); 494 } 495 else 496 { 497 uint16 *pSrc16, *pDst16; 498 pSrc16 = static_cast<uint16*>(id->indexBuffer->lock( 499 id->indexStart, 500 id->indexCount * id->indexBuffer->getIndexSize(), 501 HardwareBuffer::HBL_READ_ONLY)); 502 pDst16 = static_cast<uint16*>(ibuf->lock( 503 HardwareBuffer::HBL_DISCARD)); 504 remapIndexes(pSrc16, pDst16, indexRemap, id->indexCount); 505 id->indexBuffer->unlock(); 506 ibuf->unlock(); 507 } 508 509 targetGeomLink->indexData = OGRE_NEW IndexData(); 510 targetGeomLink->indexData->indexStart = 0; 511 targetGeomLink->indexData->indexCount = id->indexCount; 512 targetGeomLink->indexData->indexBuffer = ibuf; 513 514 // Store optimised geometry for deallocation later 515 OptimisedSubMeshGeometry *optGeom = OGRE_NEW OptimisedSubMeshGeometry(); 516 optGeom->indexData = targetGeomLink->indexData; 517 optGeom->vertexData = targetGeomLink->vertexData; 518 mOptimisedSubMeshGeometryList.push_back(optGeom); 519 } 520 //-------------------------------------------------------------------------- addSceneNode(const SceneNode * node)521 void StaticGeometry::addSceneNode(const SceneNode* node) 522 { 523 SceneNode::ConstObjectIterator obji = node->getAttachedObjectIterator(); 524 while (obji.hasMoreElements()) 525 { 526 MovableObject* mobj = obji.getNext(); 527 if (mobj->getMovableType() == "Entity") 528 { 529 addEntity(static_cast<Entity*>(mobj), 530 node->_getDerivedPosition(), 531 node->_getDerivedOrientation(), 532 node->_getDerivedScale()); 533 } 534 } 535 // Iterate through all the child-nodes 536 SceneNode::ConstChildNodeIterator nodei = node->getChildIterator(); 537 538 while (nodei.hasMoreElements()) 539 { 540 const SceneNode* subNode = static_cast<const SceneNode*>(nodei.getNext()); 541 // Add this subnode and its children... 542 addSceneNode( subNode ); 543 } 544 } 545 //-------------------------------------------------------------------------- build(void)546 void StaticGeometry::build(void) 547 { 548 // Make sure there's nothing from previous builds 549 destroy(); 550 551 // Firstly allocate meshes to regions 552 for (QueuedSubMeshList::iterator qi = mQueuedSubMeshes.begin(); 553 qi != mQueuedSubMeshes.end(); ++qi) 554 { 555 QueuedSubMesh* qsm = *qi; 556 Region* region = getRegion(qsm->worldBounds, true); 557 region->assign(qsm); 558 } 559 bool stencilShadows = false; 560 if (mCastShadows && mOwner->isShadowTechniqueStencilBased()) 561 { 562 stencilShadows = true; 563 } 564 565 // Now tell each region to build itself 566 for (RegionMap::iterator ri = mRegionMap.begin(); 567 ri != mRegionMap.end(); ++ri) 568 { 569 ri->second->build(stencilShadows); 570 571 // Set the visibility flags on these regions 572 ri->second->setVisibilityFlags(mVisibilityFlags); 573 } 574 575 } 576 //-------------------------------------------------------------------------- destroy(void)577 void StaticGeometry::destroy(void) 578 { 579 // delete the regions 580 for (RegionMap::iterator i = mRegionMap.begin(); 581 i != mRegionMap.end(); ++i) 582 { 583 mOwner->extractMovableObject(i->second); 584 OGRE_DELETE i->second; 585 } 586 mRegionMap.clear(); 587 } 588 //-------------------------------------------------------------------------- reset(void)589 void StaticGeometry::reset(void) 590 { 591 destroy(); 592 for (QueuedSubMeshList::iterator i = mQueuedSubMeshes.begin(); 593 i != mQueuedSubMeshes.end(); ++i) 594 { 595 OGRE_DELETE *i; 596 } 597 mQueuedSubMeshes.clear(); 598 // Delete precached geoemtry lists 599 for (SubMeshGeometryLookup::iterator l = mSubMeshGeometryLookup.begin(); 600 l != mSubMeshGeometryLookup.end(); ++l) 601 { 602 OGRE_DELETE_T(l->second, SubMeshLodGeometryLinkList, MEMCATEGORY_GEOMETRY); 603 } 604 mSubMeshGeometryLookup.clear(); 605 // Delete optimised geometry 606 for (OptimisedSubMeshGeometryList::iterator o = mOptimisedSubMeshGeometryList.begin(); 607 o != mOptimisedSubMeshGeometryList.end(); ++o) 608 { 609 OGRE_DELETE *o; 610 } 611 mOptimisedSubMeshGeometryList.clear(); 612 613 } 614 //-------------------------------------------------------------------------- setVisible(bool visible)615 void StaticGeometry::setVisible(bool visible) 616 { 617 mVisible = visible; 618 // tell any existing regions 619 for (RegionMap::iterator ri = mRegionMap.begin(); 620 ri != mRegionMap.end(); ++ri) 621 { 622 ri->second->setVisible(visible); 623 } 624 } 625 //-------------------------------------------------------------------------- setCastShadows(bool castShadows)626 void StaticGeometry::setCastShadows(bool castShadows) 627 { 628 mCastShadows = castShadows; 629 // tell any existing regions 630 for (RegionMap::iterator ri = mRegionMap.begin(); 631 ri != mRegionMap.end(); ++ri) 632 { 633 ri->second->setCastShadows(castShadows); 634 } 635 636 } 637 //-------------------------------------------------------------------------- setRenderQueueGroup(uint8 queueID)638 void StaticGeometry::setRenderQueueGroup(uint8 queueID) 639 { 640 assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!"); 641 mRenderQueueIDSet = true; 642 mRenderQueueID = queueID; 643 // tell any existing regions 644 for (RegionMap::iterator ri = mRegionMap.begin(); 645 ri != mRegionMap.end(); ++ri) 646 { 647 ri->second->setRenderQueueGroup(queueID); 648 } 649 } 650 //-------------------------------------------------------------------------- getRenderQueueGroup(void) const651 uint8 StaticGeometry::getRenderQueueGroup(void) const 652 { 653 return mRenderQueueID; 654 } 655 //-------------------------------------------------------------------------- setVisibilityFlags(uint32 flags)656 void StaticGeometry::setVisibilityFlags(uint32 flags) 657 { 658 mVisibilityFlags = flags; 659 for (RegionMap::const_iterator ri = mRegionMap.begin(); 660 ri != mRegionMap.end(); ++ri) 661 { 662 ri->second->setVisibilityFlags(flags); 663 } 664 } 665 //-------------------------------------------------------------------------- getVisibilityFlags() const666 uint32 StaticGeometry::getVisibilityFlags() const 667 { 668 if(mRegionMap.empty()) 669 return MovableObject::getDefaultVisibilityFlags(); 670 671 RegionMap::const_iterator ri = mRegionMap.begin(); 672 return ri->second->getVisibilityFlags(); 673 } 674 //-------------------------------------------------------------------------- dump(const String & filename) const675 void StaticGeometry::dump(const String& filename) const 676 { 677 std::ofstream of(filename.c_str()); 678 of << "Static Geometry Report for " << mName << std::endl; 679 of << "-------------------------------------------------" << std::endl; 680 of << "Number of queued submeshes: " << mQueuedSubMeshes.size() << std::endl; 681 of << "Number of regions: " << mRegionMap.size() << std::endl; 682 of << "Region dimensions: " << mRegionDimensions << std::endl; 683 of << "Origin: " << mOrigin << std::endl; 684 of << "Max distance: " << mUpperDistance << std::endl; 685 of << "Casts shadows?: " << mCastShadows << std::endl; 686 of << std::endl; 687 for (RegionMap::const_iterator ri = mRegionMap.begin(); 688 ri != mRegionMap.end(); ++ri) 689 { 690 ri->second->dump(of); 691 } 692 of << "-------------------------------------------------" << std::endl; 693 } 694 //--------------------------------------------------------------------- visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)695 void StaticGeometry::visitRenderables(Renderable::Visitor* visitor, 696 bool debugRenderables) 697 { 698 for (RegionMap::const_iterator ri = mRegionMap.begin(); 699 ri != mRegionMap.end(); ++ri) 700 { 701 ri->second->visitRenderables(visitor, debugRenderables); 702 } 703 704 } 705 //-------------------------------------------------------------------------- getRegionIterator(void)706 StaticGeometry::RegionIterator StaticGeometry::getRegionIterator(void) 707 { 708 return RegionIterator(mRegionMap.begin(), mRegionMap.end()); 709 } 710 //-------------------------------------------------------------------------- 711 //-------------------------------------------------------------------------- Region(StaticGeometry * parent,const String & name,SceneManager * mgr,uint32 regionID,const Vector3 & centre)712 StaticGeometry::Region::Region(StaticGeometry* parent, const String& name, 713 SceneManager* mgr, uint32 regionID, const Vector3& centre) 714 : MovableObject(name), mParent(parent), mSceneMgr(mgr), mNode(0), 715 mRegionID(regionID), mCentre(centre), mBoundingRadius(0.0f), 716 mCurrentLod(0), mLodStrategy(0) 717 { 718 } 719 //-------------------------------------------------------------------------- ~Region()720 StaticGeometry::Region::~Region() 721 { 722 if (mNode) 723 { 724 mNode->getParentSceneNode()->removeChild(mNode); 725 mSceneMgr->destroySceneNode(mNode->getName()); 726 mNode = 0; 727 } 728 // delete 729 for (LODBucketList::iterator i = mLodBucketList.begin(); 730 i != mLodBucketList.end(); ++i) 731 { 732 OGRE_DELETE *i; 733 } 734 mLodBucketList.clear(); 735 736 // no need to delete queued meshes, these are managed in StaticGeometry 737 738 } 739 //-------------------------------------------------------------------------- getTypeFlags(void) const740 uint32 StaticGeometry::Region::getTypeFlags(void) const 741 { 742 return SceneManager::STATICGEOMETRY_TYPE_MASK; 743 } 744 //-------------------------------------------------------------------------- assign(QueuedSubMesh * qmesh)745 void StaticGeometry::Region::assign(QueuedSubMesh* qmesh) 746 { 747 mQueuedSubMeshes.push_back(qmesh); 748 749 // Set/check LOD strategy 750 const LodStrategy *lodStrategy = qmesh->submesh->parent->getLodStrategy(); 751 if (mLodStrategy == 0) 752 { 753 mLodStrategy = lodStrategy; 754 755 // First LOD mandatory, and always from base LOD value 756 mLodValues.push_back(mLodStrategy->getBaseValue()); 757 } 758 else 759 { 760 if (mLodStrategy != lodStrategy) 761 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Lod strategies do not match", 762 "StaticGeometry::Region::assign"); 763 } 764 765 // update LOD values 766 ushort lodLevels = qmesh->submesh->parent->getNumLodLevels(); 767 assert(qmesh->geometryLodList->size() == lodLevels); 768 769 while(mLodValues.size() < lodLevels) 770 { 771 mLodValues.push_back(0.0f); 772 } 773 // Make sure LOD levels are max of all at the requested level 774 for (ushort lod = 1; lod < lodLevels; ++lod) 775 { 776 const MeshLodUsage& meshLod = 777 qmesh->submesh->parent->getLodLevel(lod); 778 mLodValues[lod] = std::max(mLodValues[lod], 779 meshLod.value); 780 } 781 782 // update bounds 783 // Transform world bounds relative to our centre 784 AxisAlignedBox localBounds( 785 qmesh->worldBounds.getMinimum() - mCentre, 786 qmesh->worldBounds.getMaximum() - mCentre); 787 mAABB.merge(localBounds); 788 mBoundingRadius = Math::boundingRadiusFromAABB(mAABB); 789 790 } 791 //-------------------------------------------------------------------------- build(bool stencilShadows)792 void StaticGeometry::Region::build(bool stencilShadows) 793 { 794 // Create a node 795 mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName, 796 mCentre); 797 mNode->attachObject(this); 798 // We need to create enough LOD buckets to deal with the highest LOD 799 // we encountered in all the meshes queued 800 for (ushort lod = 0; lod < mLodValues.size(); ++lod) 801 { 802 LODBucket* lodBucket = 803 OGRE_NEW LODBucket(this, lod, mLodValues[lod]); 804 mLodBucketList.push_back(lodBucket); 805 // Now iterate over the meshes and assign to LODs 806 // LOD bucket will pick the right LOD to use 807 QueuedSubMeshList::iterator qi, qiend; 808 qiend = mQueuedSubMeshes.end(); 809 for (qi = mQueuedSubMeshes.begin(); qi != qiend; ++qi) 810 { 811 lodBucket->assign(*qi, lod); 812 } 813 // now build 814 lodBucket->build(stencilShadows); 815 } 816 817 818 819 } 820 //-------------------------------------------------------------------------- getMovableType(void) const821 const String& StaticGeometry::Region::getMovableType(void) const 822 { 823 static String sType = "StaticGeometry"; 824 return sType; 825 } 826 //-------------------------------------------------------------------------- _notifyCurrentCamera(Camera * cam)827 void StaticGeometry::Region::_notifyCurrentCamera(Camera* cam) 828 { 829 // Set camera 830 mCamera = cam; 831 832 // Cache squared view depth for use by GeometryBucket 833 mSquaredViewDepth = mParentNode->getSquaredViewDepth(cam->getLodCamera()); 834 835 // No LOD strategy set yet, skip (this indicates that there are no submeshes) 836 if (mLodStrategy == 0) 837 return; 838 839 // Sanity check 840 assert(!mLodValues.empty()); 841 842 // Calculate LOD value 843 Real lodValue = mLodStrategy->getValue(this, cam); 844 845 // Store LOD value for this strategy 846 mLodValue = lodValue; 847 848 // Get LOD index 849 mCurrentLod = mLodStrategy->getIndex(lodValue, mLodValues); 850 } 851 //-------------------------------------------------------------------------- getBoundingBox(void) const852 const AxisAlignedBox& StaticGeometry::Region::getBoundingBox(void) const 853 { 854 return mAABB; 855 } 856 //-------------------------------------------------------------------------- getBoundingRadius(void) const857 Real StaticGeometry::Region::getBoundingRadius(void) const 858 { 859 return mBoundingRadius; 860 } 861 //-------------------------------------------------------------------------- _updateRenderQueue(RenderQueue * queue)862 void StaticGeometry::Region::_updateRenderQueue(RenderQueue* queue) 863 { 864 mLodBucketList[mCurrentLod]->addRenderables(queue, mRenderQueueID, 865 mLodValue); 866 } 867 //--------------------------------------------------------------------- visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)868 void StaticGeometry::Region::visitRenderables(Renderable::Visitor* visitor, 869 bool debugRenderables) 870 { 871 for (LODBucketList::iterator i = mLodBucketList.begin(); i != mLodBucketList.end(); ++i) 872 { 873 (*i)->visitRenderables(visitor, debugRenderables); 874 } 875 876 } 877 //-------------------------------------------------------------------------- isVisible(void) const878 bool StaticGeometry::Region::isVisible(void) const 879 { 880 if(!mVisible || mBeyondFarDistance) 881 return false; 882 883 SceneManager* sm = Root::getSingleton()._getCurrentSceneManager(); 884 if (sm && !(mVisibilityFlags & sm->_getCombinedVisibilityMask())) 885 return false; 886 887 return true; 888 } 889 //-------------------------------------------------------------------------- 890 StaticGeometry::Region::LODIterator getLODIterator(void)891 StaticGeometry::Region::getLODIterator(void) 892 { 893 return LODIterator(mLodBucketList.begin(), mLodBucketList.end()); 894 } 895 //--------------------------------------------------------------------- 896 ShadowCaster::ShadowRenderableListIterator getShadowVolumeRenderableIterator(ShadowTechnique shadowTechnique,const Light * light,HardwareIndexBufferSharedPtr * indexBuffer,size_t * indexBufferUsedSize,bool extrude,Real extrusionDistance,unsigned long flags)897 StaticGeometry::Region::getShadowVolumeRenderableIterator( 898 ShadowTechnique shadowTechnique, const Light* light, 899 HardwareIndexBufferSharedPtr* indexBuffer, size_t* indexBufferUsedSize, 900 bool extrude, Real extrusionDistance, unsigned long flags) 901 { 902 // Calculate the object space light details 903 Vector4 lightPos = light->getAs4DVector(); 904 Matrix4 world2Obj = mParentNode->_getFullTransform().inverseAffine(); 905 lightPos = world2Obj.transformAffine(lightPos); 906 Matrix3 world2Obj3x3; 907 world2Obj.extract3x3Matrix(world2Obj3x3); 908 extrusionDistance *= Math::Sqrt(std::min(std::min(world2Obj3x3.GetColumn(0).squaredLength(), world2Obj3x3.GetColumn(1).squaredLength()), world2Obj3x3.GetColumn(2).squaredLength())); 909 910 // per-LOD shadow lists & edge data 911 mLodBucketList[mCurrentLod]->updateShadowRenderables( 912 shadowTechnique, lightPos, indexBuffer, extrude, extrusionDistance, flags); 913 914 EdgeData* edgeList = mLodBucketList[mCurrentLod]->getEdgeList(); 915 ShadowRenderableList& shadowRendList = mLodBucketList[mCurrentLod]->getShadowRenderableList(); 916 917 // Calc triangle light facing 918 updateEdgeListLightFacing(edgeList, lightPos); 919 920 // Generate indexes and update renderables 921 generateShadowVolume(edgeList, *indexBuffer, *indexBufferUsedSize, 922 light, shadowRendList, flags); 923 924 925 return ShadowCaster::ShadowRenderableListIterator(shadowRendList.begin(), shadowRendList.end()); 926 927 } 928 //-------------------------------------------------------------------------- getEdgeList(void)929 EdgeData* StaticGeometry::Region::getEdgeList(void) 930 { 931 return mLodBucketList[mCurrentLod]->getEdgeList(); 932 } 933 //-------------------------------------------------------------------------- hasEdgeList(void)934 bool StaticGeometry::Region::hasEdgeList(void) 935 { 936 return getEdgeList() != 0; 937 } 938 //-------------------------------------------------------------------------- dump(std::ofstream & of) const939 void StaticGeometry::Region::dump(std::ofstream& of) const 940 { 941 of << "Region " << mRegionID << std::endl; 942 of << "--------------------------" << std::endl; 943 of << "Centre: " << mCentre << std::endl; 944 of << "Local AABB: " << mAABB << std::endl; 945 of << "Bounding radius: " << mBoundingRadius << std::endl; 946 of << "Number of LODs: " << mLodBucketList.size() << std::endl; 947 948 for (LODBucketList::const_iterator i = mLodBucketList.begin(); 949 i != mLodBucketList.end(); ++i) 950 { 951 (*i)->dump(of); 952 } 953 of << "--------------------------" << std::endl; 954 } 955 //-------------------------------------------------------------------------- 956 //-------------------------------------------------------------------------- LODShadowRenderable(LODBucket * parent,HardwareIndexBufferSharedPtr * indexBuffer,const VertexData * vertexData,bool createSeparateLightCap,bool isLightCap)957 StaticGeometry::LODBucket::LODShadowRenderable::LODShadowRenderable( 958 LODBucket* parent, HardwareIndexBufferSharedPtr* indexBuffer, 959 const VertexData* vertexData, bool createSeparateLightCap, 960 bool isLightCap) 961 : mParent(parent) 962 { 963 // Initialise render op 964 mRenderOp.indexData = OGRE_NEW IndexData(); 965 mRenderOp.indexData->indexBuffer = *indexBuffer; 966 mRenderOp.indexData->indexStart = 0; 967 // index start and count are sorted out later 968 969 // Create vertex data which just references position component (and 2 component) 970 mRenderOp.vertexData = OGRE_NEW VertexData(); 971 // Map in position data 972 mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION); 973 ushort origPosBind = 974 vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource(); 975 mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(origPosBind); 976 mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer); 977 // Map in w-coord buffer (if present) 978 if(!vertexData->hardwareShadowVolWBuffer.isNull()) 979 { 980 mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0); 981 mWBuffer = vertexData->hardwareShadowVolWBuffer; 982 mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer); 983 } 984 // Use same vertex start as input 985 mRenderOp.vertexData->vertexStart = vertexData->vertexStart; 986 987 if (isLightCap) 988 { 989 // Use original vertex count, no extrusion 990 mRenderOp.vertexData->vertexCount = vertexData->vertexCount; 991 } 992 else 993 { 994 // Vertex count must take into account the doubling of the buffer, 995 // because second half of the buffer is the extruded copy 996 mRenderOp.vertexData->vertexCount = 997 vertexData->vertexCount * 2; 998 if (createSeparateLightCap) 999 { 1000 // Create child light cap 1001 mLightCap = OGRE_NEW LODShadowRenderable(parent, 1002 indexBuffer, vertexData, false, true); 1003 } 1004 } 1005 } 1006 //-------------------------------------------------------------------------- ~LODShadowRenderable()1007 StaticGeometry::LODBucket::LODShadowRenderable::~LODShadowRenderable() 1008 { 1009 OGRE_DELETE mRenderOp.indexData; 1010 OGRE_DELETE mRenderOp.vertexData; 1011 } 1012 //-------------------------------------------------------------------------- getWorldTransforms(Matrix4 * xform) const1013 void StaticGeometry::LODBucket::LODShadowRenderable::getWorldTransforms( 1014 Matrix4* xform) const 1015 { 1016 // pretransformed 1017 *xform = mParent->getParent()->_getParentNodeFullTransform(); 1018 } 1019 //----------------------------------------------------------------------- rebindIndexBuffer(const HardwareIndexBufferSharedPtr & indexBuffer)1020 void StaticGeometry::LODBucket::LODShadowRenderable::rebindIndexBuffer(const HardwareIndexBufferSharedPtr& indexBuffer) 1021 { 1022 mRenderOp.indexData->indexBuffer = indexBuffer; 1023 if (mLightCap) mLightCap->rebindIndexBuffer(indexBuffer); 1024 } 1025 //-------------------------------------------------------------------------- 1026 //-------------------------------------------------------------------------- LODBucket(Region * parent,unsigned short lod,Real lodValue)1027 StaticGeometry::LODBucket::LODBucket(Region* parent, unsigned short lod, 1028 Real lodValue) 1029 : mParent(parent), mLod(lod), mLodValue(lodValue), mEdgeList(0) 1030 , mVertexProgramInUse(false) 1031 { 1032 } 1033 //-------------------------------------------------------------------------- ~LODBucket()1034 StaticGeometry::LODBucket::~LODBucket() 1035 { 1036 OGRE_DELETE mEdgeList; 1037 for (ShadowCaster::ShadowRenderableList::iterator s = mShadowRenderables.begin(); 1038 s != mShadowRenderables.end(); ++s) 1039 { 1040 OGRE_DELETE *s; 1041 } 1042 mShadowRenderables.clear(); 1043 // delete 1044 for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin(); 1045 i != mMaterialBucketMap.end(); ++i) 1046 { 1047 OGRE_DELETE i->second; 1048 } 1049 mMaterialBucketMap.clear(); 1050 for(QueuedGeometryList::iterator qi = mQueuedGeometryList.begin(); 1051 qi != mQueuedGeometryList.end(); ++qi) 1052 { 1053 OGRE_DELETE *qi; 1054 } 1055 mQueuedGeometryList.clear(); 1056 1057 // no need to delete queued meshes, these are managed in StaticGeometry 1058 } 1059 //-------------------------------------------------------------------------- assign(QueuedSubMesh * qmesh,ushort atLod)1060 void StaticGeometry::LODBucket::assign(QueuedSubMesh* qmesh, ushort atLod) 1061 { 1062 QueuedGeometry* q = OGRE_NEW QueuedGeometry(); 1063 mQueuedGeometryList.push_back(q); 1064 q->position = qmesh->position; 1065 q->orientation = qmesh->orientation; 1066 q->scale = qmesh->scale; 1067 if (qmesh->geometryLodList->size() > atLod) 1068 { 1069 // This submesh has enough lods, use the right one 1070 q->geometry = &(*qmesh->geometryLodList)[atLod]; 1071 } 1072 else 1073 { 1074 // Not enough lods, use the lowest one we have 1075 q->geometry = 1076 &(*qmesh->geometryLodList)[qmesh->geometryLodList->size() - 1]; 1077 } 1078 // Locate a material bucket 1079 MaterialBucket* mbucket = 0; 1080 MaterialBucketMap::iterator m = 1081 mMaterialBucketMap.find(qmesh->materialName); 1082 if (m != mMaterialBucketMap.end()) 1083 { 1084 mbucket = m->second; 1085 } 1086 else 1087 { 1088 mbucket = OGRE_NEW MaterialBucket(this, qmesh->materialName); 1089 mMaterialBucketMap[qmesh->materialName] = mbucket; 1090 } 1091 mbucket->assign(q); 1092 } 1093 //-------------------------------------------------------------------------- build(bool stencilShadows)1094 void StaticGeometry::LODBucket::build(bool stencilShadows) 1095 { 1096 1097 EdgeListBuilder eb; 1098 size_t vertexSet = 0; 1099 1100 // Just pass this on to child buckets 1101 for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin(); 1102 i != mMaterialBucketMap.end(); ++i) 1103 { 1104 MaterialBucket* mat = i->second; 1105 1106 mat->build(stencilShadows); 1107 1108 if (stencilShadows) 1109 { 1110 MaterialBucket::GeometryIterator geomIt = 1111 mat->getGeometryIterator(); 1112 // Check if we have vertex programs here 1113 Technique* t = mat->getMaterial()->getBestTechnique(); 1114 if (t) 1115 { 1116 Pass* p = t->getPass(0); 1117 if (p) 1118 { 1119 if (p->hasVertexProgram()) 1120 { 1121 mVertexProgramInUse = true; 1122 } 1123 } 1124 } 1125 1126 while (geomIt.hasMoreElements()) 1127 { 1128 GeometryBucket* geom = geomIt.getNext(); 1129 1130 // Check we're dealing with 16-bit indexes here 1131 // Since stencil shadows can only deal with 16-bit 1132 // More than that and stencil is probably too CPU-heavy 1133 // in any case 1134 assert(geom->getIndexData()->indexBuffer->getType() 1135 == HardwareIndexBuffer::IT_16BIT && 1136 "Only 16-bit indexes allowed when using stencil shadows"); 1137 eb.addVertexData(geom->getVertexData()); 1138 eb.addIndexData(geom->getIndexData(), vertexSet++); 1139 } 1140 1141 } 1142 } 1143 1144 if (stencilShadows) 1145 { 1146 mEdgeList = eb.build(); 1147 } 1148 } 1149 //-------------------------------------------------------------------------- addRenderables(RenderQueue * queue,uint8 group,Real lodValue)1150 void StaticGeometry::LODBucket::addRenderables(RenderQueue* queue, 1151 uint8 group, Real lodValue) 1152 { 1153 // Just pass this on to child buckets 1154 MaterialBucketMap::iterator i, iend; 1155 iend = mMaterialBucketMap.end(); 1156 for (i = mMaterialBucketMap.begin(); i != iend; ++i) 1157 { 1158 i->second->addRenderables(queue, group, lodValue); 1159 } 1160 } 1161 //-------------------------------------------------------------------------- 1162 StaticGeometry::LODBucket::MaterialIterator getMaterialIterator(void)1163 StaticGeometry::LODBucket::getMaterialIterator(void) 1164 { 1165 return MaterialIterator( 1166 mMaterialBucketMap.begin(), mMaterialBucketMap.end()); 1167 } 1168 //-------------------------------------------------------------------------- dump(std::ofstream & of) const1169 void StaticGeometry::LODBucket::dump(std::ofstream& of) const 1170 { 1171 of << "LOD Bucket " << mLod << std::endl; 1172 of << "------------------" << std::endl; 1173 of << "LOD Value: " << mLodValue << std::endl; 1174 of << "Number of Materials: " << mMaterialBucketMap.size() << std::endl; 1175 for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin(); 1176 i != mMaterialBucketMap.end(); ++i) 1177 { 1178 i->second->dump(of); 1179 } 1180 of << "------------------" << std::endl; 1181 1182 } 1183 //--------------------------------------------------------------------- visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)1184 void StaticGeometry::LODBucket::visitRenderables(Renderable::Visitor* visitor, 1185 bool debugRenderables) 1186 { 1187 for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin(); 1188 i != mMaterialBucketMap.end(); ++i) 1189 { 1190 i->second->visitRenderables(visitor, debugRenderables); 1191 } 1192 1193 } 1194 //--------------------------------------------------------------------- updateShadowRenderables(ShadowTechnique shadowTechnique,const Vector4 & lightPos,HardwareIndexBufferSharedPtr * indexBuffer,bool extrude,Real extrusionDistance,unsigned long flags)1195 void StaticGeometry::LODBucket::updateShadowRenderables( 1196 ShadowTechnique shadowTechnique, const Vector4& lightPos, 1197 HardwareIndexBufferSharedPtr* indexBuffer, bool extrude, 1198 Real extrusionDistance, unsigned long flags /* = 0 */) 1199 { 1200 assert(indexBuffer && "Only external index buffers are supported right now"); 1201 assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT && 1202 "Only 16-bit indexes supported for now"); 1203 1204 // We need to search the edge list for silhouette edges 1205 if (!mEdgeList) 1206 { 1207 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 1208 "You enabled stencil shadows after the buid process!", 1209 "StaticGeometry::LODBucket::getShadowVolumeRenderableIterator"); 1210 } 1211 1212 // Init shadow renderable list if required 1213 bool init = mShadowRenderables.empty(); 1214 1215 EdgeData::EdgeGroupList::iterator egi; 1216 ShadowCaster::ShadowRenderableList::iterator si, siend; 1217 LODShadowRenderable* esr = 0; 1218 if (init) 1219 mShadowRenderables.resize(mEdgeList->edgeGroups.size()); 1220 1221 //bool updatedSharedGeomNormals = false; 1222 siend = mShadowRenderables.end(); 1223 egi = mEdgeList->edgeGroups.begin(); 1224 for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi) 1225 { 1226 if (init) 1227 { 1228 // Create a new renderable, create a separate light cap if 1229 // we're using a vertex program (either for this model, or 1230 // for extruding the shadow volume) since otherwise we can 1231 // get depth-fighting on the light cap 1232 1233 *si = OGRE_NEW LODShadowRenderable(this, indexBuffer, 1234 egi->vertexData, mVertexProgramInUse || !extrude); 1235 } 1236 // Get shadow renderable 1237 esr = static_cast<LODShadowRenderable*>(*si); 1238 HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer(); 1239 // Extrude vertices in software if required 1240 if (extrude) 1241 { 1242 mParent->extrudeVertices(esrPositionBuffer, 1243 egi->vertexData->vertexCount, 1244 lightPos, extrusionDistance); 1245 1246 } 1247 1248 } 1249 1250 } 1251 //-------------------------------------------------------------------------- 1252 //-------------------------------------------------------------------------- MaterialBucket(LODBucket * parent,const String & materialName)1253 StaticGeometry::MaterialBucket::MaterialBucket(LODBucket* parent, 1254 const String& materialName) 1255 : mParent(parent) 1256 , mMaterialName(materialName) 1257 , mTechnique(0) 1258 { 1259 } 1260 //-------------------------------------------------------------------------- ~MaterialBucket()1261 StaticGeometry::MaterialBucket::~MaterialBucket() 1262 { 1263 // delete 1264 for (GeometryBucketList::iterator i = mGeometryBucketList.begin(); 1265 i != mGeometryBucketList.end(); ++i) 1266 { 1267 OGRE_DELETE *i; 1268 } 1269 mGeometryBucketList.clear(); 1270 1271 // no need to delete queued meshes, these are managed in StaticGeometry 1272 } 1273 //-------------------------------------------------------------------------- assign(QueuedGeometry * qgeom)1274 void StaticGeometry::MaterialBucket::assign(QueuedGeometry* qgeom) 1275 { 1276 // Look up any current geometry 1277 String formatString = getGeometryFormatString(qgeom->geometry); 1278 CurrentGeometryMap::iterator gi = mCurrentGeometryMap.find(formatString); 1279 bool newBucket = true; 1280 if (gi != mCurrentGeometryMap.end()) 1281 { 1282 // Found existing geometry, try to assign 1283 newBucket = !gi->second->assign(qgeom); 1284 // Note that this bucket will be replaced as the 'current' 1285 // for this format string below since it's out of space 1286 } 1287 // Do we need to create a new one? 1288 if (newBucket) 1289 { 1290 GeometryBucket* gbucket = OGRE_NEW GeometryBucket(this, formatString, 1291 qgeom->geometry->vertexData, qgeom->geometry->indexData); 1292 // Add to main list 1293 mGeometryBucketList.push_back(gbucket); 1294 // Also index in 'current' list 1295 mCurrentGeometryMap[formatString] = gbucket; 1296 if (!gbucket->assign(qgeom)) 1297 { 1298 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 1299 "Somehow we couldn't fit the requested geometry even in a " 1300 "brand new GeometryBucket!! Must be a bug, please report.", 1301 "StaticGeometry::MaterialBucket::assign"); 1302 } 1303 } 1304 } 1305 //-------------------------------------------------------------------------- build(bool stencilShadows)1306 void StaticGeometry::MaterialBucket::build(bool stencilShadows) 1307 { 1308 mTechnique = 0; 1309 mMaterial = MaterialManager::getSingleton().getByName(mMaterialName); 1310 if (mMaterial.isNull()) 1311 { 1312 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 1313 "Material '" + mMaterialName + "' not found.", 1314 "StaticGeometry::MaterialBucket::build"); 1315 } 1316 mMaterial->load(); 1317 // tell the geometry buckets to build 1318 for (GeometryBucketList::iterator i = mGeometryBucketList.begin(); 1319 i != mGeometryBucketList.end(); ++i) 1320 { 1321 (*i)->build(stencilShadows); 1322 } 1323 } 1324 //-------------------------------------------------------------------------- addRenderables(RenderQueue * queue,uint8 group,Real lodValue)1325 void StaticGeometry::MaterialBucket::addRenderables(RenderQueue* queue, 1326 uint8 group, Real lodValue) 1327 { 1328 // Get region 1329 Region *region = mParent->getParent(); 1330 1331 // Get material LOD strategy 1332 const LodStrategy *materialLodStrategy = mMaterial->getLodStrategy(); 1333 1334 // If material strategy doesn't match, recompute LOD value with correct strategy 1335 if (materialLodStrategy != region->mLodStrategy) 1336 lodValue = materialLodStrategy->getValue(region, region->mCamera); 1337 1338 // Determine the current material technique 1339 mTechnique = mMaterial->getBestTechnique( 1340 mMaterial->getLodIndex(lodValue)); 1341 GeometryBucketList::iterator i, iend; 1342 iend = mGeometryBucketList.end(); 1343 for (i = mGeometryBucketList.begin(); i != iend; ++i) 1344 { 1345 queue->addRenderable(*i, group); 1346 } 1347 1348 } 1349 //-------------------------------------------------------------------------- getGeometryFormatString(SubMeshLodGeometryLink * geom)1350 String StaticGeometry::MaterialBucket::getGeometryFormatString( 1351 SubMeshLodGeometryLink* geom) 1352 { 1353 // Formulate an identifying string for the geometry format 1354 // Must take into account the vertex declaration and the index type 1355 // Format is (all lines separated by '|'): 1356 // Index type 1357 // Vertex element (repeating) 1358 // source 1359 // semantic 1360 // type 1361 StringUtil::StrStreamType str; 1362 1363 str << geom->indexData->indexBuffer->getType() << "|"; 1364 const VertexDeclaration::VertexElementList& elemList = 1365 geom->vertexData->vertexDeclaration->getElements(); 1366 VertexDeclaration::VertexElementList::const_iterator ei, eiend; 1367 eiend = elemList.end(); 1368 for (ei = elemList.begin(); ei != eiend; ++ei) 1369 { 1370 const VertexElement& elem = *ei; 1371 str << elem.getSource() << "|"; 1372 str << elem.getSource() << "|"; 1373 str << elem.getSemantic() << "|"; 1374 str << elem.getType() << "|"; 1375 } 1376 1377 return str.str(); 1378 1379 } 1380 //-------------------------------------------------------------------------- 1381 StaticGeometry::MaterialBucket::GeometryIterator getGeometryIterator(void)1382 StaticGeometry::MaterialBucket::getGeometryIterator(void) 1383 { 1384 return GeometryIterator( 1385 mGeometryBucketList.begin(), mGeometryBucketList.end()); 1386 } 1387 //-------------------------------------------------------------------------- dump(std::ofstream & of) const1388 void StaticGeometry::MaterialBucket::dump(std::ofstream& of) const 1389 { 1390 of << "Material Bucket " << mMaterialName << std::endl; 1391 of << "--------------------------------------------------" << std::endl; 1392 of << "Geometry buckets: " << mGeometryBucketList.size() << std::endl; 1393 for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin(); 1394 i != mGeometryBucketList.end(); ++i) 1395 { 1396 (*i)->dump(of); 1397 } 1398 of << "--------------------------------------------------" << std::endl; 1399 1400 } 1401 //--------------------------------------------------------------------- visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)1402 void StaticGeometry::MaterialBucket::visitRenderables(Renderable::Visitor* visitor, 1403 bool debugRenderables) 1404 { 1405 for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin(); 1406 i != mGeometryBucketList.end(); ++i) 1407 { 1408 visitor->visit(*i, mParent->getLod(), false); 1409 } 1410 1411 } 1412 //-------------------------------------------------------------------------- 1413 //-------------------------------------------------------------------------- GeometryBucket(MaterialBucket * parent,const String & formatString,const VertexData * vData,const IndexData * iData)1414 StaticGeometry::GeometryBucket::GeometryBucket(MaterialBucket* parent, 1415 const String& formatString, const VertexData* vData, 1416 const IndexData* iData) 1417 : Renderable(), mParent(parent), mFormatString(formatString) 1418 { 1419 // Clone the structure from the example 1420 mVertexData = vData->clone(false); 1421 mIndexData = iData->clone(false); 1422 mVertexData->vertexCount = 0; 1423 mVertexData->vertexStart = 0; 1424 mIndexData->indexCount = 0; 1425 mIndexData->indexStart = 0; 1426 mIndexType = iData->indexBuffer->getType(); 1427 // Derive the max vertices 1428 if (mIndexType == HardwareIndexBuffer::IT_32BIT) 1429 { 1430 mMaxVertexIndex = 0xFFFFFFFF; 1431 } 1432 else 1433 { 1434 mMaxVertexIndex = 0xFFFF; 1435 } 1436 1437 // Check to see if we have blend indices / blend weights 1438 // remove them if so, they can try to blend non-existent bones! 1439 const VertexElement* blendIndices = 1440 mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES); 1441 const VertexElement* blendWeights = 1442 mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS); 1443 if (blendIndices && blendWeights) 1444 { 1445 assert(blendIndices->getSource() == blendWeights->getSource() 1446 && "Blend indices and weights should be in the same buffer"); 1447 // Get the source 1448 ushort source = blendIndices->getSource(); 1449 assert(blendIndices->getSize() + blendWeights->getSize() == 1450 mVertexData->vertexBufferBinding->getBuffer(source)->getVertexSize() 1451 && "Blend indices and blend buffers should have buffer to themselves!"); 1452 // Unset the buffer 1453 mVertexData->vertexBufferBinding->unsetBinding(source); 1454 // Remove the elements 1455 mVertexData->vertexDeclaration->removeElement(VES_BLEND_INDICES); 1456 mVertexData->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS); 1457 // Close gaps in bindings for effective and safely 1458 mVertexData->closeGapsInBindings(); 1459 } 1460 1461 1462 } 1463 //-------------------------------------------------------------------------- ~GeometryBucket()1464 StaticGeometry::GeometryBucket::~GeometryBucket() 1465 { 1466 OGRE_DELETE mVertexData; 1467 OGRE_DELETE mIndexData; 1468 } 1469 //-------------------------------------------------------------------------- getMaterial(void) const1470 const MaterialPtr& StaticGeometry::GeometryBucket::getMaterial(void) const 1471 { 1472 return mParent->getMaterial(); 1473 } 1474 //-------------------------------------------------------------------------- getTechnique(void) const1475 Technique* StaticGeometry::GeometryBucket::getTechnique(void) const 1476 { 1477 return mParent->getCurrentTechnique(); 1478 } 1479 //-------------------------------------------------------------------------- getRenderOperation(RenderOperation & op)1480 void StaticGeometry::GeometryBucket::getRenderOperation(RenderOperation& op) 1481 { 1482 op.indexData = mIndexData; 1483 op.operationType = RenderOperation::OT_TRIANGLE_LIST; 1484 op.srcRenderable = this; 1485 op.useIndexes = true; 1486 op.vertexData = mVertexData; 1487 } 1488 //-------------------------------------------------------------------------- getWorldTransforms(Matrix4 * xform) const1489 void StaticGeometry::GeometryBucket::getWorldTransforms(Matrix4* xform) const 1490 { 1491 // Should be the identity transform, but lets allow transformation of the 1492 // nodes the regions are attached to for kicks 1493 *xform = mParent->getParent()->getParent()->_getParentNodeFullTransform(); 1494 } 1495 //-------------------------------------------------------------------------- getSquaredViewDepth(const Camera * cam) const1496 Real StaticGeometry::GeometryBucket::getSquaredViewDepth(const Camera* cam) const 1497 { 1498 const Region *region = mParent->getParent()->getParent(); 1499 if (cam == region->mCamera) 1500 return region->mSquaredViewDepth; 1501 else 1502 return region->getParentNode()->getSquaredViewDepth(cam->getLodCamera()); 1503 } 1504 //-------------------------------------------------------------------------- getLights(void) const1505 const LightList& StaticGeometry::GeometryBucket::getLights(void) const 1506 { 1507 return mParent->getParent()->getParent()->queryLights(); 1508 } 1509 //-------------------------------------------------------------------------- getCastsShadows(void) const1510 bool StaticGeometry::GeometryBucket::getCastsShadows(void) const 1511 { 1512 return mParent->getParent()->getParent()->getCastShadows(); 1513 } 1514 //-------------------------------------------------------------------------- assign(QueuedGeometry * qgeom)1515 bool StaticGeometry::GeometryBucket::assign(QueuedGeometry* qgeom) 1516 { 1517 // Do we have enough space? 1518 // -2 first to avoid overflow (-1 to adjust count to index, -1 to ensure 1519 // no overflow at 32 bits and use >= instead of >) 1520 if ((mVertexData->vertexCount - 2 + qgeom->geometry->vertexData->vertexCount) 1521 >= mMaxVertexIndex) 1522 { 1523 return false; 1524 } 1525 1526 mQueuedGeometry.push_back(qgeom); 1527 mVertexData->vertexCount += qgeom->geometry->vertexData->vertexCount; 1528 mIndexData->indexCount += qgeom->geometry->indexData->indexCount; 1529 1530 return true; 1531 } 1532 //-------------------------------------------------------------------------- build(bool stencilShadows)1533 void StaticGeometry::GeometryBucket::build(bool stencilShadows) 1534 { 1535 // Ok, here's where we transfer the vertices and indexes to the shared 1536 // buffers 1537 // Shortcuts 1538 VertexDeclaration* dcl = mVertexData->vertexDeclaration; 1539 VertexBufferBinding* binds = mVertexData->vertexBufferBinding; 1540 1541 // create index buffer, and lock 1542 mIndexData->indexBuffer = HardwareBufferManager::getSingleton() 1543 .createIndexBuffer(mIndexType, mIndexData->indexCount, 1544 HardwareBuffer::HBU_STATIC_WRITE_ONLY); 1545 uint32* p32Dest = 0; 1546 uint16* p16Dest = 0; 1547 if (mIndexType == HardwareIndexBuffer::IT_32BIT) 1548 { 1549 p32Dest = static_cast<uint32*>( 1550 mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); 1551 } 1552 else 1553 { 1554 p16Dest = static_cast<uint16*>( 1555 mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); 1556 } 1557 // create all vertex buffers, and lock 1558 ushort b; 1559 ushort posBufferIdx = dcl->findElementBySemantic(VES_POSITION)->getSource(); 1560 1561 vector<uchar*>::type destBufferLocks; 1562 vector<VertexDeclaration::VertexElementList>::type bufferElements; 1563 for (b = 0; b < binds->getBufferCount(); ++b) 1564 { 1565 size_t vertexCount = mVertexData->vertexCount; 1566 // Need to double the vertex count for the position buffer 1567 // if we're doing stencil shadows 1568 if (stencilShadows && b == posBufferIdx) 1569 { 1570 vertexCount = vertexCount * 2; 1571 assert(vertexCount <= mMaxVertexIndex && 1572 "Index range exceeded when using stencil shadows, consider " 1573 "reducing your region size or reducing poly count"); 1574 } 1575 HardwareVertexBufferSharedPtr vbuf = 1576 HardwareBufferManager::getSingleton().createVertexBuffer( 1577 dcl->getVertexSize(b), 1578 vertexCount, 1579 HardwareBuffer::HBU_STATIC_WRITE_ONLY); 1580 binds->setBinding(b, vbuf); 1581 uchar* pLock = static_cast<uchar*>( 1582 vbuf->lock(HardwareBuffer::HBL_DISCARD)); 1583 destBufferLocks.push_back(pLock); 1584 // Pre-cache vertex elements per buffer 1585 bufferElements.push_back(dcl->findElementsBySource(b)); 1586 } 1587 1588 1589 // Iterate over the geometry items 1590 size_t indexOffset = 0; 1591 QueuedGeometryList::iterator gi, giend; 1592 giend = mQueuedGeometry.end(); 1593 Vector3 regionCentre = mParent->getParent()->getParent()->getCentre(); 1594 for (gi = mQueuedGeometry.begin(); gi != giend; ++gi) 1595 { 1596 QueuedGeometry* geom = *gi; 1597 // Copy indexes across with offset 1598 IndexData* srcIdxData = geom->geometry->indexData; 1599 if (mIndexType == HardwareIndexBuffer::IT_32BIT) 1600 { 1601 // Lock source indexes 1602 uint32* pSrc = static_cast<uint32*>( 1603 srcIdxData->indexBuffer->lock( 1604 srcIdxData->indexStart, 1605 srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(), 1606 HardwareBuffer::HBL_READ_ONLY)); 1607 1608 copyIndexes(pSrc, p32Dest, srcIdxData->indexCount, indexOffset); 1609 p32Dest += srcIdxData->indexCount; 1610 srcIdxData->indexBuffer->unlock(); 1611 } 1612 else 1613 { 1614 // Lock source indexes 1615 uint16* pSrc = static_cast<uint16*>( 1616 srcIdxData->indexBuffer->lock( 1617 srcIdxData->indexStart, 1618 srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(), 1619 HardwareBuffer::HBL_READ_ONLY)); 1620 1621 copyIndexes(pSrc, p16Dest, srcIdxData->indexCount, indexOffset); 1622 p16Dest += srcIdxData->indexCount; 1623 srcIdxData->indexBuffer->unlock(); 1624 } 1625 1626 // Now deal with vertex buffers 1627 // we can rely on buffer counts / formats being the same 1628 VertexData* srcVData = geom->geometry->vertexData; 1629 VertexBufferBinding* srcBinds = srcVData->vertexBufferBinding; 1630 for (b = 0; b < binds->getBufferCount(); ++b) 1631 { 1632 // lock source 1633 HardwareVertexBufferSharedPtr srcBuf = 1634 srcBinds->getBuffer(b); 1635 uchar* pSrcBase = static_cast<uchar*>( 1636 srcBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 1637 // Get buffer lock pointer, we'll update this later 1638 uchar* pDstBase = destBufferLocks[b]; 1639 size_t bufInc = srcBuf->getVertexSize(); 1640 1641 // Iterate over vertices 1642 float *pSrcReal, *pDstReal; 1643 Vector3 tmp; 1644 for (size_t v = 0; v < srcVData->vertexCount; ++v) 1645 { 1646 // Iterate over vertex elements 1647 VertexDeclaration::VertexElementList& elems = 1648 bufferElements[b]; 1649 VertexDeclaration::VertexElementList::iterator ei; 1650 for (ei = elems.begin(); ei != elems.end(); ++ei) 1651 { 1652 VertexElement& elem = *ei; 1653 elem.baseVertexPointerToElement(pSrcBase, &pSrcReal); 1654 elem.baseVertexPointerToElement(pDstBase, &pDstReal); 1655 switch (elem.getSemantic()) 1656 { 1657 case VES_POSITION: 1658 tmp.x = *pSrcReal++; 1659 tmp.y = *pSrcReal++; 1660 tmp.z = *pSrcReal++; 1661 // transform 1662 tmp = (geom->orientation * (tmp * geom->scale)) + 1663 geom->position; 1664 // Adjust for region centre 1665 tmp -= regionCentre; 1666 *pDstReal++ = tmp.x; 1667 *pDstReal++ = tmp.y; 1668 *pDstReal++ = tmp.z; 1669 break; 1670 case VES_NORMAL: 1671 case VES_TANGENT: 1672 case VES_BINORMAL: 1673 tmp.x = *pSrcReal++; 1674 tmp.y = *pSrcReal++; 1675 tmp.z = *pSrcReal++; 1676 // scale (invert) 1677 tmp = tmp / geom->scale; 1678 tmp.normalise(); 1679 // rotation 1680 tmp = geom->orientation * tmp; 1681 *pDstReal++ = tmp.x; 1682 *pDstReal++ = tmp.y; 1683 *pDstReal++ = tmp.z; 1684 // copy parity for tangent. 1685 if (elem.getType() == Ogre::VET_FLOAT4) 1686 *pDstReal = *pSrcReal; 1687 break; 1688 default: 1689 // just raw copy 1690 memcpy(pDstReal, pSrcReal, 1691 VertexElement::getTypeSize(elem.getType())); 1692 break; 1693 }; 1694 1695 } 1696 1697 // Increment both pointers 1698 pDstBase += bufInc; 1699 pSrcBase += bufInc; 1700 1701 } 1702 1703 // Update pointer 1704 destBufferLocks[b] = pDstBase; 1705 srcBuf->unlock(); 1706 } 1707 1708 indexOffset += geom->geometry->vertexData->vertexCount; 1709 } 1710 1711 // Unlock everything 1712 mIndexData->indexBuffer->unlock(); 1713 for (b = 0; b < binds->getBufferCount(); ++b) 1714 { 1715 binds->getBuffer(b)->unlock(); 1716 } 1717 1718 // If we're dealing with stencil shadows, copy the position data from 1719 // the early half of the buffer to the latter part 1720 if (stencilShadows) 1721 { 1722 HardwareVertexBufferSharedPtr buf = binds->getBuffer(posBufferIdx); 1723 void* pSrc = buf->lock(HardwareBuffer::HBL_NORMAL); 1724 // Point dest at second half (remember vertexcount is original count) 1725 void* pDest = static_cast<uchar*>(pSrc) + 1726 buf->getVertexSize() * mVertexData->vertexCount; 1727 memcpy(pDest, pSrc, buf->getVertexSize() * mVertexData->vertexCount); 1728 buf->unlock(); 1729 1730 // Also set up hardware W buffer if appropriate 1731 RenderSystem* rend = Root::getSingleton().getRenderSystem(); 1732 if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) 1733 { 1734 buf = HardwareBufferManager::getSingleton().createVertexBuffer( 1735 sizeof(float), mVertexData->vertexCount * 2, 1736 HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); 1737 // Fill the first half with 1.0, second half with 0.0 1738 float *pW = static_cast<float*>( 1739 buf->lock(HardwareBuffer::HBL_DISCARD)); 1740 size_t v; 1741 for (v = 0; v < mVertexData->vertexCount; ++v) 1742 { 1743 *pW++ = 1.0f; 1744 } 1745 for (v = 0; v < mVertexData->vertexCount; ++v) 1746 { 1747 *pW++ = 0.0f; 1748 } 1749 buf->unlock(); 1750 mVertexData->hardwareShadowVolWBuffer = buf; 1751 } 1752 } 1753 1754 } 1755 //-------------------------------------------------------------------------- dump(std::ofstream & of) const1756 void StaticGeometry::GeometryBucket::dump(std::ofstream& of) const 1757 { 1758 of << "Geometry Bucket" << std::endl; 1759 of << "---------------" << std::endl; 1760 of << "Format string: " << mFormatString << std::endl; 1761 of << "Geometry items: " << mQueuedGeometry.size() << std::endl; 1762 of << "Vertex count: " << mVertexData->vertexCount << std::endl; 1763 of << "Index count: " << mIndexData->indexCount << std::endl; 1764 of << "---------------" << std::endl; 1765 1766 } 1767 //-------------------------------------------------------------------------- 1768 1769 } 1770 1771