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 "OgreInstanceBatchHW_VTF.h" 30 #include "OgreSubMesh.h" 31 #include "OgreRenderOperation.h" 32 #include "OgreHardwareBufferManager.h" 33 #include "OgreHardwarePixelBuffer.h" 34 #include "OgreInstancedEntity.h" 35 #include "OgreMaterial.h" 36 #include "OgreTechnique.h" 37 #include "OgreMaterialManager.h" 38 #include "OgreTexture.h" 39 #include "OgreTextureManager.h" 40 #include "OgreRoot.h" 41 42 namespace Ogre 43 { 44 static const uint16 c_maxTexWidthHW = 4096; 45 static const uint16 c_maxTexHeightHW = 4096; 46 InstanceBatchHW_VTF(InstanceManager * creator,MeshPtr & meshReference,const MaterialPtr & material,size_t instancesPerBatch,const Mesh::IndexMap * indexToBoneMap,const String & batchName)47 InstanceBatchHW_VTF::InstanceBatchHW_VTF( 48 InstanceManager *creator, MeshPtr &meshReference, 49 const MaterialPtr &material, size_t instancesPerBatch, 50 const Mesh::IndexMap *indexToBoneMap, const String &batchName ) 51 : BaseInstanceBatchVTF( creator, meshReference, material, 52 instancesPerBatch, indexToBoneMap, batchName), 53 mKeepStatic( false ) 54 { 55 } 56 //----------------------------------------------------------------------- ~InstanceBatchHW_VTF()57 InstanceBatchHW_VTF::~InstanceBatchHW_VTF() 58 { 59 } 60 //----------------------------------------------------------------------- setupVertices(const SubMesh * baseSubMesh)61 void InstanceBatchHW_VTF::setupVertices( const SubMesh* baseSubMesh ) 62 { 63 mRenderOperation.vertexData = OGRE_NEW VertexData(); 64 mRemoveOwnVertexData = true; //Raise flag to remove our own vertex data in the end (not always needed) 65 66 VertexData *thisVertexData = mRenderOperation.vertexData; 67 VertexData *baseVertexData = baseSubMesh->vertexData; 68 69 thisVertexData->vertexStart = 0; 70 thisVertexData->vertexCount = baseVertexData->vertexCount; 71 mRenderOperation.numberOfInstances = mInstancesPerBatch; 72 73 HardwareBufferManager::getSingleton().destroyVertexDeclaration( 74 thisVertexData->vertexDeclaration ); 75 thisVertexData->vertexDeclaration = baseVertexData->vertexDeclaration->clone(); 76 77 //Reuse all vertex buffers 78 VertexBufferBinding::VertexBufferBindingMap::const_iterator itor = baseVertexData-> 79 vertexBufferBinding->getBindings().begin(); 80 VertexBufferBinding::VertexBufferBindingMap::const_iterator end = baseVertexData-> 81 vertexBufferBinding->getBindings().end(); 82 while( itor != end ) 83 { 84 const unsigned short bufferIdx = itor->first; 85 const HardwareVertexBufferSharedPtr vBuf = itor->second; 86 thisVertexData->vertexBufferBinding->setBinding( bufferIdx, vBuf ); 87 ++itor; 88 } 89 90 //Remove the blend weights & indices 91 HWBoneIdxVec hwBoneIdx; 92 HWBoneWgtVec hwBoneWgt; 93 94 //Blend weights may not be present because HW_VTF does not require to be skeletally animated 95 const VertexElement *veWeights = baseVertexData->vertexDeclaration-> 96 findElementBySemantic( VES_BLEND_WEIGHTS ); 97 if( veWeights ) 98 mWeightCount = forceOneWeight() ? 1 : veWeights->getSize() / sizeof(float); 99 else 100 mWeightCount = 1; 101 102 hwBoneIdx.resize( baseVertexData->vertexCount * mWeightCount, 0 ); 103 104 if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() ) 105 { 106 if(mWeightCount > 1) 107 { 108 hwBoneWgt.resize( baseVertexData->vertexCount * mWeightCount, 0 ); 109 retrieveBoneIdxWithWeights(baseVertexData, hwBoneIdx, hwBoneWgt); 110 } 111 else 112 { 113 retrieveBoneIdx( baseVertexData, hwBoneIdx ); 114 } 115 116 const VertexElement* pElement = thisVertexData->vertexDeclaration->findElementBySemantic 117 (VES_BLEND_INDICES); 118 if (pElement) 119 { 120 unsigned short skelDataSource = pElement->getSource(); 121 thisVertexData->vertexDeclaration->removeElement( VES_BLEND_INDICES ); 122 thisVertexData->vertexDeclaration->removeElement( VES_BLEND_WEIGHTS ); 123 if (thisVertexData->vertexDeclaration->findElementsBySource(skelDataSource).empty()) 124 { 125 thisVertexData->vertexDeclaration->closeGapsInSource(); 126 thisVertexData->vertexBufferBinding->unsetBinding(skelDataSource); 127 VertexBufferBinding::BindingIndexMap tmpMap; 128 thisVertexData->vertexBufferBinding->closeGaps(tmpMap); 129 } 130 } 131 } 132 133 createVertexTexture( baseSubMesh ); 134 createVertexSemantics( thisVertexData, baseVertexData, hwBoneIdx, hwBoneWgt); 135 } 136 //----------------------------------------------------------------------- setupIndices(const SubMesh * baseSubMesh)137 void InstanceBatchHW_VTF::setupIndices( const SubMesh* baseSubMesh ) 138 { 139 //We could use just a reference, but the InstanceManager will in the end attampt to delete 140 //the pointer, and we can't give it something that doesn't belong to us. 141 mRenderOperation.indexData = baseSubMesh->indexData->clone( true ); 142 mRemoveOwnIndexData = true; //Raise flag to remove our own index data in the end (not always needed) 143 } 144 //----------------------------------------------------------------------- createVertexSemantics(VertexData * thisVertexData,VertexData * baseVertexData,const HWBoneIdxVec & hwBoneIdx,const HWBoneWgtVec & hwBoneWgt)145 void InstanceBatchHW_VTF::createVertexSemantics( VertexData *thisVertexData, 146 VertexData *baseVertexData, 147 const HWBoneIdxVec &hwBoneIdx, 148 const HWBoneWgtVec& hwBoneWgt) 149 { 150 const float texWidth = static_cast<float>(mMatrixTexture->getWidth()); 151 152 //Only one weight per vertex is supported. It would not only be complex, but prohibitively slow. 153 //Put them in a new buffer, since it's 16 bytes aligned :-) 154 unsigned short newSource = thisVertexData->vertexDeclaration->getMaxSource() + 1; 155 156 size_t offset = 0; 157 158 size_t maxFloatsPerVector = 4; 159 160 //Can fit two dual quaternions in every float4, but only one 3x4 matrix 161 for(size_t i = 0; i < mWeightCount; i += maxFloatsPerVector / mRowLength) 162 { 163 offset += thisVertexData->vertexDeclaration->addElement( newSource, offset, VET_FLOAT4, VES_TEXTURE_COORDINATES, 164 thisVertexData->vertexDeclaration->getNextFreeTextureCoordinate() ).getSize(); 165 } 166 167 //Add the weights (supports up to four, which is Ogre's limit) 168 if(mWeightCount > 1) 169 { 170 thisVertexData->vertexDeclaration->addElement(newSource, offset, VET_FLOAT4, VES_BLEND_WEIGHTS, 171 0 ).getSize(); 172 } 173 174 //Create our own vertex buffer 175 HardwareVertexBufferSharedPtr vertexBuffer = 176 HardwareBufferManager::getSingleton().createVertexBuffer( 177 thisVertexData->vertexDeclaration->getVertexSize(newSource), 178 thisVertexData->vertexCount, 179 HardwareBuffer::HBU_STATIC_WRITE_ONLY ); 180 thisVertexData->vertexBufferBinding->setBinding( newSource, vertexBuffer ); 181 182 float *thisFloat = static_cast<float*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD)); 183 184 //Create the UVs to sample from the right bone/matrix 185 for( size_t j=0; j < baseVertexData->vertexCount * mWeightCount; j += mWeightCount) 186 { 187 size_t numberOfMatricesInLine = 0; 188 189 //Write the matrices, adding padding as needed 190 for(size_t i = 0; i < mWeightCount; ++i) 191 { 192 //Write the matrix 193 for( size_t k=0; k < mRowLength; ++k) 194 { 195 //Only calculate U (not V) since all matrices are in the same row. We use the instanced 196 //(repeated) buffer to tell how much U & V we need to offset 197 size_t instanceIdx = hwBoneIdx[j+i] * mRowLength + k; 198 *thisFloat++ = instanceIdx / texWidth; 199 } 200 201 ++numberOfMatricesInLine; 202 203 //If another matrix can't be fit, we're on another line, or if this is the last weight 204 if((numberOfMatricesInLine + 1) * mRowLength > maxFloatsPerVector || (i+1) == mWeightCount) 205 { 206 //Place zeroes in the remaining coordinates 207 for ( size_t k=mRowLength * numberOfMatricesInLine; k < maxFloatsPerVector; ++k) 208 { 209 *thisFloat++ = 0.0f; 210 } 211 212 numberOfMatricesInLine = 0; 213 } 214 } 215 216 //Don't need to write weights if there is only one 217 if(mWeightCount > 1) 218 { 219 //Write the weights 220 for(size_t i = 0; i < mWeightCount; ++i) 221 { 222 *thisFloat++ = hwBoneWgt[j+i]; 223 } 224 225 //Write the empty space 226 for(size_t i = mWeightCount; i < maxFloatsPerVector; ++i) 227 { 228 *thisFloat++ = 0.0f; 229 } 230 } 231 } 232 233 vertexBuffer->unlock(); 234 235 //Now create the instance buffer that will be incremented per instance, contains UV offsets 236 newSource = thisVertexData->vertexDeclaration->getMaxSource() + 1; 237 offset = thisVertexData->vertexDeclaration->addElement( newSource, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES, 238 thisVertexData->vertexDeclaration->getNextFreeTextureCoordinate() ).getSize(); 239 if (useBoneMatrixLookup()) 240 { 241 //if using bone matrix lookup we will need to add 3 more float4 to contain the matrix. containing 242 //the personal world transform of each entity. 243 offset += thisVertexData->vertexDeclaration->addElement( newSource, offset, VET_FLOAT4, VES_TEXTURE_COORDINATES, 244 thisVertexData->vertexDeclaration->getNextFreeTextureCoordinate() ).getSize(); 245 offset += thisVertexData->vertexDeclaration->addElement( newSource, offset, VET_FLOAT4, VES_TEXTURE_COORDINATES, 246 thisVertexData->vertexDeclaration->getNextFreeTextureCoordinate() ).getSize(); 247 thisVertexData->vertexDeclaration->addElement( newSource, offset, VET_FLOAT4, VES_TEXTURE_COORDINATES, 248 thisVertexData->vertexDeclaration->getNextFreeTextureCoordinate() ).getSize(); 249 //Add two floats of padding here? or earlier? 250 //If not using bone matrix lookup, is it ok that it is 8 bytes since divides evenly into 16 251 252 } 253 254 //Create our own vertex buffer 255 mInstanceVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 256 thisVertexData->vertexDeclaration->getVertexSize(newSource), 257 mInstancesPerBatch, 258 HardwareBuffer::HBU_STATIC_WRITE_ONLY ); 259 thisVertexData->vertexBufferBinding->setBinding( newSource, mInstanceVertexBuffer ); 260 261 //Mark this buffer as instanced 262 mInstanceVertexBuffer->setIsInstanceData( true ); 263 mInstanceVertexBuffer->setInstanceDataStepRate( 1 ); 264 265 updateInstanceDataBuffer(true, NULL); 266 } 267 268 //updates the vertex buffer containing the per instance data updateInstanceDataBuffer(bool isFirstTime,Camera * currentCamera)269 size_t InstanceBatchHW_VTF::updateInstanceDataBuffer(bool isFirstTime, Camera* currentCamera) 270 { 271 size_t visibleEntityCount = 0; 272 bool useMatrixLookup = useBoneMatrixLookup(); 273 if (isFirstTime ^ useMatrixLookup) 274 { 275 //update the mTransformLookupNumber value in the entities if needed 276 updateSharedLookupIndexes(); 277 278 const float texWidth = static_cast<float>(mMatrixTexture->getWidth()); 279 const float texHeight = static_cast<float>(mMatrixTexture->getHeight()); 280 281 //Calculate the texel offsets to correct them offline 282 //Awkwardly enough, the offset is needed in OpenGL too 283 Vector2 texelOffsets; 284 //RenderSystem *renderSystem = Root::getSingleton().getRenderSystem(); 285 texelOffsets.x = /*renderSystem->getHorizontalTexelOffset()*/ -0.5f / texWidth; 286 texelOffsets.y = /*renderSystem->getHorizontalTexelOffset()*/ -0.5f / texHeight; 287 288 float *thisVec = static_cast<float*>(mInstanceVertexBuffer->lock(HardwareBuffer::HBL_DISCARD)); 289 290 const size_t maxPixelsPerLine = std::min( static_cast<size_t>(mMatrixTexture->getWidth()), mMaxFloatsPerLine >> 2 ); 291 292 //Calculate UV offsets, which change per instance 293 for( size_t i=0; i<mInstancesPerBatch; ++i ) 294 { 295 InstancedEntity* entity = useMatrixLookup ? mInstancedEntities[i] : NULL; 296 if //Update if we are not using a lookup bone matrix method. In this case the function will 297 //be called only once 298 (!useMatrixLookup || 299 //Update if we are in the visible range of the camera (for look up bone matrix method 300 //and static mode). 301 (entity->findVisible(currentCamera))) 302 { 303 size_t matrixIndex = useMatrixLookup ? entity->mTransformLookupNumber : i; 304 size_t instanceIdx = matrixIndex * mMatricesPerInstance * mRowLength; 305 *thisVec = ((instanceIdx % maxPixelsPerLine) / texWidth) - (float)(texelOffsets.x); 306 *(thisVec + 1) = ((instanceIdx / maxPixelsPerLine) / texHeight) - (float)(texelOffsets.y); 307 thisVec += 2; 308 309 if (useMatrixLookup) 310 { 311 const Matrix4& mat = entity->_getParentNodeFullTransform(); 312 *(thisVec) = static_cast<float>( mat[0][0] ); 313 *(thisVec + 1) = static_cast<float>( mat[0][1] ); 314 *(thisVec + 2) = static_cast<float>( mat[0][2] ); 315 *(thisVec + 3) = static_cast<float>( mat[0][3] ); 316 *(thisVec + 4) = static_cast<float>( mat[1][0] ); 317 *(thisVec + 5) = static_cast<float>( mat[1][1] ); 318 *(thisVec + 6) = static_cast<float>( mat[1][2] ); 319 *(thisVec + 7) = static_cast<float>( mat[1][3] ); 320 *(thisVec + 8) = static_cast<float>( mat[2][0] ); 321 *(thisVec + 9) = static_cast<float>( mat[2][1] ); 322 *(thisVec + 10)= static_cast<float>( mat[2][2] ); 323 *(thisVec + 11)= static_cast<float>( mat[2][3] ); 324 if(currentCamera && mManager->getCameraRelativeRendering()) // && useMatrixLookup 325 { 326 const Vector3 &cameraRelativePosition = currentCamera->getDerivedPosition(); 327 *(thisVec + 3) -= static_cast<float>( cameraRelativePosition.x ); 328 *(thisVec + 7) -= static_cast<float>( cameraRelativePosition.y ); 329 *(thisVec + 11) -= static_cast<float>( cameraRelativePosition.z ); 330 } 331 thisVec += 12; 332 } 333 ++visibleEntityCount; 334 } 335 } 336 337 mInstanceVertexBuffer->unlock(); 338 } 339 else 340 { 341 visibleEntityCount = mInstancedEntities.size(); 342 } 343 return visibleEntityCount; 344 } 345 346 //----------------------------------------------------------------------- checkSubMeshCompatibility(const SubMesh * baseSubMesh)347 bool InstanceBatchHW_VTF::checkSubMeshCompatibility( const SubMesh* baseSubMesh ) 348 { 349 //Max number of texture coordinates is _usually_ 8, we need at least 2 available 350 unsigned short neededTextureCoord = 2; 351 if (useBoneMatrixLookup()) 352 { 353 //we need another 3 for the unique world transform of each instanced entity 354 neededTextureCoord += 3; 355 } 356 if( baseSubMesh->vertexData->vertexDeclaration->getNextFreeTextureCoordinate() > 8 - neededTextureCoord ) 357 { 358 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, 359 String("Given mesh must have at least ") + 360 StringConverter::toString(neededTextureCoord) + "free TEXCOORDs", 361 "InstanceBatchHW_VTF::checkSubMeshCompatibility"); 362 } 363 364 return InstanceBatch::checkSubMeshCompatibility( baseSubMesh ); 365 } 366 //----------------------------------------------------------------------- calculateMaxNumInstances(const SubMesh * baseSubMesh,uint16 flags) const367 size_t InstanceBatchHW_VTF::calculateMaxNumInstances( 368 const SubMesh *baseSubMesh, uint16 flags ) const 369 { 370 size_t retVal = 0; 371 372 RenderSystem *renderSystem = Root::getSingleton().getRenderSystem(); 373 const RenderSystemCapabilities *capabilities = renderSystem->getCapabilities(); 374 375 //VTF & HW Instancing must be supported 376 if( capabilities->hasCapability( RSC_VERTEX_BUFFER_INSTANCE_DATA ) && 377 capabilities->hasCapability( RSC_VERTEX_TEXTURE_FETCH ) ) 378 { 379 //TODO: Check PF_FLOAT32_RGBA is supported (should be, since it was the 1st one) 380 const size_t numBones = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() ); 381 382 const size_t maxUsableWidth = c_maxTexWidthHW - (c_maxTexWidthHW % (numBones * mRowLength)); 383 384 //See InstanceBatchHW::calculateMaxNumInstances for the 65535 385 retVal = std::min<size_t>( 65535, maxUsableWidth * c_maxTexHeightHW / mRowLength / numBones ); 386 387 if( flags & IM_VTFBESTFIT ) 388 { 389 size_t numUsedSkeletons = mInstancesPerBatch; 390 if (flags & IM_VTFBONEMATRIXLOOKUP) 391 numUsedSkeletons = std::min<size_t>(getMaxLookupTableInstances(), numUsedSkeletons); 392 const size_t instancesPerBatch = std::min( retVal, numUsedSkeletons ); 393 //Do the same as in createVertexTexture(), but changing c_maxTexWidthHW for maxUsableWidth 394 const size_t numWorldMatrices = instancesPerBatch * numBones; 395 396 size_t texWidth = std::min<size_t>( numWorldMatrices * mRowLength, maxUsableWidth ); 397 size_t texHeight = numWorldMatrices * mRowLength / maxUsableWidth; 398 399 const size_t remainder = (numWorldMatrices * mRowLength) % maxUsableWidth; 400 401 if( remainder && texHeight > 0 ) 402 retVal = static_cast<size_t>(texWidth * texHeight / (float)mRowLength / (float)(numBones)); 403 } 404 } 405 406 return retVal; 407 } 408 //----------------------------------------------------------------------- updateVertexTexture(Camera * currentCamera)409 size_t InstanceBatchHW_VTF::updateVertexTexture( Camera *currentCamera ) 410 { 411 size_t renderedInstances = 0; 412 bool useMatrixLookup = useBoneMatrixLookup(); 413 if (useMatrixLookup) 414 { 415 //if we are using bone matrix look up we have to update the instance buffer for the 416 //vertex texture to be relevant 417 418 //also note that in this case the number of instances to render comes directly from the 419 //updateInstanceDataBuffer() function, not from this function. 420 renderedInstances = updateInstanceDataBuffer(false, currentCamera); 421 } 422 423 424 mDirtyAnimation = false; 425 426 //Now lock the texture and copy the 4x3 matrices! 427 mMatrixTexture->getBuffer()->lock( HardwareBuffer::HBL_DISCARD ); 428 const PixelBox &pixelBox = mMatrixTexture->getBuffer()->getCurrentLock(); 429 430 float *pSource = static_cast<float*>(pixelBox.data); 431 432 InstancedEntityVec::const_iterator itor = mInstancedEntities.begin(); 433 434 vector<bool>::type writtenPositions(getMaxLookupTableInstances(), false); 435 436 size_t floatPerEntity = mMatricesPerInstance * mRowLength * 4; 437 size_t entitiesPerPadding = (size_t)(mMaxFloatsPerLine / floatPerEntity); 438 439 size_t instanceCount = mInstancedEntities.size(); 440 size_t updatedInstances = 0; 441 442 float* transforms = NULL; 443 //If using dual quaternions, write 3x4 matrices to a temporary buffer, then convert to dual quaternions 444 if(mUseBoneDualQuaternions) 445 { 446 transforms = mTempTransformsArray3x4; 447 } 448 449 for(size_t i = 0 ; i < instanceCount ; ++i) 450 { 451 InstancedEntity* entity = mInstancedEntities[i]; 452 size_t textureLookupPosition = updatedInstances; 453 if (useMatrixLookup) 454 { 455 textureLookupPosition = entity->mTransformLookupNumber; 456 } 457 //Check that we are not using a lookup matrix or that we have not already written 458 //The bone data 459 if (((!useMatrixLookup) || !writtenPositions[entity->mTransformLookupNumber]) && 460 //Cull on an individual basis, the less entities are visible, the less instances we draw. 461 //No need to use null matrices at all! 462 (entity->findVisible( currentCamera ))) 463 { 464 float* pDest = pSource + floatPerEntity * textureLookupPosition + 465 (size_t)(textureLookupPosition / entitiesPerPadding) * mWidthFloatsPadding; 466 467 if(!mUseBoneDualQuaternions) 468 { 469 transforms = pDest; 470 } 471 472 if( mMeshReference->hasSkeleton() ) 473 mDirtyAnimation |= entity->_updateAnimation(); 474 475 size_t floatsWritten = entity->getTransforms3x4( transforms ); 476 477 if( !useMatrixLookup && mManager->getCameraRelativeRendering() ) 478 makeMatrixCameraRelative3x4( transforms, floatsWritten ); 479 480 if(mUseBoneDualQuaternions) 481 { 482 convert3x4MatricesToDualQuaternions(transforms, floatsWritten / 12, pDest); 483 } 484 485 if (useMatrixLookup) 486 { 487 writtenPositions[entity->mTransformLookupNumber] = true; 488 } 489 else 490 { 491 ++updatedInstances; 492 } 493 } 494 495 ++itor; 496 } 497 498 if (!useMatrixLookup) 499 { 500 renderedInstances = updatedInstances; 501 } 502 503 mMatrixTexture->getBuffer()->unlock(); 504 505 return renderedInstances; 506 } 507 //----------------------------------------------------------------------- _boundsDirty(void)508 void InstanceBatchHW_VTF::_boundsDirty(void) 509 { 510 //Don't update if we're static, but still mark we're dirty 511 if( !mBoundsDirty && !mKeepStatic && mCreator) 512 mCreator->_addDirtyBatch( this ); 513 mBoundsDirty = true; 514 } 515 //----------------------------------------------------------------------- setStaticAndUpdate(bool bStatic)516 void InstanceBatchHW_VTF::setStaticAndUpdate( bool bStatic ) 517 { 518 //We were dirty but didn't update bounds. Do it now. 519 if( mKeepStatic && mBoundsDirty ) 520 mCreator->_addDirtyBatch( this ); 521 522 mKeepStatic = bStatic; 523 if( mKeepStatic ) 524 { 525 //One final update, since there will be none from now on 526 //(except further calls to this function). Pass NULL because 527 //we want to include only those who were added to the scene 528 //but we don't want to perform culling 529 mRenderOperation.numberOfInstances = updateVertexTexture( 0 ); 530 } 531 } 532 //----------------------------------------------------------------------- _updateRenderQueue(RenderQueue * queue)533 void InstanceBatchHW_VTF::_updateRenderQueue( RenderQueue* queue ) 534 { 535 if( !mKeepStatic ) 536 { 537 //Completely override base functionality, since we don't cull on an "all-or-nothing" basis 538 if( (mRenderOperation.numberOfInstances = updateVertexTexture( mCurrentCamera )) ) 539 queue->addRenderable( this, mRenderQueueID, mRenderQueuePriority ); 540 } 541 else 542 { 543 if( mManager->getCameraRelativeRendering() ) 544 { 545 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, "Camera-relative rendering is incompatible" 546 " with Instancing's static batches. Disable at least one of them", 547 "InstanceBatch::_updateRenderQueue"); 548 } 549 550 //Don't update when we're static 551 if( mRenderOperation.numberOfInstances ) 552 queue->addRenderable( this, mRenderQueueID, mRenderQueuePriority ); 553 } 554 } 555 } 556