Rigs of Rods 2026.01
Soft-body Physics Simulation
Loading...
Searching...
No Matches
BatchedGeometry.cpp
Go to the documentation of this file.
1/*-------------------------------------------------------------------------------------
2Copyright (c) 2006 John Judnich
3
4This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
5Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
61. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
72. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
83. This notice may not be removed or altered from any source distribution.
9-------------------------------------------------------------------------------------*/
10
11//BatchedGeometry.h
12//A "lightweight" version of Ogre::StaticGeometry, which gives you a little more control
13//over the batch materials, etc.
14//-------------------------------------------------------------------------------------
15
16#include <OgreRoot.h>
17#include <OgreRenderSystem.h>
18#include <OgreCamera.h>
19#include <OgreVector3.h>
20#include <OgreQuaternion.h>
21#include <OgreSceneNode.h>
22#include <OgreString.h>
23#include <OgreStringConverter.h>
24#include <OgreEntity.h>
25#include <OgreSubMesh.h>
26#include <OgreSubEntity.h>
27#include <OgreMesh.h>
28#include <OgreMeshManager.h>
29#include <OgreHardwareBufferManager.h>
30#include <OgreHardwareBuffer.h>
31#include <OgreMaterialManager.h>
32#include <OgreMaterial.h>
33#include <OgreTechnique.h>
34#include <string>
35
36#include "BatchedGeometry.h"
37#include "PagedGeometry.h"
38
39using namespace Ogre;
40using namespace Forests;
41
42
57const size_t BatchedGeometry::s_vertexType2Size[VET_COLOUR_ABGR + 1] = {
58 VertexElement::getTypeSize(VET_FLOAT1),
59 VertexElement::getTypeSize(VET_FLOAT2),
60 VertexElement::getTypeSize(VET_FLOAT3),
61 VertexElement::getTypeSize(VET_FLOAT4),
62 VertexElement::getTypeSize(VET_COLOUR),
63 VertexElement::getTypeSize(VET_SHORT1),
64 VertexElement::getTypeSize(VET_SHORT2),
65 VertexElement::getTypeSize(VET_SHORT3),
66 VertexElement::getTypeSize(VET_SHORT4),
67 VertexElement::getTypeSize(VET_UBYTE4),
68 VertexElement::getTypeSize(VET_COLOUR_ARGB),
69 VertexElement::getTypeSize(VET_COLOUR_ABGR)
70};
71
72
73//-------------------------------------------------------------------------------------
75BatchedGeometry::BatchedGeometry(Ogre::SceneManager *mgr, Ogre::SceneNode *rootSceneNode) :
76m_fRadius (0.f),
77m_fMinDistanceSquared(0.f),
78m_pSceneMgr (mgr),
79m_pSceneNode (NULL),
80m_pParentSceneNode (rootSceneNode),
81m_bWithinFarDistance (false),
82m_Built (false),
83m_vecCenter (Ogre::Vector3::ZERO),
84m_BoundsUndefined (true)
85{
86 assert(rootSceneNode);
87}
88
89//-----------------------------------------------------------------------------
95
96//-----------------------------------------------------------------------------
98const Ogre::String& BatchedGeometry::getMovableType() const
99{
100 static const Ogre::String strType = "BatchedGeometry";
101 return strType;
102}
103
104
105//-----------------------------------------------------------------------------
107void BatchedGeometry::addEntity(Entity *ent, const Vector3 &position,
108 const Quaternion &orientation,
109 const Vector3 &scale,
110 const Ogre::ColourValue &color)
111{
112 const MeshPtr &mesh = ent->getMesh();
113
114 //If shared vertex data is used, extract into non-shared data
116
117 //For each subentity
118 for (uint32 i = 0; i < ent->getNumSubEntities(); ++i)
119 {
120 //Get the subentity
121 SubEntity *subEntity = ent->getSubEntity(i);
122 SubMesh *subMesh = subEntity->getSubMesh();
123
124 //Generate a format string that uniquely identifies this material & vertex/index format
125 if (subMesh->vertexData == NULL)
126 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "SubMesh vertex data not found!", "BatchedGeometry::addEntity()");
127 String formatStr = getFormatString(subEntity);
128
129 //If a batch using an identical format exists...
130 SubBatch *batch = 0;
131 TSubBatchMap::iterator batchIter = m_mapSubBatch.find(formatStr);
132 if (batchIter != m_mapSubBatch.end())
133 batch = batchIter->second; //Use the batch
134 else // Otherwise create a new batch
135 {
136 batch = new SubBatch(this, subEntity);
137 m_mapSubBatch.insert(std::pair<String, SubBatch*>(formatStr, batch));
138 }
139
140 //Now add the submesh to the compatible batch
141 batch->addSubEntity(subEntity, position, orientation, scale, color);
142 }
143
144 //Update bounding box
145 Matrix4 mat(orientation);
146 mat.setScale(scale);
147 AxisAlignedBox entBounds = ent->getBoundingBox();
148 entBounds.transform(mat);
149
151 {
152 m_boundsAAB.setMinimum(entBounds.getMinimum() + position);
153 m_boundsAAB.setMaximum(entBounds.getMaximum() + position);
154 m_BoundsUndefined = false;
155 }
156 else
157 {
158 Vector3 min = m_boundsAAB.getMinimum();
159 Vector3 max = m_boundsAAB.getMaximum();
160 min.makeFloor(entBounds.getMinimum() + position);
161 max.makeCeil(entBounds.getMaximum() + position);
162 m_boundsAAB.setMinimum(min);
163 m_boundsAAB.setMaximum(max);
164 }
165}
166
167
168//-----------------------------------------------------------------------------
170uint32 CountUsedVertices(IndexData *id, std::map<uint32, uint32> &ibmap)
171{
172 uint32 i, count;
173 switch (id->indexBuffer->getType()) {
174 case HardwareIndexBuffer::IT_16BIT:
175 {
176 uint16 *data = (uint16*)id->indexBuffer->lock(id->indexStart * sizeof(uint16),
177 id->indexCount * sizeof(uint16), HardwareBuffer::HBL_READ_ONLY);
178
179 for (i = 0; i < id->indexCount; i++) {
180 uint16 index = data[i];
181 if (ibmap.find(index) == ibmap.end())
182 {
183 // use separate lines to avoid undefined compiler behavior.
184 // see: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf?fbclid=IwAR2Wp4bQWvl0O9t7kBIXeiRsOxwxU8bttpes-gK71x_2j0ABtzGD5mcoF_c
185 uint32 size = (uint32)(ibmap.size());
186 ibmap[index] = size;
187 }
188 }
189 count = (uint32)ibmap.size();
190 id->indexBuffer->unlock();
191 }
192 break;
193
194 case HardwareIndexBuffer::IT_32BIT:
195 {
196 uint32 *data = (uint32*)id->indexBuffer->lock(id->indexStart * sizeof(uint32),
197 id->indexCount * sizeof(uint32), HardwareBuffer::HBL_READ_ONLY);
198
199 for (i = 0; i < id->indexCount; i++) {
200 uint32 index = data[i];
201 if (ibmap.find(index) == ibmap.end())
202 {
203 // use separate lines to avoid undefined compiler behavior.
204 // see: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0145r3.pdf?fbclid=IwAR2Wp4bQWvl0O9t7kBIXeiRsOxwxU8bttpes-gK71x_2j0ABtzGD5mcoF_c
205 uint32 size = (uint32)(ibmap.size());
206 ibmap[index] = size;
207 }
208 }
209 count = (uint32)ibmap.size();
210 id->indexBuffer->unlock();
211 }
212 break;
213
214 default:
215 throw new Ogre::Exception(0, "Unknown index buffer type", "Converter.cpp::CountVertices");
216 break;
217 }
218
219 return count;
220}
221
222
223//-----------------------------------------------------------------------------
225void BatchedGeometry::extractVertexDataFromShared(const Ogre::MeshPtr &mesh)
226{
227 if (!mesh || !mesh->sharedVertexData)
228 return;
229
230 Mesh::SubMeshIterator subMeshIterator = mesh->getSubMeshIterator();
231
232 // Get shared vertex data
233 VertexData *oldVertexData = mesh->sharedVertexData;
234
235 while (subMeshIterator.hasMoreElements()) {
236 SubMesh *subMesh = subMeshIterator.getNext();
237
238 // Get index data
239 IndexData *indexData = subMesh->indexData;
240 HardwareIndexBufferSharedPtr ib = indexData->indexBuffer;
241
242 // Create new nonshared vertex data
243 std::map<uint32, uint32> indicesMap;
244 VertexData *newVertexData = new VertexData();
245 newVertexData->vertexCount = CountUsedVertices(indexData, indicesMap);
246 //delete newVertexData->vertexDeclaration;
247 newVertexData->vertexDeclaration = oldVertexData->vertexDeclaration->clone();
248
249 // Create new vertex buffers
250 uint32 buffersCount = (uint32)oldVertexData->vertexBufferBinding->getBufferCount();
251 for (uint32 bufferIndex = 0; bufferIndex < buffersCount; bufferIndex++) {
252
253 // Lock shared vertex buffer
254 HardwareVertexBufferSharedPtr oldVertexBuffer = oldVertexData->vertexBufferBinding->getBuffer(bufferIndex);
255 size_t vertexSize = oldVertexBuffer->getVertexSize();
256 uint8 *oldLock = (uint8*)oldVertexBuffer->lock(0, oldVertexData->vertexCount * vertexSize, HardwareBuffer::HBL_READ_ONLY);
257
258 // Create and lock nonshared vertex buffer
259 HardwareVertexBufferSharedPtr newVertexBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
260 vertexSize, newVertexData->vertexCount, oldVertexBuffer->getUsage(), oldVertexBuffer->hasShadowBuffer());
261 uint8 *newLock = (uint8*)newVertexBuffer->lock(0, newVertexData->vertexCount * vertexSize, HardwareBuffer::HBL_NORMAL);
262
263 // Copy vertices from shared vertex buffer into nonshared vertex buffer
264 std::map<uint32, uint32>::iterator i, iend = indicesMap.end();
265 for (i = indicesMap.begin(); i != iend; i++) {
266 memcpy(newLock + vertexSize * i->second, oldLock + vertexSize * i->first, vertexSize);
267 }
268
269 // Unlock vertex buffers
270 oldVertexBuffer->unlock();
271 newVertexBuffer->unlock();
272
273 // Bind new vertex buffer
274 newVertexData->vertexBufferBinding->setBinding(bufferIndex, newVertexBuffer);
275 }
276
277 // Re-create index buffer
278 switch (indexData->indexBuffer->getType()) {
279 case HardwareIndexBuffer::IT_16BIT:
280 {
281 uint16 *data = (uint16*)indexData->indexBuffer->lock(indexData->indexStart * sizeof(uint16),
282 indexData->indexCount * sizeof(uint16), HardwareBuffer::HBL_NORMAL);
283
284 for (uint32 i = 0; i < indexData->indexCount; i++) {
285 data[i] = (uint16)indicesMap[data[i]];
286 }
287
288 indexData->indexBuffer->unlock();
289 }
290 break;
291
292 case HardwareIndexBuffer::IT_32BIT:
293 {
294 uint32 *data = (uint32*)indexData->indexBuffer->lock(indexData->indexStart * sizeof(uint32),
295 indexData->indexCount * sizeof(uint32), HardwareBuffer::HBL_NORMAL);
296
297 for (uint32 i = 0; i < indexData->indexCount; i++) {
298 data[i] = (uint32)indicesMap[data[i]];
299 }
300
301 indexData->indexBuffer->unlock();
302 }
303 break;
304
305 default:
306 throw new Ogre::Exception(0, "Unknown index buffer type", "Converter.cpp::CountVertices");
307 break;
308 }
309
310 // Store new attributes
311 subMesh->useSharedVertices = false;
312 subMesh->vertexData = newVertexData;
313 }
314
315 // Release shared vertex data
316 delete mesh->sharedVertexData;
317 mesh->sharedVertexData = NULL;
318}
319
320
321//-----------------------------------------------------------------------------
324{
325 static char buf[1024];
326 // add materialname and buffer type
327 int countWritten = sprintf(buf, "%s|%d", ent->getMaterialName().c_str(), ent->getSubMesh()->indexData->indexBuffer->getType());
328
329 // now add vertex decl
330 const VertexDeclaration::VertexElementList &elemList = ent->getSubMesh()->vertexData->vertexDeclaration->getElements();
331 for (VertexDeclaration::VertexElementList::const_iterator i = elemList.begin(), iend = elemList.end(); i != iend; ++i)
332 {
333 const VertexElement &el = *i;
334 countWritten += sprintf(buf + countWritten, "|%d|%d|%d", el.getSource(), el.getSemantic(), el.getType());
335 }
336
337 return buf;
338}
339
340
341//-----------------------------------------------------------------------------
344{
346 if (m_Built)
347 OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "Invalid call to build() - geometry is already batched (call clear() first)", "BatchedGeometry::GeomBatch::build()");
348
349 if (!m_mapSubBatch.empty())
350 {
351 // Finish bounds information
352 m_vecCenter = m_boundsAAB.getCenter(); // Calculate bounds center
353 m_boundsAAB.setMinimum(m_boundsAAB.getMinimum() - m_vecCenter); // Center the bounding box
354 m_boundsAAB.setMaximum(m_boundsAAB.getMaximum() - m_vecCenter); // Center the bounding box
355 m_fRadius = m_boundsAAB.getMaximum().length(); // Calculate BB radius
356
357 // Create scene node
358 m_pSceneNode = m_pParentSceneNode->createChildSceneNode(m_vecCenter);
359
360 //Build each batch
361 for (TSubBatchMap::iterator i = m_mapSubBatch.begin(), iend = m_mapSubBatch.end(); i != iend; ++i)
362 i->second->build();
363
364 m_pSceneNode->attachObject(this); // Attach the batch to the scene node
365
366 //Debug
367 //sceneNode->showBoundingBox(true);
368
369 m_Built = true;
370 }
371
372}
373
374
375//-----------------------------------------------------------------------------
378{
379 //Remove the batch from the scene
380 if (m_pSceneNode)
381 {
382 m_pSceneNode->removeAllChildren();
383 if (m_pSceneNode->getParent())
384 m_pSceneNode->getParentSceneNode()->removeAndDestroyChild(m_pSceneNode);
385 else
386 m_pSceneMgr->destroySceneNode(m_pSceneNode);
387
388 m_pSceneNode = 0;
389 }
390
391 //Reset bounds information
392 m_BoundsUndefined = true;
393 m_vecCenter = Vector3::ZERO;
394 m_fRadius = 0.f;
395
396 //Delete each batch
397 for (TSubBatchMap::iterator i = m_mapSubBatch.begin(), iend = m_mapSubBatch.end(); i != iend; ++i)
398 delete i->second;
399 m_mapSubBatch.clear();
400
401 m_Built = false;
402}
403
404
405//-----------------------------------------------------------------------------
408{
409 assert(isVisible() && "Ogre core code must detect that this MovableObject invisible");
410
411 // SVA speed up adding
412 Ogre::RenderQueueGroup *rqg = queue->getQueueGroup(getRenderQueueGroup());
413 for (TSubBatchMap::const_iterator i = m_mapSubBatch.begin(), iend = m_mapSubBatch.end(); i != iend; ++i)
414 i->second->addSelfToRenderQueue(rqg);
415
417 //if (isVisible()){
418 // //Ask each batch to add itself to the render queue if appropriate
419 // for (SubBatchMap::iterator i = subBatchMap.begin(); i != subBatchMap.end(); ++i){
420 // i->second->addSelfToRenderQueue(queue, getRenderQueueGroup());
421 // }
422 //}
423}
424
425
426//-----------------------------------------------------------------------------
429{
430 return mVisible && m_bWithinFarDistance;
431}
432
433
434//-----------------------------------------------------------------------------
437{
438 if (getRenderingDistance() == Ogre::Real(0.))
440 else
441 {
442 //Calculate camera distance
443 Vector3 camVec = _convertToLocal(cam->getDerivedPosition()) - m_vecCenter;
444 Real centerDistanceSquared = camVec.squaredLength();
445 m_fMinDistanceSquared = std::max(Ogre::Real(0.), centerDistanceSquared - (m_fRadius * m_fRadius));
446 //Note: centerDistanceSquared measures the distance between the camera and the center of the GeomBatch,
447 //while minDistanceSquared measures the closest distance between the camera and the closest edge of the
448 //geometry's bounding sphere.
449
450 //Determine whether the BatchedGeometry is within the far rendering distance
451 m_bWithinFarDistance = m_fMinDistanceSquared <= Math::Sqr(getRenderingDistance());
452 }
453}
454
455
456//-----------------------------------------------------------------------------
458Ogre::Vector3 BatchedGeometry::_convertToLocal(const Vector3 &globalVec) const
459{
460 //Convert from the given global position to the local coordinate system of the parent scene node.
461 return (m_pParentSceneNode->getOrientation().Inverse() * globalVec);
462}
463
464
465
466//=============================================================================
467// BatchedGeometry::SubBatch implementation
468//=============================================================================
469
470
471//-----------------------------------------------------------------------------
474m_pBestTechnique (NULL),
475m_pVertexData (0),
476m_pIndexData (0),
477m_Built (false),
478m_RequireVertexColors (false),
479m_pSubMesh (0),
480m_pParentGeom (parent)
481{
482 assert(ent);
483 m_pSubMesh = ent->getSubMesh();
484
485 const Ogre::MaterialPtr &parentMaterial = ent->getMaterial();
486 if (!parentMaterial)
487 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Empty parent material");
488
489 // SVA clone material
490 // This function is used to make a single clone of materials used, since the materials
491 // will be modified by the batch system (and it wouldn't be good to modify the original materials
492 // that the user may be using somewhere else).
493 {
494 Ogre::String newName = parentMaterial->getName() + "_Batched";
495 m_ptrMaterial = Ogre::static_pointer_cast<Material>(MaterialManager::getSingleton().getByName(newName, parentMaterial->getGroup()));
496 if (!m_ptrMaterial)
497 m_ptrMaterial = parentMaterial->clone(newName);
498 }
499
500 //Setup vertex/index data structure
501 m_pVertexData = m_pSubMesh->vertexData->clone(false);
502 m_pIndexData = m_pSubMesh->indexData->clone(false);
503
504 //Remove blend weights from vertex format
505 const VertexElement* blendIndices = m_pVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
506 const VertexElement* blendWeights = m_pVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
507 if (blendIndices && blendWeights)
508 {
509 //Check for format errors
510 assert(blendIndices->getSource() == blendWeights->getSource()
511 && "Blend indices and weights should be in the same buffer");
512 assert(blendIndices->getSize() + blendWeights->getSize() == m_pVertexData->vertexBufferBinding->getBuffer(blendIndices->getSource())->getVertexSize()
513 && "Blend indices and blend buffers should have buffer to themselves!");
514
515 //Remove the blend weights
516 m_pVertexData->vertexBufferBinding->unsetBinding(blendIndices->getSource());
517 m_pVertexData->vertexDeclaration->removeElement(VES_BLEND_INDICES);
518 m_pVertexData->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
519 m_pVertexData->closeGapsInBindings();
520 }
521
522 //Reset vertex/index count
523 m_pVertexData->vertexStart = 0;
524 m_pVertexData->vertexCount = 0;
525 m_pIndexData->indexStart = 0;
526 m_pIndexData->indexCount = 0;
527}
528
529
530//-----------------------------------------------------------------------------
533{
534 clear();
535
536 OGRE_DELETE m_pVertexData;
537 OGRE_DELETE m_pIndexData;
538}
539
540
541//-----------------------------------------------------------------------------
543void BatchedGeometry::SubBatch::addSubEntity(SubEntity *ent, const Vector3 &position,
544 const Quaternion &orientation, const Vector3 &scale,
545 const Ogre::ColourValue &color, void* userData)
546{
547 assert(!m_Built);
548
549 //Add this submesh to the queue
550 QueuedMesh newMesh(ent->getSubMesh(), position, orientation, scale, color, userData);
551 if (color != ColourValue::White)
552 {
553 m_RequireVertexColors = true;
554 VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();
555 switch (format)
556 {
557 case VET_COLOUR_ARGB:
558 std::swap(newMesh.color.r, newMesh.color.b);
559 break;
560 case VET_COLOUR_ABGR:
561 break;
562 default:
563 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Unknown RenderSystem color format");
564 break;
565 }
566 }
567
568 m_queueMesh.push_back(newMesh);
569
570 //Increment the vertex/index count so the buffers will have room for this mesh
571 m_pVertexData->vertexCount += newMesh.subMesh->vertexData->vertexCount;
572 m_pIndexData->indexCount += newMesh.subMesh->indexData->indexCount;
573}
574
575
576//-----------------------------------------------------------------------------
579{
580 assert(!m_Built);
581
582 HardwareIndexBuffer::IndexType srcIndexType = m_pSubMesh->indexData->indexBuffer->getType();
583 HardwareIndexBuffer::IndexType destIndexType = // type of index buffer
584 m_pVertexData->vertexCount > 0xFFFF || srcIndexType == HardwareIndexBuffer::IT_32BIT ?
585 HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT;
586
587 //Allocate the index buffer
588 m_pIndexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
589 destIndexType, m_pIndexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
590
591 //Lock the index buffer
592 uint32 *indexBuffer32;
593 uint16 *indexBuffer16;
594 if (destIndexType == HardwareIndexBuffer::IT_32BIT)
595 indexBuffer32 = static_cast<uint32*>(m_pIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
596 else
597 indexBuffer16 = static_cast<uint16*>(m_pIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
598
599 //Allocate & lock the vertex buffers
600 std::vector<uchar*> vertexBuffers;
601 std::vector<VertexDeclaration::VertexElementList> vertexBufferElements;
602
603 VertexBufferBinding *vertBinding = m_pVertexData->vertexBufferBinding;
604 VertexDeclaration *vertDecl = m_pVertexData->vertexDeclaration;
605
606 for (Ogre::ushort i = 0; i < vertBinding->getBufferCount(); ++i)
607 {
608 HardwareVertexBufferSharedPtr buffer = HardwareBufferManager::getSingleton().createVertexBuffer(
609 vertDecl->getVertexSize(i), m_pVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
610 vertBinding->setBinding(i, buffer);
611
612 vertexBuffers.push_back(static_cast<uchar*>(buffer->lock(HardwareBuffer::HBL_DISCARD)));
613 vertexBufferElements.push_back(vertDecl->findElementsBySource(i));
614 }
615
616 //If no vertex colors are used, make sure the final batch includes them (so the shade values work)
617 if (m_RequireVertexColors)
618 {
619 if (!m_pVertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE))
620 {
621 Ogre::ushort i = (Ogre::ushort)vertBinding->getBufferCount();
622 vertDecl->addElement(i, 0, VET_COLOUR, VES_DIFFUSE);
623
624 HardwareVertexBufferSharedPtr buffer = HardwareBufferManager::getSingleton().createVertexBuffer(
625 vertDecl->getVertexSize(i), m_pVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
626 vertBinding->setBinding(i, buffer);
627
628 vertexBuffers.push_back(static_cast<uchar*>(buffer->lock(HardwareBuffer::HBL_DISCARD)));
629 vertexBufferElements.push_back(vertDecl->findElementsBySource(i));
630 }
631
632 m_ptrMaterial->getTechnique(0)->getPass(0)->setVertexColourTracking(TVC_AMBIENT);
633 }
634
635 //For each queued mesh...
636 size_t indexOffset = 0;
637 for (size_t iMesh = 0, cntMeshes = m_queueMesh.size(); iMesh < cntMeshes; ++iMesh)
638 {
639 const QueuedMesh &queuedMesh = m_queueMesh[iMesh]; // <-- std::vector
640
641 // If orientation identity we can skip many operation in vertex processing
642 if (queuedMesh.orientation == Ogre::Quaternion::IDENTITY)
643 _buildIdentiryOrientation(queuedMesh, m_pParentGeom->m_vecCenter, vertexBufferElements, vertexBuffers, m_pVertexData);
644 else
645 _buildFullTransform(queuedMesh, m_pParentGeom->m_vecCenter, vertexBufferElements, vertexBuffers, m_pVertexData);
646
647 //Copy mesh index data into the index buffer
648 Ogre::IndexData *sourceIndexData = queuedMesh.subMesh->indexData;
649
650 if (srcIndexType == HardwareIndexBuffer::IT_32BIT)
651 {
652 sourceIndexData->indexBuffer->readData(
653 sourceIndexData->indexStart * sizeof(uint32),
654 sourceIndexData->indexCount * sizeof(uint32), indexBuffer32);
655 uint32 *updateEnd = indexBuffer32 + sourceIndexData->indexCount;
656
657 // add indexOffset
658 while (indexBuffer32 != updateEnd)
659 *indexBuffer32++ += indexOffset;
660 }
661 else
662 {
663 if (destIndexType == HardwareIndexBuffer::IT_32BIT)
664 {
665 //-- Convert 16 bit to 32 bit indices --
666 std::vector<uint16> tmp(sourceIndexData->indexCount);
667 //Lock the input buffer
668 sourceIndexData->indexBuffer->readData(sourceIndexData->indexStart*sizeof(uint16), tmp.size(), tmp.data());
669 uint16 *source = tmp.data();
670 uint16 *sourceEnd = source + sourceIndexData->indexCount;
671
672 //And copy it to the output buffer
673 while (source != sourceEnd)
674 *indexBuffer32++ = (*source++ + indexOffset);
675 }
676 else
677 {
678 sourceIndexData->indexBuffer->readData(
679 sourceIndexData->indexStart * sizeof(uint16),
680 sourceIndexData->indexCount * sizeof(uint16), indexBuffer16);
681 uint16 *updateEnd = indexBuffer16 + sourceIndexData->indexCount;
682
683 // add indexOffset
684 while (indexBuffer16 != updateEnd)
685 *indexBuffer16++ += indexOffset;
686 }
687 indexOffset += queuedMesh.subMesh->vertexData->vertexCount; // Increment the index offset
688 }
689
690 } // For each queued mesh
691
692 //Unlock buffers
693 m_pIndexData->indexBuffer->unlock();
694 for (Ogre::ushort i = 0; i < vertBinding->getBufferCount(); ++i)
695 vertBinding->getBuffer(i)->unlock();
696
697 m_queueMesh.clear(); // Clear mesh queue
698 m_Built = true;
699}
700
701
702//-----------------------------------------------------------------------------
705 const Ogre::Vector3 &parentGeomCenter,
706 const std::vector<VertexDeclaration::VertexElementList> &vertexBufferElements,
707 std::vector<Ogre::uchar*> &vertexBuffers,
708 Ogre::VertexData *dstVertexData)
709{
710 const VertexData *sourceVertexData = queuedMesh.subMesh->vertexData;
711 Ogre::Vector3 v3AddBatchPosition = queuedMesh.position - parentGeomCenter;
712
713 //Copy mesh vertex data into the vertex buffer
714 VertexBufferBinding *sourceBinds = sourceVertexData->vertexBufferBinding;
715 VertexBufferBinding *destBinds = dstVertexData->vertexBufferBinding;
716
717 std::vector<uchar> shadowBuf;
718
719 // For each vertex buffer
720 for (unsigned short ibuffer = 0, bufCnt = destBinds->getBufferCount(); ibuffer < bufCnt; ++ibuffer)
721 {
722 if (ibuffer < sourceBinds->getBufferCount()) // destanation buffer index smaller than source buffers count
723 {
724 //Lock the input buffer
725 const HardwareVertexBufferSharedPtr &sourceBuffer = sourceBinds->getBuffer(ibuffer);
726
727 shadowBuf.resize(sourceBuffer->getSizeInBytes());
728 sourceBuffer->readData(0, sourceBuffer->getSizeInBytes(), shadowBuf.data());
729 uchar *sourceBase = shadowBuf.data();
730
731 uchar *destBase = vertexBuffers[ibuffer]; //Get the locked output buffer
732
733 const VertexDeclaration::VertexElementList &elems = vertexBufferElements[ibuffer];
734 VertexDeclaration::VertexElementList::const_iterator iBegin = elems.begin(), iEnd = elems.end();
735 float *sourcePtr = 0, *destPtr = 0;
736 size_t sourceVertexBuffer = sourceBuffer->getVertexSize();
737
738 //Copy vertices
739 for (size_t v = 0, vertexCounter = sourceVertexData->vertexCount; v < vertexCounter; ++v)
740 {
741 // Iterate over vertex elements
742 VertexDeclaration::VertexElementList::const_iterator it = iBegin;
743 while (it != iEnd)
744 {
745 const VertexElement &elem = *it;
746 elem.baseVertexPointerToElement(sourceBase, &sourcePtr);
747 elem.baseVertexPointerToElement(destBase, &destPtr);
748
749 switch (elem.getSemantic())
750 {
751 case VES_POSITION:
752 {
753 Vector3 tmp(sourcePtr[0], sourcePtr[1], sourcePtr[2]);
754 tmp *= queuedMesh.scale;
755 tmp += v3AddBatchPosition;
756
757 destPtr[0] = (float)tmp.x; destPtr[1] = (float)tmp.y; destPtr[2] = (float)tmp.z;
758 }
759 break;
760
761 case VES_NORMAL:
762 case VES_BINORMAL:
763 case VES_TANGENT:
764 {
765 // Raw copy
766 destPtr[0] = sourcePtr[0];
767 destPtr[1] = sourcePtr[1];
768 destPtr[2] = sourcePtr[2];
769 }
770 break;
771
772 case VES_DIFFUSE:
773 {
774 uint32 tmpColor = *((uint32*)sourcePtr++);
775 uint8 tmpR = static_cast<uint8>(((tmpColor) & 0xFF) * queuedMesh.color.r);
776 uint8 tmpG = static_cast<uint8>(((tmpColor >> 8) & 0xFF) * queuedMesh.color.g);
777 uint8 tmpB = static_cast<uint8>(((tmpColor >> 16) & 0xFF) * queuedMesh.color.b);
778 //uint8 tmpA = 0xFF; //static_cast<uint8>(((tmpColor >> 24) & 0xFF) * queuedMesh.color.a); // always alpha 1.f
779 //*((uint32*)destPtr) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
780 *((uint32*)destPtr) = tmpR | (tmpG << 8) | (tmpB << 16) | (0xFF << 24);
781 }
782 break;
783
784 default:
785 // Raw copy
786 //memcpy(destPtr, sourcePtr, VertexElement::getTypeSize(elem.getType()));
787 memcpy(destPtr, sourcePtr, s_vertexType2Size[elem.getType()]);
788 break;
789 };
790
791 ++it;
792 } // while Iterate over vertex elements
793
794 // Increment both pointers
795 destBase += sourceVertexBuffer;
796 sourceBase += sourceVertexBuffer;
797 }
798
799 vertexBuffers[ibuffer] = destBase;
800 }
801 else
802 {
803 size_t bufferNumber = destBinds->getBufferCount()-1;
804
805 //Get the locked output buffer
806 uint32 *startPtr = (uint32*)vertexBuffers[bufferNumber];
807 uint32 *endPtr = startPtr + sourceVertexData->vertexCount;
808
809 //Generate color
810 uint8 tmpR = static_cast<uint8>(queuedMesh.color.r * 255);
811 uint8 tmpG = static_cast<uint8>(queuedMesh.color.g * 255);
812 uint8 tmpB = static_cast<uint8>(queuedMesh.color.b * 255);
813 uint32 tmpColor = tmpR | (tmpG << 8) | (tmpB << 16) | (0xFF << 24);
814
815 //Copy colors
816 while (startPtr < endPtr)
817 *startPtr++ = tmpColor;
818
819 vertexBuffers[bufferNumber] += sizeof(uint32) * sourceVertexData->vertexCount;
820 }
821
822 } // For each vertex buffer
823
824}
825
826//-----------------------------------------------------------------------------
829 const Ogre::Vector3 &parentGeomCenter,
830 const std::vector<VertexDeclaration::VertexElementList> &vertexBufferElements,
831 std::vector<Ogre::uchar*> &vertexBuffers,
832 Ogre::VertexData *dstVertexData)
833{
834 const VertexData *sourceVertexData = queuedMesh.subMesh->vertexData;
835 // Get rotation matrix for vertex rotation
836 Ogre::Matrix3 m3MeshOrientation;
837 queuedMesh.orientation.ToRotationMatrix(m3MeshOrientation);
838 const Ogre::Real *mat = m3MeshOrientation[0]; // Ogre::Matrix3 is row major
839 Ogre::Vector3 v3AddBatchPosition = queuedMesh.position - parentGeomCenter;
840 const Ogre::Vector3 &scale = queuedMesh.scale;
841
842 //Copy mesh vertex data into the vertex buffer
843 VertexBufferBinding *sourceBinds = sourceVertexData->vertexBufferBinding;
844 VertexBufferBinding *destBinds = dstVertexData->vertexBufferBinding;
845
846 std::vector<uchar> shadowBuf;
847
848 // For each vertex buffer
849 for (unsigned short ibuffer = 0, bufCnt = destBinds->getBufferCount(); ibuffer < bufCnt; ++ibuffer)
850 {
851 if (ibuffer < sourceBinds->getBufferCount()) // destanation buffer index smaller than source buffers count
852 {
853 //Lock the input buffer
854 const HardwareVertexBufferSharedPtr &sourceBuffer = sourceBinds->getBuffer(ibuffer);
855 shadowBuf.resize(sourceBuffer->getSizeInBytes());
856 sourceBuffer->readData(0, sourceBuffer->getSizeInBytes(), shadowBuf.data());
857 uchar *sourceBase = shadowBuf.data();
858
859 //Get the locked output buffer
860 uchar *destBase = vertexBuffers[ibuffer];
861
862
863 const VertexDeclaration::VertexElementList &elems = vertexBufferElements[ibuffer];
864 VertexDeclaration::VertexElementList::const_iterator iBegin = elems.begin(), iEnd = elems.end();
865 float *sourcePtr = 0, *destPtr = 0;
866 size_t sourceVertexSize = sourceBuffer->getVertexSize();
867
868 //Copy vertices
869 for (size_t v = 0, vertexCounter = sourceVertexData->vertexCount; v < vertexCounter; ++v)
870 {
871 VertexDeclaration::VertexElementList::const_iterator it = iBegin;
872 // Iterate over vertex elements
873 while (it != iEnd)
874 {
875 const VertexElement &elem = *it;
876 elem.baseVertexPointerToElement(sourceBase, &sourcePtr);
877 elem.baseVertexPointerToElement(destBase, &destPtr);
878
879 switch (elem.getSemantic())
880 {
881 case VES_POSITION:
882 {
883 Vector3 tmp(sourcePtr[0] * scale.x, sourcePtr[1] * scale.x, sourcePtr[2] * scale.x);
884 tmp = m3MeshOrientation*tmp;
885 tmp += v3AddBatchPosition;
886 destPtr[0] = (float)tmp.x;
887 destPtr[1] = (float)tmp.y;
888 destPtr[2] = (float)tmp.z;
889 }
890 break;
891
892 case VES_NORMAL:
893 case VES_BINORMAL:
894 case VES_TANGENT:
895 {
896 // rotate vector by matrix. Ogre::Matrix3::operator* (const Vector3&) is not fast
897 destPtr[0] = float(mat[0] * sourcePtr[0] + mat[1] * sourcePtr[1] + mat[2] * sourcePtr[2]); // x
898 destPtr[1] = float(mat[3] * sourcePtr[0] + mat[4] * sourcePtr[1] + mat[5] * sourcePtr[2]); // y
899 destPtr[2] = float(mat[6] * sourcePtr[0] + mat[7] * sourcePtr[1] + mat[8] * sourcePtr[2]); // z
900 }
901 break;
902
903 case VES_DIFFUSE:
904 {
905 uint32 tmpColor = *((uint32*)sourcePtr);
906 uint8 tmpR = static_cast<uint8>(((tmpColor) & 0xFF) * queuedMesh.color.r);
907 uint8 tmpG = static_cast<uint8>(((tmpColor >> 8) & 0xFF) * queuedMesh.color.g);
908 uint8 tmpB = static_cast<uint8>(((tmpColor >> 16) & 0xFF) * queuedMesh.color.b);
909 //uint8 tmpA = 0xFF; //static_cast<uint8>(((tmpColor >> 24) & 0xFF) * queuedMesh.color.a); // always alpha 1.f
910
911 //*((uint32*)destPtr) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
912 *((uint32*)destPtr) = tmpR | (tmpG << 8) | (tmpB << 16) | (0xFF << 24);
913 }
914 break;
915
916 default:
917 //memcpy(destPtr, sourcePtr, VertexElement::getTypeSize(elem.getType()));
918 memcpy(destPtr, sourcePtr, s_vertexType2Size[elem.getType()]);
919 break;
920 };
921
922 ++it;
923 } // for VertexElementList
924
925 // Increment both pointers
926 destBase += sourceVertexSize;
927 sourceBase += sourceVertexSize;
928 }
929
930 //Unlock the input buffer
931 vertexBuffers[ibuffer] = destBase;
932 }
933 else
934 {
935 size_t bufferNumber = destBinds->getBufferCount()-1;
936
937 //Get the locked output buffer
938 uint32 *startPtr = (uint32*)vertexBuffers[bufferNumber];
939 uint32 *endPtr = startPtr + sourceVertexData->vertexCount;
940
941 //Generate color
942 uint8 tmpR = static_cast<uint8>(queuedMesh.color.r * 255);
943 uint8 tmpG = static_cast<uint8>(queuedMesh.color.g * 255);
944 uint8 tmpB = static_cast<uint8>(queuedMesh.color.b * 255);
945 uint32 tmpColor = tmpR | (tmpG << 8) | (tmpB << 16) | (0xFF << 24);
946
947 //Copy colors
948 while (startPtr < endPtr)
949 *startPtr++ = tmpColor;
950
951 vertexBuffers[bufferNumber] += sizeof(uint32) * sourceVertexData->vertexCount;
952 }
953 }
954}
955
956
957//-----------------------------------------------------------------------------
960{
961 //If built, delete the batch
962 if (m_Built)
963 {
964 m_Built = false;
965
966 //Delete buffers
967 m_pIndexData->indexBuffer.reset();
968 m_pVertexData->vertexBufferBinding->unsetAllBindings();
969
970 //Reset vertex/index count
971 m_pVertexData->vertexStart = 0;
972 m_pVertexData->vertexCount = 0;
973 m_pIndexData->indexStart = 0;
974 m_pIndexData->indexCount = 0;
975 }
976
977 m_queueMesh.clear(); // Clear mesh queue
978}
979
980
981//-----------------------------------------------------------------------------
984{
985 if (!m_Built)
986 return;
987
988 //Update material technique based on camera distance
989 m_pBestTechnique = m_ptrMaterial->getBestTechnique(m_ptrMaterial->getLodIndex(
990 m_pParentGeom->m_fMinDistanceSquared * m_pParentGeom->m_fMinDistanceSquared));
991 rqg->addRenderable(this, m_pBestTechnique, OGRE_RENDERABLE_DEFAULT_PRIORITY);
992}
993
994
995//-----------------------------------------------------------------------------
998{
999 op.operationType = RenderOperation::OT_TRIANGLE_LIST;
1000 op.srcRenderable = this;
1001 op.useIndexes = true;
1002 op.vertexData = m_pVertexData;
1003 op.indexData = m_pIndexData;
1004}
1005
1006
1007//-----------------------------------------------------------------------------
1010{
1011 Vector3 camVec = m_pParentGeom->_convertToLocal(cam->getDerivedPosition()) - m_pParentGeom->m_vecCenter;
1012 return camVec.squaredLength();
1013}
1014
1015//-----------------------------------------------------------------------------
1017const Ogre::LightList& BatchedGeometry::SubBatch::getLights(void) const
1018{
1019 return m_pParentGeom->queryLights();
1020}
uint32 CountUsedVertices(IndexData *id, std::map< uint32, uint32 > &ibmap)
Visible chunk of geometry.
virtual void build()
Build (assemble a vertex/index buffers) geometry for rendering.
static void _buildFullTransform(const QueuedMesh &queuedMesh, const Ogre::Vector3 &parentGeomCenter, const std::vector< Ogre::VertexDeclaration::VertexElementList > &vertexBufferElements, std::vector< Ogre::uchar * > &vertexBuffers, Ogre::VertexData *dst)
Build vertex of QueuedMesh if it have some orientation.
Ogre::Real getSquaredViewDepth(const Ogre::Camera *cam) const
const Ogre::LightList & getLights(void) const
void addSubEntity(Ogre::SubEntity *ent, const Ogre::Vector3 &position, const Ogre::Quaternion &orientation, const Ogre::Vector3 &scale, const Ogre::ColourValue &color=Ogre::ColourValue::White, void *userData=NULL)
Ogre::SubMesh * m_pSubMesh
Ogre::SubMesh for Index/Vertex buffers manipulation.
void getRenderOperation(Ogre::RenderOperation &op)
static void _buildIdentiryOrientation(const QueuedMesh &queuedMesh, const Ogre::Vector3 &parentGeomCenter, const std::vector< Ogre::VertexDeclaration::VertexElementList > &vertexBufferElements, std::vector< Ogre::uchar * > &vertexBuffers, Ogre::VertexData *dst)
Build vertex of QueuedMesh if it have identity orientation.
SubBatch(BatchedGeometry *parent, Ogre::SubEntity *ent)
Constructor.
void addSelfToRenderQueue(Ogre::RenderQueueGroup *rqg)
A "lightweight" version of Ogre::StaticGeometry, which gives you a little more control over the batch...
const Ogre::String & getMovableType(void) const
static void extractVertexDataFromShared(const Ogre::MeshPtr &mesh)
Ogre::SceneNode * m_pParentSceneNode
BatchedGeometry(Ogre::SceneManager *mgr, Ogre::SceneNode *rootSceneNode)
Constructor.
Ogre::AxisAlignedBox m_boundsAAB
Ogre::SceneManager * m_pSceneMgr
Ogre::Vector3 _convertToLocal(const Ogre::Vector3 &globalVec) const
static const size_t s_vertexType2Size[Ogre::VET_COLOUR_ABGR+1]
Internal matrix for remap vertex type to vertex size instead call VertexElement::getTypeSize.
static Ogre::String getFormatString(Ogre::SubEntity *ent)
virtual void addEntity(Ogre::Entity *ent, const Ogre::Vector3 &position, const Ogre::Quaternion &orientation=Ogre::Quaternion::IDENTITY, const Ogre::Vector3 &scale=Ogre::Vector3::UNIT_SCALE, const Ogre::ColourValue &color=Ogre::ColourValue::White)
Ogre::SceneNode * m_pSceneNode
void _updateRenderQueue(Ogre::RenderQueue *queue)
void _notifyCurrentCamera(Ogre::Camera *cam)