lugre_meshbuffer.cpp

Go to the documentation of this file.
00001 #include "lugre_prefix.h"
00002 #include "lugre_meshbuffer.h"
00003 #undef min
00004 #undef max
00005 #include <Ogre.h>
00006 #include <map>
00007 #include <string>
00008 #include "lugre_meshshape.h"
00009 using namespace Ogre;
00010 
00011 #define DEBUG_MESHBUFFER 0
00012 
00013 namespace Lugre {
00014 
00015 // ***** ***** ***** ***** ***** cache
00016     
00017 std::map<std::string,cBufferedMesh*> gBufferedMeshCache;
00018 
00019 bool gMeshBuffer_PrintStacktraceOnLoad = false;
00020 void    PrintLuaStackTrace      ();
00021     
00022 cBufferedMesh*  GetBufferedMesh (const char* szMeshName) {
00023     //  search in cache
00024     cBufferedMesh*& pBufferedMesh = gBufferedMeshCache[szMeshName];
00025     if (pBufferedMesh) return pBufferedMesh;
00026     
00027     if (gMeshBuffer_PrintStacktraceOnLoad) {
00028         printf("GetBufferedMesh %s\n",szMeshName);
00029         PrintLuaStackTrace();
00030     }
00031     
00032     // extract data from mesh
00033     pBufferedMesh = new cBufferedMesh();
00034     Ogre::MeshPtr pMesh = Ogre::MeshManager::getSingleton().load(szMeshName,
00035         Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
00036     if (!pMesh.isNull()) pBufferedMesh->SetFromMesh(*pMesh);
00037         
00038     return pBufferedMesh;
00039 }
00040 
00041 // ***** ***** ***** ***** ***** cBufferedMesh
00042     
00043 cBufferedMesh::cBufferedMesh() : mfBoundRad(0) {}
00044     
00045 void    cBufferedMesh::SetFromMesh  (Ogre::Mesh& pMesh) {
00046     if (DEBUG_MESHBUFFER) printf("cBufferedMesh::SetFromMesh submeshes=%d shared=%d\n",(int)pMesh.getNumSubMeshes(),pMesh.sharedVertexData?1:0);
00047         
00048     // read shared vertices
00049     if (pMesh.sharedVertexData) mBufferedVertexData_Shared.SetFromVertexData(*pMesh.sharedVertexData);
00050     
00051     // read submeshes
00052     mBufferedSubMeshes.resize(pMesh.getNumSubMeshes());
00053     for (int i=0;i<pMesh.getNumSubMeshes();++i) GetSubMesh(i).SetFromSubMesh(this,*pMesh.getSubMesh(i));
00054         
00055     // bounds
00056     // mBounds = pMesh.getBounds();
00057     
00058     // manually calculates the bounding box
00059     mBounds.setNull();
00060     for (int iSubMesh=0;iSubMesh<mBufferedSubMeshes.size();++iSubMesh) {
00061         cBufferedSubMesh&       sub = mBufferedSubMeshes[iSubMesh];
00062         cBufferedVertexData&    data = sub.GetUsesShared() ? GetBufferedVertexData_Shared() : sub.GetBufferedVertexData();
00063         
00064         for (int iVertex=0;iVertex<data.GetVertexCount();++iVertex) {
00065             Ogre::Vector3 v = data.GetVertexPosVec3(iVertex);
00066             mBounds.merge(v);
00067         }
00068     }
00069     
00070     mfBoundRad = mymax(mBounds.getMinimum().length(),mBounds.getMaximum().length());
00071     if (DEBUG_MESHBUFFER) printf("cBufferedMesh::SetFromMesh done\n");
00072 }
00073 
00074 int     cBufferedMesh::RayPick      (const Ogre::Vector3& vRayPos,const Ogre::Vector3& vRayDir,const Ogre::Vector3& vPos,const Ogre::Quaternion& qRot,const Ogre::Vector3& vScale,float* pfHitDist) {
00075     // get origin & dir in local coordinates
00076     Ogre::Quaternion invrot     = qRot.Inverse();
00077     return RayPick((invrot*(vRayPos - vPos))/vScale,(invrot * vRayDir)/ vScale,pfHitDist);
00078 }
00079 
00080 int     cBufferedMesh::RayPick      (const Ogre::Vector3& vRayPos,const Ogre::Vector3& vRayDir,float* pfHitDist) {
00081     if (!Ogre::Ray(vRayPos,vRayDir).intersects(Ogre::Sphere(Ogre::Vector3::ZERO,mfBoundRad + 0.1)).first) return -1;
00082     int iFaceHit = -1;
00083     float myHitDist;
00084     for (int iSubMesh=0;iSubMesh<mBufferedSubMeshes.size();++iSubMesh) {
00085         cBufferedSubMesh&       sub = mBufferedSubMeshes[iSubMesh];
00086         cBufferedVertexData&    data = sub.GetUsesShared() ? GetBufferedVertexData_Shared() : sub.GetBufferedVertexData();
00087         unsigned int* pIdx      = sub.GetIndexData();
00088         unsigned int* pIdxEnd   = pIdx + sub.GetIndexCount();
00089         int iFaceNum = 0;
00090         for (;pIdx!=pIdxEnd;pIdx+=3,++iFaceNum) {
00091             if (IntersectRayTriangle(vRayPos,vRayDir,
00092                 data.GetVertexPosVec3(pIdx[0]),
00093                 data.GetVertexPosVec3(pIdx[1]),
00094                 data.GetVertexPosVec3(pIdx[2]),&myHitDist)) {
00095                 if (iFaceHit == -1 || myHitDist < *pfHitDist) { *pfHitDist = myHitDist; iFaceHit = iFaceNum; }
00096             }
00097         }
00098     }
00099     return iFaceHit;
00100 }
00101 
00102 // ***** ***** ***** ***** ***** cBufferedVertexData
00103 
00104 cBufferedVertexData::cBufferedVertexData() : miVertexCount(0) {}
00105     
00106 cBufferedVertexData::~cBufferedVertexData() {
00108     for (int i=0;i<mDataBuffers.size();++i) free(mDataBuffers[i]);
00109     mDataBuffers.clear();
00110     mDataBufferVertexSize.clear();
00111 }
00112 
00113 void    cBufferedVertexData::SetFromVertexData  (const Ogre::VertexData& pVertexData) {
00114     assert(mDataBuffers.size() == 0 && "do not init more than once");
00115     assert(mDataBufferVertexSize.size() == 0 && "do not init more than once");
00116     
00117     // copy vertex decl
00118     if (DEBUG_MESHBUFFER) printf("cBufferedVertexData::SetFromVertexData vertexdecl\n");
00119     mpVertexDecl = pVertexData.vertexDeclaration ? pVertexData.vertexDeclaration->clone() : 0;
00120     
00121     // vertex count
00122     miVertexCount = pVertexData.vertexCount;
00123     
00124     // copy buffers
00125     int iBufferCount = mpVertexDecl ? (mpVertexDecl->getMaxSource()+1) : 0; // pVertexData.vertexBufferBinding->getBufferCount()
00126     if (DEBUG_MESHBUFFER) printf("cBufferedVertexData::SetFromVertexData buffers:%d %d\n",iBufferCount,(int)pVertexData.vertexBufferBinding->getBufferCount());
00127     for (int iBuffer=0;iBuffer<iBufferCount;++iBuffer) {
00128         // prepare buffer
00129         HardwareVertexBufferSharedPtr vbuf = pVertexData.vertexBufferBinding->getBuffer(iBuffer);
00130         
00131         // prepare buffer in main-RAM (instead of vram)
00132         int iDataSize = miVertexCount * vbuf->getVertexSize();
00133         if (DEBUG_MESHBUFFER) printf("cBufferedVertexData::SetFromVertexData buffer[%d] vsize=%d\n",iBuffer,(int)vbuf->getVertexSize());
00134         char* pRAMBuffer = (char*)malloc(iDataSize);
00135         mDataBuffers.push_back(pRAMBuffer);
00136         mDataBufferVertexSize.push_back(vbuf->getVertexSize());
00137         
00138         // copy data from vram
00139         vbuf->readData(0,iDataSize,pRAMBuffer);
00140     }
00141     
00142     // quick access for position and texcoords (for mousepicking, texcoords for alpha pick later)
00143     if (DEBUG_MESHBUFFER) printf("cBufferedVertexData::SetFromVertexData prepare quick access\n");
00144     SetQuickDataFromSemantic(mQuickPos,Ogre::VES_POSITION);
00145     SetQuickDataFromSemantic(mQuickTexCoord,Ogre::VES_TEXTURE_COORDINATES);
00146     if (DEBUG_MESHBUFFER) printf("cBufferedVertexData::SetFromVertexData done\n");
00147 }
00148 
00149 void    cBufferedVertexData::SetQuickDataFromSemantic   (cQuickData& pQuickData,const Ogre::VertexElementSemantic sem,const int i) {
00150     assert(!pQuickData.mpFirst && !pQuickData.miOffsetToNext && "do not init more than once");
00151     
00152     // search for semantic (Ogre::VES_POSITION,Ogre::VES_TEXTURE_COORDINATES...)
00153     const Ogre::VertexElement* elem = mpVertexDecl ? mpVertexDecl->findElementBySemantic(sem,i) : 0;
00154     if (!elem) return;
00155     
00156     // find out in which buffer the element is
00157     unsigned short iSource = elem->getSource();
00158     assert(iSource < mDataBuffers.size());
00159     
00160     // prepare quick access
00161     pQuickData.mpFirst = mDataBuffers[iSource] + elem->getOffset();
00162     pQuickData.miOffsetToNext = mpVertexDecl->getVertexSize(iSource);
00163 }       
00164 
00165 
00166 
00167 
00168 // ***** ***** ***** ***** ***** cBufferedSubMesh
00169 
00170 cBufferedSubMesh::cBufferedSubMesh() : mbUseSharedVertexData(false), mpParent(0) {}
00171 
00172 void    cBufferedSubMesh::TransformTexCoords    (const float u0,const float v0,const float u1,const float v1) {
00173     if (GetUsesShared()) { printf("ERROR: cBufferedSubMesh::TransformTexCoords : shared vertex data not supported (oldmat=%s)\n",msMatName.c_str()); return; }
00174     float ud = u1 - u0;
00175     float vd = v1 - v0;
00176     for (int i=0;i<GetVertexCount();++i) {
00177         float* p = mBufferedVertexData.GetVertexTexCoord(i);
00178         p[0] = u0 + ud*mymax(0.0,mymin(1.0,p[0]));
00179         p[1] = v0 + vd*mymax(0.0,mymin(1.0,p[1]));
00180     }
00181 }
00182 
00183 void    cBufferedSubMesh::SetMatName            (const char* szMatName) {
00184     msMatName = szMatName;
00185     try {
00186         mpMat = Ogre::MaterialManager::getSingleton().getByName(msMatName);
00187     } catch (...) {} // it's shouldn't be fatal here if the material is not found, the rest is still very useful
00188 }
00189 
00190 void    cBufferedSubMesh::SetFromSubMesh    (cBufferedMesh* pParent,Ogre::SubMesh& pSubMesh) {
00191     if (DEBUG_MESHBUFFER) printf("cBufferedSubMesh::SetFromSubMesh\n");
00192     
00193     // set parent
00194     mpParent = pParent;
00195     
00196     // read material 
00197     SetMatName(pSubMesh.getMaterialName().c_str());
00198     
00199     // read vertexdata
00200     mbUseSharedVertexData = pSubMesh.useSharedVertices;
00201     if (!mbUseSharedVertexData) {
00202         if (pSubMesh.vertexData)
00203                 mBufferedVertexData.SetFromVertexData(*pSubMesh.vertexData);
00204         else    printf("cBufferedSubMesh::SetFromSubMesh warning, empty submesh vertex data\n");
00205     }
00206     if (DEBUG_MESHBUFFER) printf("cBufferedSubMesh::SetFromSubMesh mat=%s mbUseSharedVertexData=%d\n",msMatName.c_str(),mbUseSharedVertexData?1:0);
00207     
00208     // calculate format hash  (a string describing the vertex-format, helpful for grouping in batch-code)
00209     Ogre::VertexElementType iPreferredColourFormat = Root::getSingleton().getRenderSystem()->getColourVertexElementType(); // Ogre::VET_COLOUR;
00210     if (DEBUG_MESHBUFFER) printf("cBufferedSubMesh::SetFromSubMesh hash start\n");
00211     if (mBufferedVertexData.GetVertexDecl()) {
00212         Ogre::StringUtil::StrStreamType str;
00213         bool bHasColour = false;
00214         str << msMatName << "|";
00215         //~ str << pSubMesh.indexData->indexBuffer->getType() << "|";
00216         const Ogre::VertexDeclaration::VertexElementList &elemList = mBufferedVertexData.GetVertexDecl()->getElements();
00217         Ogre::VertexDeclaration::VertexElementList::const_iterator i;
00218         for (i = elemList.begin(); i != elemList.end(); ++i) {
00219             const Ogre::VertexElement &element = *i;
00220             str << element.getSource()      << "|";
00221             str << element.getSemantic()    << "|";
00222             str << element.getType()        << "|";
00223             if (element.getSemantic() == Ogre::VES_DIFFUSE) bHasColour = true;
00224         }
00225         msFormatHash = str.str();
00226         if (bHasColour) {
00227             msFormatHashWithColour = msFormatHash;
00228         } else {
00229             // append extra colour field to format (mainly used for fastbatch vertex colouring)
00230             str << 0                        << "|"; // element.getSource()
00231             str << Ogre::VES_DIFFUSE        << "|"; // element.getSemantic()
00232             str << iPreferredColourFormat   << "|"; // element.getType()
00233             msFormatHashWithColour = str.str();
00234         }
00235     }
00236     if (DEBUG_MESHBUFFER) printf("cBufferedSubMesh::SetFromSubMesh hash done\n");
00237         
00238     // read index data
00239     IndexData* index_data = pSubMesh.indexData;
00240     HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
00241 
00242     mIndexData.clear();
00243     mIndexData.reserve(index_data->indexCount);
00244     if (DEBUG_MESHBUFFER) printf("cBufferedSubMesh::SetFromSubMesh indices=%d\n",(int)index_data->indexCount);
00245     if (ibuf->getType() == HardwareIndexBuffer::IT_32BIT) {
00246 		::uint32* pReader = static_cast< ::uint32*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
00247         for (int i=0;i<index_data->indexCount;++i) mIndexData.push_back(static_cast<unsigned int>(pReader[i]));
00248     } else {
00249 		::uint16* pReader = static_cast< ::uint16*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
00250         for (int i=0;i<index_data->indexCount;++i) mIndexData.push_back(static_cast<unsigned int>(pReader[i]));
00251     }
00252     ibuf->unlock();
00253     if (DEBUG_MESHBUFFER) printf("cBufferedSubMesh::SetFromSubMesh done\n");
00254 }
00255     
00256 
00257 
00258 };

Generated on Wed Feb 8 06:00:13 2012 for cpp by  doxygen 1.5.6