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