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