Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgrePatchSurface.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 
00027 #include "OgrePatchSurface.h"
00028 
00029 #include "OgreMeshManager.h"
00030 #include "OgreMesh.h"
00031 #include "OgreSubMesh.h"
00032 #include "OgreException.h"
00033 #include "OgreHardwareBufferManager.h"
00034 #include "OgreHardwareVertexBuffer.h"
00035 #include "OgreHardwareIndexBuffer.h"
00036 
00037 #define LEVEL_WIDTH(lvl) ((1 << (lvl+1)) + 1)
00038 
00039 namespace Ogre {
00040 
00041     // TODO: make this deal with specular colours and more than 2 texture coords
00042 
00043     //-----------------------------------------------------------------------
00044     PatchSurface::PatchSurface()
00045     {
00046         mType = PST_BEZIER;
00047     }
00048     //-----------------------------------------------------------------------
00049     PatchSurface::~PatchSurface()
00050     {
00051     }
00052     //-----------------------------------------------------------------------
00053     void PatchSurface::defineSurface(void* controlPointBuffer, 
00054             VertexDeclaration *declaration, size_t width, size_t height,
00055             PatchSurfaceType pType, size_t uMaxSubdivisionLevel, 
00056             size_t vMaxSubdivisionLevel, VisibleSide visibleSide)
00057     {
00058         if (height == 0 || width == 0)
00059             return; // Do nothing - garbage
00060 
00061         mType = pType;
00062         mCtlWidth = width;
00063         mCtlHeight = height;
00064         mCtlCount = width * height;
00065         mControlPointBuffer = controlPointBuffer;
00066         mDeclaration = declaration;
00067 
00068         // Copy positions into Vector3 vector
00069         mVecCtlPoints.clear();
00070         const VertexElement* elem = declaration->findElementBySemantic(VES_POSITION);
00071         size_t vertSize = declaration->getVertexSize(0);
00072         const unsigned char *pVert = static_cast<const unsigned char*>(controlPointBuffer);
00073         Real* pReal;
00074         for (size_t i = 0; i < mCtlCount; ++i)
00075         {
00076             elem->baseVertexPointerToElement((void*)pVert, &pReal);
00077             mVecCtlPoints.push_back(Vector3(pReal));
00078             pVert += vertSize;
00079         }
00080 
00081         mVSide = visibleSide;
00082 
00083         // Determine max level
00084         // Initialise to 100% detail
00085         mSubdivisionFactor = 1.0f;
00086         if (uMaxSubdivisionLevel == AUTO_LEVEL)
00087         {
00088             mULevel = mMaxULevel = getAutoULevel();
00089         }
00090         else
00091         {
00092             mULevel = mMaxULevel = uMaxSubdivisionLevel;
00093         }
00094 
00095         if (vMaxSubdivisionLevel == AUTO_LEVEL)
00096         {
00097             mVLevel = mMaxVLevel = getAutoVLevel();
00098         }
00099         else
00100         {
00101             mVLevel = mMaxVLevel = vMaxSubdivisionLevel;
00102         }
00103 
00104 
00105 
00106         // Derive mesh width / height
00107         mMeshWidth  = (LEVEL_WIDTH(mMaxULevel)-1) * ((mCtlWidth-1)/2) + 1;
00108         mMeshHeight = (LEVEL_WIDTH(mMaxVLevel)-1) * ((mCtlHeight-1)/2) + 1;
00109 
00110 
00111         // Calculate number of required vertices / indexes at max resolution
00112         mRequiredVertexCount = mMeshWidth * mMeshHeight;
00113         int iterations = (mVSide == VS_BOTH)? 2 : 1;
00114         mRequiredIndexCount = (mMeshWidth-1) * (mMeshHeight-1) * 2 * iterations * 3;
00115 
00116         // Calculate bounds based on control points
00117         std::vector<Vector3>::const_iterator ctli;
00118         Vector3 min, max;
00119         Real maxSqRadius;
00120         bool first = true;
00121         for (ctli = mVecCtlPoints.begin(); ctli != mVecCtlPoints.end(); ++ctli)
00122         {
00123             if (first)
00124             {
00125                 min = max = *ctli;
00126                 maxSqRadius = ctli->squaredLength();
00127                 first = false;
00128             }
00129             else
00130             {
00131                 min.makeFloor(*ctli);
00132                 max.makeCeil(*ctli);
00133                 maxSqRadius = std::max(ctli->squaredLength(), maxSqRadius);
00134 
00135             }
00136         }
00137         mAABB.setExtents(min, max);
00138         mBoundingSphere = Math::Sqrt(maxSqRadius);
00139 
00140     }
00141     //-----------------------------------------------------------------------
00142     const AxisAlignedBox& PatchSurface::getBounds(void) const
00143     {
00144         return mAABB;
00145     }
00146     //-----------------------------------------------------------------------
00147     Real PatchSurface::getBoundingSphereRadius(void) const
00148     {
00149         return mBoundingSphere;
00150     }
00151     //-----------------------------------------------------------------------
00152     size_t PatchSurface::getRequiredVertexCount(void) const
00153     {
00154         return mRequiredVertexCount;
00155     }
00156     //-----------------------------------------------------------------------
00157     size_t PatchSurface::getRequiredIndexCount(void) const
00158     {
00159         return mRequiredIndexCount;
00160     }
00161     //-----------------------------------------------------------------------
00162     void PatchSurface::build(HardwareVertexBufferSharedPtr destVertexBuffer, 
00163         size_t vertexStart, HardwareIndexBufferSharedPtr destIndexBuffer, size_t indexStart)
00164     {
00165 
00166         if (mVecCtlPoints.empty())
00167             return;
00168 
00169         mVertexBuffer = destVertexBuffer;
00170         mVertexOffset = vertexStart;
00171         mIndexBuffer = destIndexBuffer;
00172         mIndexOffset = indexStart;
00173 
00174         // Lock just the region we are interested in 
00175         void* lockedBuffer = mVertexBuffer->lock(
00176             mVertexOffset * mDeclaration->getVertexSize(0), 
00177             mRequiredVertexCount * mDeclaration->getVertexSize(0),
00178             HardwareBuffer::HBL_NO_OVERWRITE);
00179 
00180         distributeControlPoints(lockedBuffer);
00181 
00182         // Subdivide the curve to the MAX :)
00183         // Do u direction first, so need to step over v levels not done yet
00184         size_t vStep = 1 << mMaxVLevel;
00185         size_t uStep = 1 << mMaxULevel;
00186 
00187         size_t v, u;
00188         for (v = 0; v < mMeshHeight; v += vStep)
00189         {
00190             // subdivide this row in u
00191             subdivideCurve(lockedBuffer, v*mMeshWidth, uStep, mMeshWidth / uStep, mULevel);
00192         }
00193 
00194         // Now subdivide in v direction, this time all the u direction points are there so no step
00195         for (u = 0; u < mMeshWidth; ++u)
00196         {
00197             subdivideCurve(lockedBuffer, u, vStep*mMeshWidth, mMeshHeight / vStep, mVLevel);
00198         }
00199         
00200 
00201         mVertexBuffer->unlock();
00202 
00203         // Make triangles from mesh at this current level of detail
00204         makeTriangles();
00205 
00206     }
00207     //-----------------------------------------------------------------------
00208     size_t PatchSurface::getAutoULevel(bool forMax)
00209     {
00210         // determine levels
00211         // Derived from work by Bart Sekura in Rogl
00212         Vector3 a,b,c;
00213         size_t u,v;
00214         bool found=false;
00215         // Find u level
00216         for(v = 0; v < mCtlHeight; v++) {
00217             for(u = 0; u < mCtlWidth-1; u += 2) {
00218                 a = mVecCtlPoints[v * mCtlWidth + u];
00219                 b = mVecCtlPoints[v * mCtlWidth + u+1];
00220                 c = mVecCtlPoints[v * mCtlWidth + u+2];
00221                 if(a!=c) {
00222                     found=true;
00223                     break;
00224                 }
00225             }
00226             if(found) break;
00227         }
00228         if(!found) {
00229             Except(Exception::ERR_INTERNAL_ERROR, "Can't find suitable control points for determining U subdivision level",
00230                 "PatchSurface::getAutoULevel");
00231         }
00232 
00233         return findLevel(a,b,c);
00234 
00235     }
00236     //-----------------------------------------------------------------------
00237     size_t PatchSurface::getAutoVLevel(bool forMax)
00238     {
00239         Vector3 a,b,c;
00240         size_t u,v;
00241         bool found=false;
00242         for(u = 0; u < mCtlWidth; u++) {
00243             for(v = 0; v < mCtlHeight-1; v += 2) {
00244                 a = mVecCtlPoints[v * mCtlWidth + u];
00245                 b = mVecCtlPoints[(v+1) * mCtlWidth + u];
00246                 c = mVecCtlPoints[(v+2) * mCtlWidth + u];
00247                 if(a!=c) {
00248                     found=true;
00249                     break;
00250                 }
00251             }
00252             if(found) break;
00253         }
00254         if(!found) {
00255             Except(Exception::ERR_INTERNAL_ERROR, "Can't find suitable control points for determining V subdivision level",
00256                 "PatchSurface::getAutoVLevel");
00257         }
00258 
00259         return findLevel(a,b,c);
00260 
00261     }
00262     //-----------------------------------------------------------------------
00263     void PatchSurface::setSubdivisionFactor(Real factor)
00264     {
00265         assert(factor >= 0.0f && factor <= 1.0f);
00266 
00267         mULevel = factor * mMaxULevel;
00268         mVLevel = factor * mMaxVLevel;
00269 
00270         makeTriangles();
00271 
00272 
00273     }
00274     //-----------------------------------------------------------------------
00275     size_t PatchSurface::getCurrentIndexCount(void) const
00276     {
00277         return mCurrIndexCount;
00278     }
00279     //-----------------------------------------------------------------------
00280     size_t PatchSurface::findLevel(Vector3& a, Vector3& b, Vector3& c)
00281     {
00282         // Derived from work by Bart Sekura in rogl
00283         // Apart from I think I fixed a bug - see below
00284         // I also commented the code, the only thing wrong with rogl is almost no comments!!
00285 
00286         const size_t max_levels = 5;
00287         const float subdiv = 10;
00288         size_t level;
00289 
00290         float test=subdiv*subdiv;
00291         Vector3 s,t,d;
00292         for(level=0; level<max_levels-1; level++)
00293         {
00294             // Subdivide the 2 lines
00295             s = a.midPoint(b);
00296             t = b.midPoint(c);
00297             // Find the midpoint between the 2 midpoints
00298             c = s.midPoint(t);
00299             // Get the vector between this subdivided midpoint and the middle point of the original line
00300             d = c - b;
00301             // Find the squared length, and break when small enough
00302             if(d.dotProduct(d) < test) {
00303                 break;
00304             }
00305             b=a; 
00306         }
00307 
00308         return level;
00309 
00310     }
00311 
00312     /*
00313     //-----------------------------------------------------------------------
00314     void PatchSurface::allocateMemory(void)
00315     {
00316         if (mMemoryAllocated)
00317             deallocateMemory();
00318 
00319         // Allocate to the size of max level
00320 
00321         // Create mesh
00322         mMesh = MeshManager::getSingleton().createManual(mMeshName);
00323         mMesh->sharedVertexData = new VertexData();
00324         // Copy all vertex parameters
00325         mMesh->sharedVertexData->vertexStart = 0;
00326         // Vertex count will be set on build() because it depends on current level
00327         // NB clone the declaration because Mesh's VertexData will destroy it
00328         mMesh->sharedVertexData->vertexDeclaration = mDeclaration->clone();
00329         // Create buffer (only a single buffer)
00330         // Allocate enough buffer memory for maximum subdivision, not current subdivision
00331         HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().
00332             createVertexBuffer(
00333                 mDeclaration->getVertexSize(0), 
00334                 mMaxMeshHeight * mMaxMeshWidth, // maximum size 
00335                 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // dynamic for changing level
00336 
00337         // Set binding
00338         mMesh->sharedVertexData->vertexBufferBinding->setBinding(0, vbuf);
00339 
00340         SubMesh* sm = mMesh->createSubMesh();
00341         // Allocate enough index data for max subdivision
00342         sm->indexData->indexStart = 0;
00343         // Index count will be set on build()
00344         unsigned short iterations = (mVSide == VS_BOTH ? 2 : 1);
00345         sm->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
00346             HardwareIndexBuffer::IT_16BIT, 
00347             (mMaxMeshWidth-1) * (mMaxMeshHeight-1) * 2 * iterations * 3,  
00348             HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
00349 
00350         mMesh->load();
00351 
00352         // Derive bounds from control points, cannot stray outside that
00353         Vector3 min, max;
00354         Real maxSquaredRadius;
00355         bool first = true;
00356         std::vector<Vector3>::iterator i, iend;
00357         iend = mVecCtlPoints.end();
00358         for (i = mVecCtlPoints.begin(); i != iend; ++i)
00359         {
00360             if (first)
00361             {
00362                 min = max = *i;
00363                 maxSquaredRadius = i->squaredLength();
00364             }
00365             else
00366             {
00367                 min.makeFloor(*i);
00368                 max.makeCeil(*i);
00369                 maxSquaredRadius = std::max(maxSquaredRadius, i->squaredLength());
00370             }
00371 
00372         }
00373         mMesh->_setBounds(AxisAlignedBox(min, max));
00374         mMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius));
00375 
00376 
00377 
00378     }
00379     */
00380     //-----------------------------------------------------------------------
00381     void PatchSurface::distributeControlPoints(void* lockedBuffer)
00382     {
00383         // Insert original control points into expanded mesh
00384         size_t uStep = 1 << mULevel;
00385         size_t vStep = 1 << mVLevel;
00386 
00387 
00388         void* pSrc = mControlPointBuffer;
00389         size_t vertexSize = mDeclaration->getVertexSize(0);
00390         Real *pSrcReal, *pDestReal;
00391         RGBA *pSrcRGBA, *pDestRGBA;
00392         void* pDest;
00393         const VertexElement* elemPos = mDeclaration->findElementBySemantic(VES_POSITION);
00394         const VertexElement* elemNorm = mDeclaration->findElementBySemantic(VES_NORMAL);
00395         const VertexElement* elemTex0 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 0);
00396         const VertexElement* elemTex1 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 1);
00397         const VertexElement* elemDiffuse = mDeclaration->findElementBySemantic(VES_DIFFUSE);
00398         for (size_t v = 0; v < mMeshHeight; v += vStep)
00399         {
00400             // set dest by v from base
00401             pDest = static_cast<void*>(
00402                 static_cast<unsigned char*>(lockedBuffer) + (vertexSize * mMeshWidth * v));
00403             for (size_t u = 0; u < mMeshWidth; u += uStep)
00404             {
00405 
00406                 // Copy Position
00407                 elemPos->baseVertexPointerToElement(pSrc, &pSrcReal);
00408                 elemPos->baseVertexPointerToElement(pDest, &pDestReal);
00409                 *pDestReal++ = *pSrcReal++;
00410                 *pDestReal++ = *pSrcReal++;
00411                 *pDestReal++ = *pSrcReal++;
00412 
00413                 // Copy Normals
00414                 if (elemNorm)
00415                 {
00416                     elemNorm->baseVertexPointerToElement(pSrc, &pSrcReal);
00417                     elemNorm->baseVertexPointerToElement(pDest, &pDestReal);
00418                     *pDestReal++ = *pSrcReal++;
00419                     *pDestReal++ = *pSrcReal++;
00420                     *pDestReal++ = *pSrcReal++;
00421                 }
00422 
00423                 // Copy Diffuse
00424                 if (elemDiffuse)
00425                 {
00426                     elemDiffuse->baseVertexPointerToElement(pSrc, &pSrcRGBA);
00427                     elemDiffuse->baseVertexPointerToElement(pDest, &pDestRGBA);
00428                     *pDestRGBA++ = *pSrcRGBA++;
00429                 }
00430 
00431                 // Copy texture coords
00432                 if (elemTex0)
00433                 {
00434                     elemTex0->baseVertexPointerToElement(pSrc, &pSrcReal);
00435                     elemTex0->baseVertexPointerToElement(pDest, &pDestReal);
00436                     for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex0->getType()); ++dim)
00437                         *pDestReal++ = *pSrcReal++;
00438                 }
00439                 if (elemTex1)
00440                 {
00441                     elemTex1->baseVertexPointerToElement(pSrc, &pSrcReal);
00442                     elemTex1->baseVertexPointerToElement(pDest, &pDestReal);
00443                     for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex1->getType()); ++dim)
00444                         *pDestReal++ = *pSrcReal++;
00445                 }
00446 
00447                 // Increment source by one vertex
00448                 pSrc = static_cast<void*>(
00449                     static_cast<unsigned char*>(pSrc) + vertexSize);
00450                 // Increment dest by 1 vertex * uStep
00451                 pDest = static_cast<void*>(
00452                     static_cast<unsigned char*>(pDest) + (vertexSize * uStep));
00453             } // u
00454         } // v
00455 
00456        
00457     }
00458     //-----------------------------------------------------------------------
00459     void PatchSurface::subdivideCurve(void* lockedBuffer, size_t startIdx, size_t stepSize, size_t numSteps, size_t iterations)
00460     {
00461         // Subdivides a curve within a sparsely populated buffer (gaps are already there to be interpolated into)
00462         size_t leftIdx, rightIdx, destIdx, halfStep, maxIdx;
00463         bool firstSegment;
00464 
00465         maxIdx = startIdx + (numSteps * stepSize);
00466         size_t step = stepSize;
00467 
00468         while(iterations--)
00469         {
00470             halfStep = step / 2;
00471             leftIdx = startIdx;
00472             destIdx = leftIdx + halfStep;
00473             rightIdx = leftIdx + step;
00474             firstSegment = true;
00475             while (leftIdx < maxIdx)
00476             {
00477                 // Interpolate
00478                 interpolateVertexData(lockedBuffer, leftIdx, rightIdx, destIdx);
00479 
00480                 // If 2nd or more segment, interpolate current left between current and last mid points
00481                 if (!firstSegment)
00482                 {
00483                     interpolateVertexData(lockedBuffer, leftIdx - halfStep, leftIdx + halfStep, leftIdx);
00484                 }
00485                 // Next segment
00486                 leftIdx = rightIdx;
00487                 destIdx = leftIdx + halfStep;
00488                 rightIdx = leftIdx + step;
00489                 firstSegment = false;
00490             }
00491 
00492             step = halfStep;
00493         }
00494     }
00495     //-----------------------------------------------------------------------
00496     void PatchSurface::makeTriangles(void)
00497     {
00498         // Our vertex buffer is subdivided to the highest level, we need to generate tris
00499         // which step over the vertices we don't need for this level of detail.
00500 
00501         // Calculate steps
00502         int vStep = 1 << (mMaxVLevel - mVLevel);
00503         int uStep = 1 << (mMaxULevel - mULevel);
00504         size_t currWidth = (LEVEL_WIDTH(mULevel)-1) * ((mCtlWidth-1)/2) + 1;
00505         size_t currHeight = (LEVEL_WIDTH(mVLevel)-1) * ((mCtlHeight-1)/2) + 1;
00506 
00507         bool use32bitindexes = (mIndexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
00508 
00509         // The mesh is built, just make a list of indexes to spit out the triangles
00510         int vInc, uInc;
00511         
00512         size_t vCount, uCount, v, u, iterations;
00513 
00514         if (mVSide == VS_BOTH)
00515         {
00516             iterations = 2;
00517             vInc = vStep;
00518             v = 0; // Start with front
00519         }
00520         else
00521         {
00522             iterations = 1;
00523             if (mVSide == VS_FRONT)
00524             {
00525                 vInc = vStep;
00526                 v = 0;
00527             }
00528             else
00529             {
00530                 vInc = -vStep;
00531                 v = mMeshHeight - 1;
00532             }
00533         }
00534 
00535         // Calc num indexes
00536         mCurrIndexCount = (currWidth - 1) * (currHeight - 1) * 6 * iterations;
00537 
00538         size_t v1, v2, v3;
00539         // Lock just the section of the buffer we need
00540         unsigned short* p16;
00541         unsigned int* p32;
00542         if (use32bitindexes)
00543         {
00544             p32 = static_cast<unsigned int*>(
00545                 mIndexBuffer->lock(
00546                     mIndexOffset * sizeof(unsigned int), 
00547                     mRequiredIndexCount * sizeof(unsigned int), 
00548                     HardwareBuffer::HBL_NO_OVERWRITE));
00549         }
00550         else
00551         {
00552             p16 = static_cast<unsigned short*>(
00553                 mIndexBuffer->lock(
00554                     mIndexOffset * sizeof(unsigned short), 
00555                     mRequiredIndexCount * sizeof(unsigned short), 
00556                     HardwareBuffer::HBL_NO_OVERWRITE));
00557         }
00558 
00559         while (iterations--)
00560         {
00561             // Make tris in a zigzag pattern (compatible with strips)
00562             u = 0;
00563             uInc = uStep; // Start with moving +u
00564 
00565             vCount = currHeight - 1;
00566             while (vCount--)
00567             {
00568                 uCount = currWidth - 1;
00569                 while (uCount--)
00570                 {
00571                     // First Tri in cell
00572                     // -----------------
00573                     v1 = ((v + vInc) * mMeshWidth) + u;
00574                     v2 = (v * mMeshWidth) + u;
00575                     v3 = ((v + vInc) * mMeshWidth) + (u + uInc);
00576                     // Output indexes
00577                     if (use32bitindexes)
00578                     {
00579                         *p32++ = static_cast<unsigned int>(v1);
00580                         *p32++ = static_cast<unsigned int>(v2);
00581                         *p32++ = static_cast<unsigned int>(v3);
00582                     }
00583                     else
00584                     {
00585                         *p16++ = static_cast<unsigned short>(v1);
00586                         *p16++ = static_cast<unsigned short>(v2);
00587                         *p16++ = static_cast<unsigned short>(v3);
00588                     }
00589                     // Second Tri in cell
00590                     // ------------------
00591                     v1 = ((v + vInc) * mMeshWidth) + (u + uInc);
00592                     v2 = (v * mMeshWidth) + u;
00593                     v3 = (v * mMeshWidth) + (u + uInc);
00594                     // Output indexes
00595                     if (use32bitindexes)
00596                     {
00597                         *p32++ = static_cast<unsigned int>(v1);
00598                         *p32++ = static_cast<unsigned int>(v2);
00599                         *p32++ = static_cast<unsigned int>(v3);
00600                     }
00601                     else
00602                     {
00603                         *p16++ = static_cast<unsigned short>(v1);
00604                         *p16++ = static_cast<unsigned short>(v2);
00605                         *p16++ = static_cast<unsigned short>(v3);
00606                     }
00607 
00608                     // Next column
00609                     u += uInc;
00610                 }
00611                 // Next row
00612                 v += vInc;
00613                 u = 0;
00614 
00615 
00616             }
00617 
00618             // Reverse vInc for double sided
00619             v = mMeshHeight - 1;
00620             vInc = -vInc;
00621 
00622         }
00623 
00624         mIndexBuffer->unlock();
00625 
00626 
00627     }
00628     //-----------------------------------------------------------------------
00629     void PatchSurface::interpolateVertexData(void* lockedBuffer, size_t leftIdx, size_t rightIdx, size_t destIdx)
00630     {
00631         size_t vertexSize = mDeclaration->getVertexSize(0);
00632         const VertexElement* elemPos = mDeclaration->findElementBySemantic(VES_POSITION);
00633         const VertexElement* elemNorm = mDeclaration->findElementBySemantic(VES_NORMAL);
00634         const VertexElement* elemDiffuse = mDeclaration->findElementBySemantic(VES_DIFFUSE);
00635         const VertexElement* elemTex0 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 0);
00636         const VertexElement* elemTex1 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 1);
00637 
00638         Real *pDestReal, *pLeftReal, *pRightReal;
00639         unsigned char *pDestChar, *pLeftChar, *pRightChar;
00640         unsigned char *pDest, *pLeft, *pRight;
00641 
00642         // Set up pointers & interpolate
00643         pDest = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * destIdx);
00644         pLeft = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * leftIdx);
00645         pRight = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * rightIdx);
00646 
00647         // Position
00648         elemPos->baseVertexPointerToElement(pDest, &pDestReal);
00649         elemPos->baseVertexPointerToElement(pLeft, &pLeftReal);
00650         elemPos->baseVertexPointerToElement(pRight, &pRightReal);
00651 
00652         *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5;
00653         *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5;
00654         *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5;
00655 
00656         if (elemNorm)
00657         {
00658             elemNorm->baseVertexPointerToElement(pDest, &pDestReal);
00659             elemNorm->baseVertexPointerToElement(pLeft, &pLeftReal);
00660             elemNorm->baseVertexPointerToElement(pRight, &pRightReal);
00661             Vector3 norm;
00662             norm.x = (*pLeftReal++ + *pRightReal++) * 0.5;
00663             norm.y = (*pLeftReal++ + *pRightReal++) * 0.5;
00664             norm.z = (*pLeftReal++ + *pRightReal++) * 0.5;
00665             norm.normalise();
00666 
00667             *pDestReal++ = norm.x;
00668             *pDestReal++ = norm.y;
00669             *pDestReal++ = norm.z;
00670         }
00671         if (elemDiffuse)
00672         {
00673             // Blend each byte individually
00674             elemDiffuse->baseVertexPointerToElement(pDest, &pDestChar);
00675             elemDiffuse->baseVertexPointerToElement(pLeft, &pLeftChar);
00676             elemDiffuse->baseVertexPointerToElement(pRight, &pRightChar);
00677             // 4 bytes to RGBA
00678             *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5;
00679             *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5;
00680             *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5;
00681             *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5;
00682         }
00683         if (elemTex0)
00684         {
00685             elemTex0->baseVertexPointerToElement(pDest, &pDestReal);
00686             elemTex0->baseVertexPointerToElement(pLeft, &pLeftReal);
00687             elemTex0->baseVertexPointerToElement(pRight, &pRightReal);
00688 
00689             for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex0->getType()); ++dim)
00690                 *pDestReal++ = ((*pLeftReal++) + (*pRightReal++)) * 0.5;
00691         }
00692         if (elemTex1)
00693         {
00694             elemTex1->baseVertexPointerToElement(pDest, &pDestReal);
00695             elemTex1->baseVertexPointerToElement(pLeft, &pLeftReal);
00696             elemTex1->baseVertexPointerToElement(pRight, &pRightReal);
00697 
00698             for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex1->getType()); ++dim)
00699                 *pDestReal++ = ((*pLeftReal++) + (*pRightReal++)) * 0.5;
00700         }
00701     }
00702 
00703 }
00704 

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:21 2004