00001 #include "lugre_prefix.h"
00002 #include "lugre_fastbatch.h"
00003 #include "lugre_meshbuffer.h"
00004 #include <stdlib.h>
00005 #include <list>
00006 #include <Ogre.h>
00007 #include <utility>
00008
00009 #define DEBUG_FASTBATCH 0
00010
00011
00012
00013
00014
00015
00016
00017 using namespace Ogre;
00018
00019 namespace Lugre {
00020
00021
00022
00023 cFastBatch::cFastBatch () : mfBoundRad(0) {
00024 mParentNode = NULL;
00025
00026
00027 StringUtil::StrStreamType name;
00028 static int ms_uGenNameCount = 1;
00029 name << "LugreFastBatch" << ms_uGenNameCount++;
00030 mName = name.str();
00031
00032
00033 mfBoundRad = 0.0;
00034 mBounds.setExtents(Ogre::Vector3::ZERO,Ogre::Vector3::ZERO);
00035
00036 }
00037
00038 cFastBatch::~cFastBatch () {
00039
00040 for (tSubBatchMapIterator itor=mSubBatches.begin();itor!=mSubBatches.end();++itor) delete (*itor).second;
00041 mSubBatches.clear();
00042 }
00043
00044 void cFastBatch::AddMesh (cBufferedMesh& pBufferedMesh, const Ogre::Vector3& vPos,
00045 const Ogre::Quaternion& qRot,
00046 const Ogre::Vector3& vScale,
00047 const Ogre::ColourValue& vCol,
00048 const bool bColourOverride,
00049 const float fOrderValue) {
00050
00051 if (DEBUG_FASTBATCH) printf("cFastBatch::AddMesh(%f,%f,%f)\n",vPos.x,vPos.y,vPos.z);
00052
00053
00054 if (1) {
00055 Ogre::Matrix4 mat(qRot);
00056 mat.setScale(vScale);
00057 Ogre::AxisAlignedBox entBounds = pBufferedMesh.GetBounds();
00058 entBounds.transform(mat);
00059
00060 if (mSubBatches.size() == 0) {
00061 mBounds.setMinimum(entBounds.getMinimum() + vPos);
00062 mBounds.setMaximum(entBounds.getMaximum() + vPos);
00063 } else {
00064 Ogre::Vector3 vMin = mBounds.getMinimum();
00065 Ogre::Vector3 vMax = mBounds.getMaximum();
00066 vMin.makeFloor( entBounds.getMinimum() + vPos);
00067 vMax.makeCeil( entBounds.getMaximum() + vPos);
00068 mBounds.setMinimum(vMin);
00069 mBounds.setMaximum(vMax);
00070 }
00071 }
00072
00073
00074 for (int i=0;i<pBufferedMesh.GetSubMeshCount();++i) {
00075 cBufferedSubMesh& pBufferedSubMesh = pBufferedMesh.GetSubMesh(i);
00076 if (pBufferedSubMesh.GetUsesShared()) { printf("warning, FastBatch doesn support shared vertex data\n"); continue; }
00077
00078
00079 cSubBatch*& mySubBatch = mSubBatches[bColourOverride ? pBufferedSubMesh.GetFormatHashWithColour() : pBufferedSubMesh.GetFormatHash()];
00080 if (!mySubBatch) mySubBatch = new cSubBatch(this,pBufferedSubMesh,bColourOverride);
00081
00082 mySubBatch->AddInstance(cInstance(&pBufferedSubMesh,vPos,qRot,vScale,vCol,bColourOverride),fOrderValue);
00083 }
00084 }
00085
00086 void cFastBatch::Build () {
00087
00088
00089
00090 Ogre::Vector3 vCenter = Ogre::Vector3::ZERO;
00091
00092
00093 mfBoundRad = mymax(mBounds.getMinimum().length(),mBounds.getMaximum().length());
00094 mvBoundsCenter = (mBounds.getMinimum() + mBounds.getMaximum()) * 0.5;
00095
00096
00097 if (DEBUG_FASTBATCH) {
00098 printf("cFastBatch::Build() mfBoundRad=%f\n",mfBoundRad);
00099 Ogre::Vector3 v = mBounds.getMinimum();
00100 Ogre::Vector3 w = mBounds.getMaximum();
00101 printf("cFastBatch::Build() min=%f,%f,%f max=%f,%f,%f\n",v.x,v.y,v.z, w.x,w.y,w.z);
00102 }
00103
00104
00105 for (tSubBatchMapIterator itor=mSubBatches.begin();itor!=mSubBatches.end();++itor) (*itor).second->Build();
00106 }
00107
00108 void cFastBatch::SetDisplayRange (const float fMin,const float fMax) {
00109 for (tSubBatchMapIterator itor=mSubBatches.begin();itor!=mSubBatches.end();++itor) (*itor).second->SetDisplayRange(fMin,fMax);
00110 }
00111
00112 void cFastBatch::_updateRenderQueue (Ogre::RenderQueue *queue) {
00113
00114 if (isVisible()) {
00115 for (tSubBatchMapIterator itor=mSubBatches.begin();itor!=mSubBatches.end();++itor) {
00116 queue->addRenderable( (*itor).second, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
00117
00118 }
00119
00120 }
00121 }
00122
00123 const Ogre::String& cFastBatch::getMovableType (void) const { static Ogre::String t = "LugreFastBatch"; return t; }
00124
00125
00126
00127
00128 cFastBatch::cSubBatch::cSubBatch (cFastBatch* pParent,cBufferedSubMesh& pBufferedSubMesh, const bool bColourOverride) {
00129
00130 mpParent = pParent;
00131
00132
00133
00134 setMaterial(pBufferedSubMesh.GetMat());
00135 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::cSubBatch matptr.isnull()=%d\n",mpMat.isNull()?1:0);
00136
00137
00138 mpVertexData = new Ogre::VertexData();
00139 mpVertexData->vertexStart = 0;
00140 mpVertexData->vertexCount = 0;
00141
00142
00143 mpIndexData = new Ogre::IndexData();
00144 mpIndexData->indexStart = 0;
00145 mpIndexData->indexCount = 0;
00146 miTotalIndexCount = 0;
00147
00148
00149 VertexDeclaration* decl = mpVertexData->vertexDeclaration;
00150
00151
00152 cBufferedVertexData& pVertexData = pBufferedSubMesh.GetBufferedVertexData();
00153 Ogre::VertexDeclaration* pVertexDecl = pVertexData.GetVertexDecl();
00154 const Ogre::VertexDeclaration::VertexElementList& pVertexElemList = pVertexDecl->getElements();
00155 bool bHasColour = false;
00156 int iOffset = 0;
00157
00158
00159 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::cSubBatch vertex format:");
00160 for (Ogre::VertexDeclaration::VertexElementList::const_iterator ei=pVertexElemList.begin();ei!=pVertexElemList.end();++ei) {
00161 const Ogre::VertexElement &elem = *ei;
00162 assert((elem.getSize() % sizeof(float)) == 0 && "error, vertex decl element size must be multiple of 4(sizeof(float))");
00163 iOffset += decl->addElement(kCommonSourceIndex,iOffset,elem.getType(),elem.getSemantic(),elem.getIndex()).getSize();
00164 if (DEBUG_FASTBATCH) switch (elem.getSemantic()) {
00165 case Ogre::VES_POSITION : printf("pos,"); break;
00166 case Ogre::VES_NORMAL : printf("normal,"); break;
00167 case Ogre::VES_DIFFUSE : printf("diffuse,"); break;
00168 case Ogre::VES_TANGENT : printf("tangent,"); break;
00169 case Ogre::VES_BINORMAL : printf("binormal,"); break;
00170 case Ogre::VES_TEXTURE_COORDINATES : printf("texcoords,"); break;
00171 default : printf("UNKNOWN,"); break;
00172 }
00173 if (elem.getSemantic() == Ogre::VES_DIFFUSE) bHasColour = true;
00174 }
00175 if (DEBUG_FASTBATCH) printf("\n");
00176
00177
00178 mbAddColourAtEnd = !bHasColour && bColourOverride;
00179 if (mbAddColourAtEnd) {
00180 miPreferredColourFormat = Ogre::Root::getSingleton().getRenderSystem()->getColourVertexElementType();
00181 iOffset += decl->addElement(kCommonSourceIndex,iOffset,miPreferredColourFormat,Ogre::VES_DIFFUSE,0).getSize();
00182 }
00183
00184
00185 miVertexSize = iOffset;
00186 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::cSubBatch miVertexSize=%d bHasColour=%d mbAddColourAtEnd=%d\n",(int)miVertexSize,bHasColour?1:0,mbAddColourAtEnd?1:0);
00187
00188
00189
00190
00191
00192
00193
00194
00195 }
00196
00197 cFastBatch::cSubBatch::~cSubBatch () {
00198 delete mpVertexData; mpVertexData = 0;
00199 delete mpIndexData; mpIndexData = 0;
00200 }
00201
00202 void cFastBatch::cSubBatch::AddInstance (cInstance pInstance,const float fOrderValue) {
00203
00204 mpVertexData->vertexCount += pInstance.mpBufferedSubMesh->GetVertexCount();
00205 mpIndexData->indexCount += pInstance.mpBufferedSubMesh->GetIndexCount();
00206 miTotalIndexCount += pInstance.mpBufferedSubMesh->GetIndexCount();
00207
00208
00209 if (miPreferredColourFormat == VET_COLOUR_ARGB) { std::swap(pInstance.mvCol.r, pInstance.mvCol.b); }
00210
00211
00212 mInstances.insert(std::pair<float,cInstance>(fOrderValue,pInstance));
00213 }
00214
00215 void cFastBatch::cSubBatch::SetDisplayRange (const float fMin,const float fMax) {
00216 assert(mpVertexData && "should not happen");
00217 assert(mpIndexData && "should not happen");
00218
00219
00220 if(mOrderValueOffsets.size() == 0)return;
00221
00222
00223 float minOrderValue = (*mOrderValueOffsets.begin()).first;
00224 float maxOrderValue = (*mOrderValueOffsets.rbegin()).first;
00225
00226 if(fMax < minOrderValue || fMin > maxOrderValue || fMin > fMax){
00227
00228 mpIndexData->indexStart = 0;
00229 mpIndexData->indexCount = 0;
00230 } else {
00231
00232 std::map<float,int>::iterator itor_min = mOrderValueOffsets.lower_bound(fMin);
00233 std::map<float,int>::iterator itor_max = mOrderValueOffsets.upper_bound(fMax);
00234 int iIndexIndexStart = (itor_min != mOrderValueOffsets.end()) ? (*itor_min).second : 0;
00235 int iIndexIndexEnd = (itor_max != mOrderValueOffsets.end()) ? (*itor_max).second : miTotalIndexCount;
00236
00237 mpIndexData->indexStart = iIndexIndexStart;
00238 mpIndexData->indexCount = iIndexIndexEnd - iIndexIndexStart;
00239 }
00240 }
00241
00242 void cFastBatch::cSubBatch::Build () {
00243 Ogre::HardwareVertexBufferSharedPtr mHWVBuf;
00244 Ogre::HardwareIndexBufferSharedPtr mHWIBuf;
00245 HardwareBuffer::Usage hbu = HardwareBuffer::HBU_STATIC_WRITE_ONLY;
00246 bool b32BitIndices = true;
00247
00248
00249
00250
00251 mHWVBuf = HardwareBufferManager::getSingleton().createVertexBuffer(miVertexSize,mpVertexData->vertexCount,hbu,false);
00252 mpVertexData->vertexBufferBinding->setBinding(kCommonSourceIndex,mHWVBuf);
00253
00254
00255 Ogre::HardwareIndexBuffer::IndexType iIdxType = b32BitIndices ? HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT;
00256 mHWIBuf = HardwareBufferManager::getSingleton().createIndexBuffer(iIdxType,mpIndexData->indexCount,hbu,false);
00257 mpIndexData->indexBuffer = mHWIBuf;
00258
00259
00260 if (!mpRenderSys) mpRenderSys = Ogre::Root::getSingleton().getRenderSystem();
00261
00262
00263 Ogre::uint32 iIndexOffset = 0;
00264 Vector3 tmp;
00265 Ogre::uint32 tmpColour;
00266 Ogre::uint8 tmpR, tmpG, tmpB, tmpA;
00267 mOrderValueOffsets.clear();
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 float* pWriter = static_cast<float*>(mHWVBuf->lock(HardwareBuffer::HBL_DISCARD));
00278 --pWriter;
00279
00280
00281
00282 Ogre::uint16* pIndexWriter16 = 0;
00283 Ogre::uint32* pIndexWriter32 = 0;
00284 if (b32BitIndices)
00285 pIndexWriter32 = static_cast<Ogre::uint32*>(mHWIBuf->lock(HardwareBuffer::HBL_DISCARD));
00286 else pIndexWriter16 = static_cast<Ogre::uint16*>(mHWIBuf->lock(HardwareBuffer::HBL_DISCARD));
00287
00288
00289 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::Build : %d instances, vc=%d, ic=%d\n",(int)mInstances.size(),mpVertexData->vertexCount,mpIndexData->indexCount);
00290
00291 int iNumberOfWrittenIndices = 0;
00292
00293 float fLastOrderVal = 0;
00294 for (std::multimap<float,cInstance>::iterator itor=mInstances.begin();itor!=mInstances.end();++itor) {
00295 cInstance& pInst = (*itor).second;
00296 float fOrderValue = (*itor).first;
00297 if (iNumberOfWrittenIndices == 0 || fOrderValue != fLastOrderVal) {
00298 fLastOrderVal = fOrderValue;
00299 mOrderValueOffsets[fOrderValue] = iNumberOfWrittenIndices;
00300 }
00301 cBufferedSubMesh& pSubMesh = *pInst.mpBufferedSubMesh;
00302 cBufferedVertexData& pVertexData = pSubMesh.GetBufferedVertexData();
00303 Ogre::VertexDeclaration* pVertexDecl = pVertexData.GetVertexDecl();
00304 const Ogre::VertexDeclaration::VertexElementList& pVertexElemList = pVertexDecl->getElements();
00305
00306
00307
00308 if (mbAddColourAtEnd) {
00309
00310 tmpR = Ogre::uint8(float(0xFF) * pInst.mvCol.r);
00311 tmpG = Ogre::uint8(float(0xFF) * pInst.mvCol.g);
00312 tmpB = Ogre::uint8(float(0xFF) * pInst.mvCol.b);
00313 tmpA = Ogre::uint8(float(0xFF) * pInst.mvCol.a);
00314 tmpColour = (tmpR) | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
00315 }
00316
00317 if (DEBUG_FASTBATCH) printf("inst rot=%f,%f,%f,%f pos=%f,%f,%f scale=%f,%f,%f mbAddColourAtEnd=%d\n",
00318 pInst.mqRot.w,pInst.mqRot.x,pInst.mqRot.y,pInst.mqRot.z,
00319 pInst.mvPos.x,pInst.mvPos.y,pInst.mvPos.z,
00320 pInst.mvScale.x,pInst.mvScale.y,pInst.mvScale.z, mbAddColourAtEnd?1:0);
00321
00322
00323 int iVertexCount = pVertexData.GetVertexCount();
00324 Ogre::Quaternion qRot = pInst.mqRot;
00325 Ogre::Vector3 vScale = pInst.mvScale;
00326 Ogre::Vector3 vSign(vScale.x<0?-1:1,vScale.y<0?-1:1,vScale.z<0?-1:1);
00327 Ogre::Vector3 vPos = pInst.mvPos;
00328
00329
00330 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::Build : GetVertexCount()=%d\n",iVertexCount);
00331 for (int iVertex=0;iVertex<iVertexCount;++iVertex) {
00332
00333 for (Ogre::VertexDeclaration::VertexElementList::const_iterator ei=pVertexElemList.begin();ei!=pVertexElemList.end();++ei) {
00334 const Ogre::VertexElement &elem = *ei;
00335 const float* pReader = reinterpret_cast<const float*>(pVertexData.GetVertexData(elem.getSource(),iVertex) + elem.getOffset());
00336
00337 switch (elem.getSemantic()) {
00338 case VES_POSITION:
00339 tmp.x = pReader[0];
00340 tmp.y = pReader[1];
00341 tmp.z = pReader[2];
00342
00343
00344 tmp = (qRot * (tmp * vScale)) + vPos;
00345
00346 *++pWriter = tmp.x;
00347 *++pWriter = tmp.y;
00348 *++pWriter = tmp.z;
00349 break;
00350
00351 case VES_NORMAL:
00352 tmp.x = pReader[0];
00353 tmp.y = pReader[1];
00354 tmp.z = pReader[2];
00355
00356
00357 tmp = qRot * (tmp * vSign);
00358
00359 *++pWriter = tmp.x;
00360 *++pWriter = tmp.y;
00361 *++pWriter = tmp.z;
00362 break;
00363
00364 case VES_DIFFUSE:
00365 tmpColour = *((Ogre::uint32*)pReader);
00366 tmpR = Ogre::uint8(float((tmpColour ) & 0xFF) * pInst.mvCol.r);
00367 tmpG = Ogre::uint8(float((tmpColour >> 8) & 0xFF) * pInst.mvCol.g);
00368 tmpB = Ogre::uint8(float((tmpColour >> 16) & 0xFF) * pInst.mvCol.b);
00369 tmpA = Ogre::uint8(float((tmpColour >> 24) & 0xFF) * pInst.mvCol.a);
00370
00371
00372
00373 tmpColour = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
00374 *((Ogre::uint32*)++pWriter) = tmpColour;
00375 break;
00376
00377 case VES_TANGENT:
00378 case VES_BINORMAL:
00379 tmp.x = pReader[0];
00380 tmp.y = pReader[1];
00381 tmp.z = pReader[2];
00382
00383
00384 tmp = qRot * (tmp * vSign);
00385
00386 *++pWriter = tmp.x;
00387 *++pWriter = tmp.y;
00388 *++pWriter = tmp.z;
00389 break;
00390
00391 default: {
00392
00393 int iElementSizeInFloats = elem.getSize() / sizeof(float);
00394 for (int k=0;k<iElementSizeInFloats;++k) *++pWriter = pReader[k];
00395 }
00396 break;
00397 };
00398 }
00399
00400
00401 if (mbAddColourAtEnd) {
00402 *((Ogre::uint32*)++pWriter) = tmpColour;
00403 }
00404 }
00405
00406
00407 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::Build : GetIndexCount()=%d\n",(int)pSubMesh.GetIndexCount());
00408 int iSubMeshIndexCount = pSubMesh.GetIndexCount();
00409 iNumberOfWrittenIndices += iSubMeshIndexCount;
00410 Ogre::uint32* pIndexReader = pSubMesh.GetIndexData();
00411 Ogre::uint32* pIndexReaderEnd = pIndexReader + iSubMeshIndexCount;
00412 if (b32BitIndices) {
00413 for (;pIndexReader!=pIndexReaderEnd;++pIndexReader,++pIndexWriter32) *pIndexWriter32 = (iIndexOffset + *pIndexReader);
00414 } else {
00415 for (;pIndexReader!=pIndexReaderEnd;++pIndexReader,++pIndexWriter16) *pIndexWriter16 = (iIndexOffset + *pIndexReader);
00416 }
00417
00418
00419 iIndexOffset += iVertexCount;
00420 }
00421 mInstances.clear();
00422
00423
00424 mHWVBuf->unlock();
00425 mHWIBuf->unlock();
00426
00427 if (DEBUG_FASTBATCH) printf("cFastBatch::cSubBatch::Build : count v,i=%d,%d\n",(int)mpVertexData->vertexCount,(int)mpIndexData->indexCount);
00428 }
00429
00430
00431
00432
00433 Ogre::Real cFastBatch::cSubBatch::getSquaredViewDepth (const Ogre::Camera* cam) const {
00434
00435 return (cam->getDerivedPosition() - mpParent->GetBoundsCenter()).squaredLength();
00436 }
00437
00438 void cFastBatch::cSubBatch::setMaterialName (const Ogre::String &mat) {
00439 mpMat = Ogre::MaterialManager::getSingleton().getByName(mat);
00440 if (mpMat.isNull())
00441 OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "Could not find material " + mat,
00442 "cFastBatch::cSubBatch::setMaterialName" );
00443 mpMat->load();
00444 }
00445
00446 Ogre::String cFastBatch::cSubBatch::getMaterialName () const { return mpMat->getName(); }
00447
00448 void cFastBatch::cSubBatch::getRenderOperation (Ogre::RenderOperation& op) {
00449
00450 op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
00451 op.srcRenderable = this;
00452 op.useIndexes = true;
00453 op.vertexData = mpVertexData;
00454 op.indexData = mpIndexData;
00455 }
00456
00457 void cFastBatch::cSubBatch::getWorldTransforms (Ogre::Matrix4* xform) const {
00458 *xform = mpParent->_getParentNodeFullTransform();
00459 }
00460 const Ogre::Quaternion& cFastBatch::cSubBatch::getWorldOrientation (void) const {
00461 return mpParent->getParentNode()->_getDerivedOrientation();
00462 }
00463 const Ogre::Vector3& cFastBatch::cSubBatch::getWorldPosition (void) const {
00464 return mpParent->getParentNode()->_getDerivedPosition();
00465 }
00466
00467
00468
00469 Ogre::RenderSystem* cFastBatch::cSubBatch::mpRenderSys = 0;
00470
00471 };