lugre_meshshape.cpp

Go to the documentation of this file.
00001 #include "lugre_prefix.h"
00002 #include "lugre_meshshape.h"
00003 #undef min
00004 #undef max
00005 #include <Ogre.h>
00006 #include <assert.h>
00007 using namespace Ogre;
00008 
00009 namespace Lugre {
00010     
00011 std::map<std::string,MeshShape*>    gMeshShapeCache;
00012 
00013 void    UnloadMeshShape     (const char* szMeshName) {
00014     MeshShape*& pShape = gMeshShapeCache[szMeshName];
00015     if (pShape) { delete pShape; pShape = 0; }
00016 }
00017 
00018 MeshShape*  MeshShape::GetMeshShape             (Ogre::Entity* pEntity) {
00019     if (!pEntity) return 0;
00020     Ogre::MeshPtr pMesh = pEntity->getMesh();
00021     assert(!pMesh.isNull() && "entity has no mesh");
00022     if (pMesh.isNull()) return 0;
00023         
00024     // look in cache
00025     MeshShape*& pShape = gMeshShapeCache[pMesh->getName()];
00026     if (pShape) { pShape->Update(pEntity); return pShape; }
00027         
00028     // register new shape
00029     pShape = new MeshShape(pMesh);
00030     pShape->Update(pEntity);
00031     return pShape;
00032 }
00033 
00034 MeshShape::MeshShape    (Ogre::MeshPtr pMesh) : mbInitialised(false), mpMesh(pMesh), mvMin(0,0,0), mvMax(0,0,0) {}
00035 MeshShape::~MeshShape   () {}
00036     
00037 
00038 /*
00039 // NOTE THAT THIS FUNCTION IS BASED ON MATERIAL FROM:
00040 
00041 // Magic Software, Inc.
00042 // http://www.geometrictools.com
00043 // Copyright (c) 2000, All Rights Reserved
00044 //
00045 // Source code from Magic Software is supplied under the terms of a license
00046 // agreement and may not be copied or disclosed except in accordance with the
00047 // terms of that agreement.  The various license agreements may be found at
00048 // the Magic Software web site.
00049 // http://www.geometrictools.com/License/WildMagic3License.pdf
00050 // see http://www.geometrictools.com/Foundation/Intersection/Wm3IntrRay3Triangle3.cpp
00051 
00052 // Find-intersection query.  The point of intersection is
00053 //   P = origin + t*direction = b0*V0 + b1*V1 + b2*V2
00054 // a,b,c are the 3 edges of the triangle
00055 */
00059 bool    IntersectRayTriangle    (const Vector3& ray_origin,const Vector3& ray_dir,const Vector3& a,const Vector3& b,const Vector3& c,float* pfHitDist,float* pfABC) {
00060     // compute the offset origin, edges, and normal
00061     Vector3 kDiff = ray_origin - a;
00062     Vector3 kEdge1 = b - a;
00063     Vector3 kEdge2 = c - a;
00064     Vector3 kNormal = kEdge1.crossProduct(kEdge2);
00065     Real    ZERO_TOLERANCE = 0.1E-6;
00066 
00067     // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
00068     // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
00069     //   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
00070     //   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
00071     //   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
00072     Real fDdN = ray_dir.dotProduct(kNormal);
00073     Real fSign;
00074     if (fDdN > ZERO_TOLERANCE)
00075     {
00076         fSign = (Real)1.0;
00077     }
00078     else if (fDdN < -ZERO_TOLERANCE)
00079     {
00080         fSign = (Real)-1.0;
00081         fDdN = -fDdN;
00082     }
00083     else
00084     {
00085         // Ray and triangle are parallel, call it a "no intersection"
00086         // even if the ray does intersect.
00087         return false;
00088     }
00089 
00090     Real fDdQxE2 = fSign*ray_dir.dotProduct(kDiff.crossProduct(kEdge2));
00091     if (fDdQxE2 >= (Real)0.0)
00092     {
00093         Real fDdE1xQ = fSign*ray_dir.dotProduct(kEdge1.crossProduct(kDiff));
00094         if (fDdE1xQ >= (Real)0.0)
00095         {
00096             if (fDdQxE2 + fDdE1xQ <= fDdN)
00097             {
00098                 // line intersects triangle, check if ray does
00099                 Real fQdN = -fSign*kDiff.dotProduct(kNormal);
00100                 if (fQdN >= (Real)0.0)
00101                 {
00102                     // ray intersects triangle
00103                     if (pfABC || pfHitDist) {
00104                         Real fInv = ((Real)1.0)/fDdN;
00105                         if (pfHitDist) *pfHitDist = fQdN*fInv;
00106                         if (pfABC) {
00107                             pfABC[1] = fDdQxE2*fInv;
00108                             pfABC[2] = fDdE1xQ*fInv;
00109                             pfABC[0] = (Real)1.0 - pfABC[1] - pfABC[2];
00110                         }
00111                     }
00112                     return true;
00113                 }
00114                 // else: t < 0, no intersection
00115             }
00116             // else: b1+b2 > 1, no intersection
00117         }
00118         // else: b2 < 0, no intersection
00119     }
00120     // else: b1 < 0, no intersection
00121 
00122     return false;
00123 }
00124 
00125 
00126     
00127 
00132 void    MeshShape::Update           (Ogre::Entity *pEntity) {
00133     // if (!pEntity) return;
00134     if (mpMesh.isNull()) return;
00135     if (pEntity && mbInitialised && !pEntity->hasSkeleton()) return; // no need to update static models every frame...
00136     mbInitialised = true;
00137     //printf("#### MeshShape::Update\n");
00138     //printf("MeshShape::Update skeleton=%d\n",pEntity->hasSkeleton()?1:0);
00139         
00140     //assert(pEntity->getMesh().get() == mpMesh.get() && "mesh pointer changed ! (ogrecaching/garbage collection?)");
00141     
00142     mlVertices.clear();
00143     mlIndices.clear();
00144         
00145     bool added_shared = false;
00146     size_t current_offset = 0;
00147     size_t shared_offset = 0;
00148     size_t next_offset = 0;
00149     size_t index_offset = 0;
00150     int numOfSubs = 0;
00151 
00152     // true if the entity is possibly animated (=has skeleton) , this means Update should be called every frame
00153     bool useSoftwareBlendingVertices = pEntity && pEntity->hasSkeleton();
00154 
00155     if (useSoftwareBlendingVertices)
00156     {
00157         pEntity->_updateAnimation();
00158     }
00159 
00160     // Run through the submeshes again, adding the data into the arrays
00161     for ( size_t i = 0; i < mpMesh->getNumSubMeshes(); ++i) {
00162         SubMesh* submesh = mpMesh->getSubMesh(i);
00163         bool useSharedVertices = submesh->useSharedVertices;
00164 
00165         //----------------------------------------------------------------
00166         // GET VERTEXDATA
00167         //----------------------------------------------------------------
00168         const VertexData * vertex_data;
00169         if(useSoftwareBlendingVertices)
00170                 vertex_data = useSharedVertices ? pEntity->_getSkelAnimVertexData() : pEntity->getSubEntity(i)->_getSkelAnimVertexData();
00171         else    vertex_data = useSharedVertices ? mpMesh->sharedVertexData : submesh->vertexData;
00172 
00173         if((!useSharedVertices)||(useSharedVertices && !added_shared))
00174         {
00175             if(useSharedVertices)
00176             {
00177                 added_shared = true;
00178                 shared_offset = current_offset;
00179             }
00180 
00181             const VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
00182             
00183             HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
00184 
00185             unsigned char* vertex =
00186                 static_cast<unsigned char*>(vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
00187 
00188             // There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
00189             //  as second argument. So make it float, to avoid trouble when Ogre::Real is
00190             //  comiled/typedefed as double:
00191             float* pReal;
00192 
00193             mlVertices.reserve(mlVertices.size()+vertex_data->vertexCount);
00194             for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
00195             {
00196                 posElem->baseVertexPointerToElement(vertex, &pReal);
00197                 if (mlVertices.size() == 0) {
00198                     mvMin.x = mvMax.x = pReal[0];
00199                     mvMin.y = mvMax.y = pReal[1];
00200                     mvMin.z = mvMax.z = pReal[2];
00201                 } else {
00202                     if (mvMin.x > pReal[0]) mvMin.x = pReal[0];
00203                     if (mvMin.y > pReal[1]) mvMin.y = pReal[1];
00204                     if (mvMin.z > pReal[2]) mvMin.z = pReal[2];
00205                     if (mvMax.x < pReal[0]) mvMax.x = pReal[0];
00206                     if (mvMax.y < pReal[1]) mvMax.y = pReal[1];
00207                     if (mvMax.z < pReal[2]) mvMax.z = pReal[2];
00208                 }
00209                 mlVertices.push_back(Vector3(pReal[0],pReal[1],pReal[2]));
00210             }
00211 
00212             vbuf->unlock();
00213             next_offset += vertex_data->vertexCount;
00214         }
00215         
00216         
00217         // TODO : GET TEXCOORD DATA
00218         // TODO : GET FACE-MATERIAL MAP, or at least material cound....
00219         // TODO : no need to update index, texcoord and material buffers for animation !
00220         
00221         // TODO : const VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_TEXTURE_COORDINATES);
00222         // for texture alpha checking, VertexElementType should be VET_FLOAT2 
00223 
00224         //----------------------------------------------------------------
00225         // GET INDEXDATA
00226         //----------------------------------------------------------------
00227         IndexData* index_data = submesh->indexData;
00228         size_t numTris = index_data->indexCount / 3;
00229         HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
00230 
00231         bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
00232 
00233 		::uint32 *pLong = static_cast< ::uint32*>(ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
00234 		::uint16* pShort = reinterpret_cast< ::uint16*>(pLong);
00235 
00236         size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;
00237 
00238         mlIndices.reserve(mlIndices.size()+3*numTris);
00239         if ( use32bitindexes )
00240         {
00241             for ( size_t k = 0; k < numTris*3; ++k)
00242             {
00243                 mlIndices.push_back(pLong[k] + static_cast<int>(offset));
00244             }
00245         }
00246         else
00247         {
00248             for ( size_t k = 0; k < numTris*3; ++k)
00249             {
00250                 mlIndices.push_back(static_cast<int>(pShort[k]) + static_cast<int>(offset));
00251             }
00252         }
00253 
00254         ibuf->unlock();
00255 
00256         current_offset = next_offset;
00257     }
00258     //mvMid = 0.5*(mvMin + mvMax);
00259     //mfBoundRad = 0.5 * (mvMax - mvMin).length();
00260 }
00261 
00262 
00263 void    MeshShape::RayIntersect (const Ogre::Vector3& ray_origin,const Ogre::Vector3& ray_dir,std::vector<std::pair<float,int> > &pHitList) {
00264     if (mpMesh.isNull()) return;
00265     Vector3 vMid = 0.5*(mvMin + mvMax);
00266     float fRad = mymax((mvMin-vMid).length(),(mvMax-vMid).length());    
00267     if (!Ogre::Ray(ray_origin,ray_dir).intersects(Ogre::Sphere(vMid,fRad + 0.1)).first) return;
00268     float myHitDist;
00269     for (int i=0;i<mlIndices.size();i+=3) {
00270         if (IntersectRayTriangle(ray_origin,ray_dir,
00271             mlVertices[mlIndices[i+0]],
00272             mlVertices[mlIndices[i+1]],
00273             mlVertices[mlIndices[i+2]],&myHitDist)) {
00274             pHitList.push_back(std::make_pair(myHitDist,i/3));
00275         }
00276     }
00277 }
00278 
00281 int     MeshShape::RayIntersect (const Vector3& ray_origin,const Vector3& ray_dir,float* pfHitDist) {
00282     if (mpMesh.isNull()) return -1;
00283     // check bounding sphere first
00284     
00285     //printf("#WWW### MeshShape::RayIntersect %f\n",mpMesh->getBoundingSphereRadius());
00286     
00287     Vector3 vMid = 0.5*(mvMin + mvMax);
00288     float fRad = mymax((mvMin-vMid).length(),(mvMax-vMid).length());
00289     //float fRad = mpMesh->getBoundingSphereRadius();
00290     
00291     if (!Ogre::Ray(ray_origin,ray_dir).intersects(Ogre::Sphere(vMid,fRad + 0.1)).first) return -1;
00292     
00293     //printf("MeshShape::RayIntersect hitbounds : rad=%f\n",fRad);
00294     
00295     
00296     int iFaceHit = -1;
00297     float myHitDist;
00298     
00299     //printf("#WWW### MeshShape::RayIntersect rayhit %d\n",mlIndices.size());
00300     
00301     for (int i=0;i<mlIndices.size();i+=3) {
00302         if (IntersectRayTriangle(ray_origin,ray_dir,
00303             mlVertices[mlIndices[i+0]],
00304             mlVertices[mlIndices[i+1]],
00305             mlVertices[mlIndices[i+2]],&myHitDist)) {
00306             if (iFaceHit == -1 || myHitDist < *pfHitDist) { *pfHitDist = myHitDist; iFaceHit = i/3; }
00307         }
00308     }
00309     //printf("MeshShape::RayIntersect hit=%d dist=%f\n",bHit?1:0,bHit?(*pfHitDist):0);
00310     return iFaceHit;
00311 }
00312 
00313 };

Generated on Wed May 23 06:00:14 2012 for cpp by  doxygen 1.5.6