1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4     (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreStableHeaders.h"
29 
30 #include "OgrePatchSurface.h"
31 
32 #include "OgreMeshManager.h"
33 #include "OgreMesh.h"
34 #include "OgreSubMesh.h"
35 #include "OgreException.h"
36 #include "OgreHardwareBufferManager.h"
37 #include "OgreHardwareVertexBuffer.h"
38 #include "OgreHardwareIndexBuffer.h"
39 
40 #define LEVEL_WIDTH(lvl) ((1 << (lvl+1)) + 1)
41 
42 namespace Ogre {
43 
44     // TODO: make this deal with specular colours and more than 2 texture coords
45 
46     //-----------------------------------------------------------------------
PatchSurface()47     PatchSurface::PatchSurface()
48     {
49         mType = PST_BEZIER;
50     }
51     //-----------------------------------------------------------------------
~PatchSurface()52     PatchSurface::~PatchSurface()
53     {
54     }
55     //-----------------------------------------------------------------------
defineSurface(void * controlPointBuffer,VertexDeclaration * declaration,size_t width,size_t height,PatchSurfaceType pType,size_t uMaxSubdivisionLevel,size_t vMaxSubdivisionLevel,VisibleSide visibleSide)56     void PatchSurface::defineSurface(void* controlPointBuffer,
57             VertexDeclaration *declaration, size_t width, size_t height,
58             PatchSurfaceType pType, size_t uMaxSubdivisionLevel,
59             size_t vMaxSubdivisionLevel, VisibleSide visibleSide)
60     {
61         if (height == 0 || width == 0)
62             return; // Do nothing - garbage
63 
64         mType = pType;
65         mCtlWidth = width;
66         mCtlHeight = height;
67         mCtlCount = width * height;
68         mControlPointBuffer = controlPointBuffer;
69         mDeclaration = declaration;
70 
71         // Copy positions into Vector3 vector
72         mVecCtlPoints.clear();
73         const VertexElement* elem = declaration->findElementBySemantic(VES_POSITION);
74         size_t vertSize = declaration->getVertexSize(0);
75         const unsigned char *pVert = static_cast<const unsigned char*>(controlPointBuffer);
76         float* pFloat;
77         for (size_t i = 0; i < mCtlCount; ++i)
78         {
79             elem->baseVertexPointerToElement(const_cast<unsigned char*>(pVert), &pFloat);
80             mVecCtlPoints.push_back(Vector3(pFloat[0], pFloat[1], pFloat[2]));
81             pVert += vertSize;
82         }
83 
84         mVSide = visibleSide;
85 
86         // Determine max level
87         // Initialise to 100% detail
88         mSubdivisionFactor = 1.0f;
89         if (uMaxSubdivisionLevel == (size_t)AUTO_LEVEL)
90         {
91             mULevel = mMaxULevel = getAutoULevel();
92         }
93         else
94         {
95             mULevel = mMaxULevel = uMaxSubdivisionLevel;
96         }
97 
98         if (vMaxSubdivisionLevel == (size_t)AUTO_LEVEL)
99         {
100             mVLevel = mMaxVLevel = getAutoVLevel();
101         }
102         else
103         {
104             mVLevel = mMaxVLevel = vMaxSubdivisionLevel;
105         }
106 
107 
108 
109         // Derive mesh width / height
110         mMeshWidth  = (LEVEL_WIDTH(mMaxULevel)-1) * ((mCtlWidth-1)/2) + 1;
111         mMeshHeight = (LEVEL_WIDTH(mMaxVLevel)-1) * ((mCtlHeight-1)/2) + 1;
112 
113 
114         // Calculate number of required vertices / indexes at max resolution
115         mRequiredVertexCount = mMeshWidth * mMeshHeight;
116         int iterations = (mVSide == VS_BOTH)? 2 : 1;
117         mRequiredIndexCount = (mMeshWidth-1) * (mMeshHeight-1) * 2 * iterations * 3;
118 
119         // Calculate bounds based on control points
120         vector<Vector3>::type::const_iterator ctli;
121         Vector3 min = Vector3::ZERO, max = Vector3::UNIT_SCALE;
122         Real maxSqRadius = 0;
123         bool first = true;
124         for (ctli = mVecCtlPoints.begin(); ctli != mVecCtlPoints.end(); ++ctli)
125         {
126             if (first)
127             {
128                 min = max = *ctli;
129                 maxSqRadius = ctli->squaredLength();
130                 first = false;
131             }
132             else
133             {
134                 min.makeFloor(*ctli);
135                 max.makeCeil(*ctli);
136                 maxSqRadius = std::max(ctli->squaredLength(), maxSqRadius);
137 
138             }
139         }
140         mAABB.setExtents(min, max);
141         mBoundingSphere = Math::Sqrt(maxSqRadius);
142 
143     }
144     //-----------------------------------------------------------------------
getBounds(void) const145     const AxisAlignedBox& PatchSurface::getBounds(void) const
146     {
147         return mAABB;
148     }
149     //-----------------------------------------------------------------------
getBoundingSphereRadius(void) const150     Real PatchSurface::getBoundingSphereRadius(void) const
151     {
152         return mBoundingSphere;
153     }
154     //-----------------------------------------------------------------------
getRequiredVertexCount(void) const155     size_t PatchSurface::getRequiredVertexCount(void) const
156     {
157         return mRequiredVertexCount;
158     }
159     //-----------------------------------------------------------------------
getRequiredIndexCount(void) const160     size_t PatchSurface::getRequiredIndexCount(void) const
161     {
162         return mRequiredIndexCount;
163     }
164     //-----------------------------------------------------------------------
build(HardwareVertexBufferSharedPtr destVertexBuffer,size_t vertexStart,HardwareIndexBufferSharedPtr destIndexBuffer,size_t indexStart)165     void PatchSurface::build(HardwareVertexBufferSharedPtr destVertexBuffer,
166         size_t vertexStart, HardwareIndexBufferSharedPtr destIndexBuffer, size_t indexStart)
167     {
168 
169         if (mVecCtlPoints.empty())
170             return;
171 
172         mVertexBuffer = destVertexBuffer;
173         mVertexOffset = vertexStart;
174         mIndexBuffer = destIndexBuffer;
175         mIndexOffset = indexStart;
176 
177         // Lock just the region we are interested in
178         void* lockedBuffer = mVertexBuffer->lock(
179             mVertexOffset * mDeclaration->getVertexSize(0),
180             mRequiredVertexCount * mDeclaration->getVertexSize(0),
181             HardwareBuffer::HBL_NO_OVERWRITE);
182 
183         distributeControlPoints(lockedBuffer);
184 
185         // Subdivide the curve to the MAX :)
186         // Do u direction first, so need to step over v levels not done yet
187         size_t vStep = 1 << mMaxVLevel;
188         size_t uStep = 1 << mMaxULevel;
189 
190         size_t v, u;
191         for (v = 0; v < mMeshHeight; v += vStep)
192         {
193             // subdivide this row in u
194             subdivideCurve(lockedBuffer, v*mMeshWidth, uStep, mMeshWidth / uStep, mULevel);
195         }
196 
197         // Now subdivide in v direction, this time all the u direction points are there so no step
198         for (u = 0; u < mMeshWidth; ++u)
199         {
200             subdivideCurve(lockedBuffer, u, vStep*mMeshWidth, mMeshHeight / vStep, mVLevel);
201         }
202 
203 
204         mVertexBuffer->unlock();
205 
206         // Make triangles from mesh at this current level of detail
207         makeTriangles();
208 
209     }
210     //-----------------------------------------------------------------------
getAutoULevel(bool forMax)211     size_t PatchSurface::getAutoULevel(bool forMax)
212     {
213         // determine levels
214         // Derived from work by Bart Sekura in Rogl
215         Vector3 a,b,c;
216         size_t u,v;
217         bool found=false;
218         // Find u level
219         for(v = 0; v < mCtlHeight; v++) {
220             for(u = 0; u < mCtlWidth-1; u += 2) {
221                 a = mVecCtlPoints[v * mCtlWidth + u];
222                 b = mVecCtlPoints[v * mCtlWidth + u+1];
223                 c = mVecCtlPoints[v * mCtlWidth + u+2];
224                 if(a!=c) {
225                     found=true;
226                     break;
227                 }
228             }
229             if(found) break;
230         }
231         if(!found) {
232             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Can't find suitable control points for determining U subdivision level",
233                 "PatchSurface::getAutoULevel");
234         }
235 
236         return findLevel(a,b,c);
237 
238     }
239     //-----------------------------------------------------------------------
getAutoVLevel(bool forMax)240     size_t PatchSurface::getAutoVLevel(bool forMax)
241     {
242         Vector3 a,b,c;
243         size_t u,v;
244         bool found=false;
245         for(u = 0; u < mCtlWidth; u++) {
246             for(v = 0; v < mCtlHeight-1; v += 2) {
247                 a = mVecCtlPoints[v * mCtlWidth + u];
248                 b = mVecCtlPoints[(v+1) * mCtlWidth + u];
249                 c = mVecCtlPoints[(v+2) * mCtlWidth + u];
250                 if(a!=c) {
251                     found=true;
252                     break;
253                 }
254             }
255             if(found) break;
256         }
257         if(!found) {
258             OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Can't find suitable control points for determining V subdivision level",
259                 "PatchSurface::getAutoVLevel");
260         }
261 
262         return findLevel(a,b,c);
263 
264     }
265     //-----------------------------------------------------------------------
setSubdivisionFactor(Real factor)266     void PatchSurface::setSubdivisionFactor(Real factor)
267     {
268         assert(factor >= 0.0f && factor <= 1.0f);
269 
270         mSubdivisionFactor = factor;
271         mULevel = static_cast<size_t>(factor * mMaxULevel);
272         mVLevel = static_cast<size_t>(factor * mMaxVLevel);
273 
274         makeTriangles();
275 
276 
277     }
278     //-----------------------------------------------------------------------
getSubdivisionFactor(void) const279     Real PatchSurface::getSubdivisionFactor(void) const
280     {
281         return mSubdivisionFactor;
282     }
283     //-----------------------------------------------------------------------
getCurrentIndexCount(void) const284     size_t PatchSurface::getCurrentIndexCount(void) const
285     {
286         return mCurrIndexCount;
287     }
288     //-----------------------------------------------------------------------
findLevel(Vector3 & a,Vector3 & b,Vector3 & c)289     size_t PatchSurface::findLevel(Vector3& a, Vector3& b, Vector3& c)
290     {
291         // Derived from work by Bart Sekura in rogl
292         // Apart from I think I fixed a bug - see below
293         // I also commented the code, the only thing wrong with rogl is almost no comments!!
294 
295         const size_t max_levels = 5;
296         const float subdiv = 10;
297         size_t level;
298 
299         float test=subdiv*subdiv;
300         Vector3 s,t,d;
301         for(level=0; level<max_levels-1; level++)
302         {
303             // Subdivide the 2 lines
304             s = a.midPoint(b);
305             t = b.midPoint(c);
306             // Find the midpoint between the 2 midpoints
307             c = s.midPoint(t);
308             // Get the vector between this subdivided midpoint and the middle point of the original line
309             d = c - b;
310             // Find the squared length, and break when small enough
311             if(d.dotProduct(d) < test) {
312                 break;
313             }
314             b=a;
315         }
316 
317         return level;
318 
319     }
320 
321     /*
322     //-----------------------------------------------------------------------
323     void PatchSurface::allocateMemory(void)
324     {
325         if (mMemoryAllocated)
326             deallocateMemory();
327 
328         // Allocate to the size of max level
329 
330         // Create mesh
331         mMesh = MeshManager::getSingleton().createManual(mMeshName);
332         mMesh->sharedVertexData = OGRE_NEW VertexData();
333         // Copy all vertex parameters
334         mMesh->sharedVertexData->vertexStart = 0;
335         // Vertex count will be set on build() because it depends on current level
336         // NB clone the declaration because Mesh's VertexData will destroy it
337         mMesh->sharedVertexData->vertexDeclaration = mDeclaration->clone();
338         // Create buffer (only a single buffer)
339         // Allocate enough buffer memory for maximum subdivision, not current subdivision
340         HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().
341             createVertexBuffer(
342                 mDeclaration->getVertexSize(0),
343                 mMaxMeshHeight * mMaxMeshWidth, // maximum size
344                 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // dynamic for changing level
345 
346         // Set binding
347         mMesh->sharedVertexData->vertexBufferBinding->setBinding(0, vbuf);
348 
349         SubMesh* sm = mMesh->createSubMesh();
350         // Allocate enough index data for max subdivision
351         sm->indexData->indexStart = 0;
352         // Index count will be set on build()
353         unsigned short iterations = (mVSide == VS_BOTH ? 2 : 1);
354         sm->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
355             HardwareIndexBuffer::IT_16BIT,
356             (mMaxMeshWidth-1) * (mMaxMeshHeight-1) * 2 * iterations * 3,
357             HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
358 
359         mMesh->load();
360 
361         // Derive bounds from control points, cannot stray outside that
362         Vector3 min, max;
363         Real maxSquaredRadius;
364         bool first = true;
365         vector<Vector3>::type::iterator i, iend;
366         iend = mVecCtlPoints.end();
367         for (i = mVecCtlPoints.begin(); i != iend; ++i)
368         {
369             if (first)
370             {
371                 min = max = *i;
372                 maxSquaredRadius = i->squaredLength();
373             }
374             else
375             {
376                 min.makeFloor(*i);
377                 max.makeCeil(*i);
378                 maxSquaredRadius = std::max(maxSquaredRadius, i->squaredLength());
379             }
380 
381         }
382         mMesh->_setBounds(AxisAlignedBox(min, max));
383         mMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius));
384 
385 
386 
387     }
388     */
389     //-----------------------------------------------------------------------
distributeControlPoints(void * lockedBuffer)390     void PatchSurface::distributeControlPoints(void* lockedBuffer)
391     {
392         // Insert original control points into expanded mesh
393         size_t uStep = 1 << mULevel;
394         size_t vStep = 1 << mVLevel;
395 
396         void* pSrc = mControlPointBuffer;
397         size_t vertexSize = mDeclaration->getVertexSize(0);
398         float *pSrcReal, *pDestReal;
399         RGBA *pSrcRGBA, *pDestRGBA;
400         const VertexElement* elemPos = mDeclaration->findElementBySemantic(VES_POSITION);
401         const VertexElement* elemNorm = mDeclaration->findElementBySemantic(VES_NORMAL);
402         const VertexElement* elemTex0 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 0);
403         const VertexElement* elemTex1 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 1);
404         const VertexElement* elemDiffuse = mDeclaration->findElementBySemantic(VES_DIFFUSE);
405         for (size_t v = 0; v < mMeshHeight; v += vStep)
406         {
407             // set dest by v from base
408             void* pDest = static_cast<void*>(
409                 static_cast<unsigned char*>(lockedBuffer) + (vertexSize * mMeshWidth * v));
410             for (size_t u = 0; u < mMeshWidth; u += uStep)
411             {
412 
413                 // Copy Position
414                 elemPos->baseVertexPointerToElement(pSrc, &pSrcReal);
415                 elemPos->baseVertexPointerToElement(pDest, &pDestReal);
416                 *pDestReal++ = *pSrcReal++;
417                 *pDestReal++ = *pSrcReal++;
418                 *pDestReal++ = *pSrcReal++;
419 
420                 // Copy Normals
421                 if (elemNorm)
422                 {
423                     elemNorm->baseVertexPointerToElement(pSrc, &pSrcReal);
424                     elemNorm->baseVertexPointerToElement(pDest, &pDestReal);
425                     *pDestReal++ = *pSrcReal++;
426                     *pDestReal++ = *pSrcReal++;
427                     *pDestReal++ = *pSrcReal++;
428                 }
429 
430                 // Copy Diffuse
431                 if (elemDiffuse)
432                 {
433                     elemDiffuse->baseVertexPointerToElement(pSrc, &pSrcRGBA);
434                     elemDiffuse->baseVertexPointerToElement(pDest, &pDestRGBA);
435                     *pDestRGBA++ = *pSrcRGBA++;
436                 }
437 
438                 // Copy texture coords
439                 if (elemTex0)
440                 {
441                     elemTex0->baseVertexPointerToElement(pSrc, &pSrcReal);
442                     elemTex0->baseVertexPointerToElement(pDest, &pDestReal);
443                     for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex0->getType()); ++dim)
444                         *pDestReal++ = *pSrcReal++;
445                 }
446                 if (elemTex1)
447                 {
448                     elemTex1->baseVertexPointerToElement(pSrc, &pSrcReal);
449                     elemTex1->baseVertexPointerToElement(pDest, &pDestReal);
450                     for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex1->getType()); ++dim)
451                         *pDestReal++ = *pSrcReal++;
452                 }
453 
454                 // Increment source by one vertex
455                 pSrc = static_cast<void*>(
456                     static_cast<unsigned char*>(pSrc) + vertexSize);
457                 // Increment dest by 1 vertex * uStep
458                 pDest = static_cast<void*>(
459                     static_cast<unsigned char*>(pDest) + (vertexSize * uStep));
460             } // u
461         } // v
462 
463 
464     }
465     //-----------------------------------------------------------------------
subdivideCurve(void * lockedBuffer,size_t startIdx,size_t stepSize,size_t numSteps,size_t iterations)466     void PatchSurface::subdivideCurve(void* lockedBuffer, size_t startIdx, size_t stepSize, size_t numSteps, size_t iterations)
467     {
468         // Subdivides a curve within a sparsely populated buffer (gaps are already there to be interpolated into)
469         size_t maxIdx;
470 
471         maxIdx = startIdx + (numSteps * stepSize);
472         size_t step = stepSize;
473 
474         while(iterations--)
475         {
476             size_t leftIdx, rightIdx, destIdx, halfStep;
477             halfStep = step / 2;
478             leftIdx = startIdx;
479             destIdx = leftIdx + halfStep;
480             rightIdx = leftIdx + step;
481             bool firstSegment = true;
482             while (leftIdx < maxIdx)
483             {
484                 // Interpolate
485                 interpolateVertexData(lockedBuffer, leftIdx, rightIdx, destIdx);
486 
487                 // If 2nd or more segment, interpolate current left between current and last mid points
488                 if (!firstSegment)
489                 {
490                     interpolateVertexData(lockedBuffer, leftIdx - halfStep, leftIdx + halfStep, leftIdx);
491                 }
492                 // Next segment
493                 leftIdx = rightIdx;
494                 destIdx = leftIdx + halfStep;
495                 rightIdx = leftIdx + step;
496                 firstSegment = false;
497             }
498 
499             step = halfStep;
500         }
501     }
502     //-----------------------------------------------------------------------
makeTriangles(void)503     void PatchSurface::makeTriangles(void)
504     {
505         // Our vertex buffer is subdivided to the highest level, we need to generate tris
506         // which step over the vertices we don't need for this level of detail.
507 
508         // Calculate steps
509         int vStep = 1 << (mMaxVLevel - mVLevel);
510         int uStep = 1 << (mMaxULevel - mULevel);
511         size_t currWidth = (LEVEL_WIDTH(mULevel)-1) * ((mCtlWidth-1)/2) + 1;
512         size_t currHeight = (LEVEL_WIDTH(mVLevel)-1) * ((mCtlHeight-1)/2) + 1;
513 
514         bool use32bitindexes = (mIndexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
515 
516         // The mesh is built, just make a list of indexes to spit out the triangles
517         int vInc;
518 
519         size_t uCount, v, iterations;
520 
521         if (mVSide == VS_BOTH)
522         {
523             iterations = 2;
524             vInc = vStep;
525             v = 0; // Start with front
526         }
527         else
528         {
529             iterations = 1;
530             if (mVSide == VS_FRONT)
531             {
532                 vInc = vStep;
533                 v = 0;
534             }
535             else
536             {
537                 vInc = -vStep;
538                 v = mMeshHeight - 1;
539             }
540         }
541 
542         // Calc num indexes
543         mCurrIndexCount = (currWidth - 1) * (currHeight - 1) * 6 * iterations;
544 
545         size_t v1, v2, v3;
546         // Lock just the section of the buffer we need
547         unsigned short* p16 = 0;
548         unsigned int* p32 = 0;
549         if (use32bitindexes)
550         {
551             p32 = static_cast<unsigned int*>(
552                 mIndexBuffer->lock(
553                     mIndexOffset * sizeof(unsigned int),
554                     mRequiredIndexCount * sizeof(unsigned int),
555                     HardwareBuffer::HBL_NO_OVERWRITE));
556         }
557         else
558         {
559             p16 = static_cast<unsigned short*>(
560                 mIndexBuffer->lock(
561                     mIndexOffset * sizeof(unsigned short),
562                     mRequiredIndexCount * sizeof(unsigned short),
563                     HardwareBuffer::HBL_NO_OVERWRITE));
564         }
565 
566         while (iterations--)
567         {
568             // Make tris in a zigzag pattern (compatible with strips)
569             size_t u = 0;
570             int uInc = uStep; // Start with moving +u
571 
572             size_t vCount = currHeight - 1;
573             while (vCount--)
574             {
575                 uCount = currWidth - 1;
576                 while (uCount--)
577                 {
578                     // First Tri in cell
579                     // -----------------
580                     v1 = ((v + vInc) * mMeshWidth) + u;
581                     v2 = (v * mMeshWidth) + u;
582                     v3 = ((v + vInc) * mMeshWidth) + (u + uInc);
583                     // Output indexes
584                     if (use32bitindexes)
585                     {
586                         *p32++ = static_cast<unsigned int>(v1);
587                         *p32++ = static_cast<unsigned int>(v2);
588                         *p32++ = static_cast<unsigned int>(v3);
589                     }
590                     else
591                     {
592                         *p16++ = static_cast<unsigned short>(v1);
593                         *p16++ = static_cast<unsigned short>(v2);
594                         *p16++ = static_cast<unsigned short>(v3);
595                     }
596                     // Second Tri in cell
597                     // ------------------
598                     v1 = ((v + vInc) * mMeshWidth) + (u + uInc);
599                     v2 = (v * mMeshWidth) + u;
600                     v3 = (v * mMeshWidth) + (u + uInc);
601                     // Output indexes
602                     if (use32bitindexes)
603                     {
604                         *p32++ = static_cast<unsigned int>(v1);
605                         *p32++ = static_cast<unsigned int>(v2);
606                         *p32++ = static_cast<unsigned int>(v3);
607                     }
608                     else
609                     {
610                         *p16++ = static_cast<unsigned short>(v1);
611                         *p16++ = static_cast<unsigned short>(v2);
612                         *p16++ = static_cast<unsigned short>(v3);
613                     }
614 
615                     // Next column
616                     u += uInc;
617                 }
618                 // Next row
619                 v += vInc;
620                 u = 0;
621 
622 
623             }
624 
625             // Reverse vInc for double sided
626             v = mMeshHeight - 1;
627             vInc = -vInc;
628 
629         }
630 
631         mIndexBuffer->unlock();
632 
633 
634     }
635     //-----------------------------------------------------------------------
interpolateVertexData(void * lockedBuffer,size_t leftIdx,size_t rightIdx,size_t destIdx)636     void PatchSurface::interpolateVertexData(void* lockedBuffer, size_t leftIdx, size_t rightIdx, size_t destIdx)
637     {
638         size_t vertexSize = mDeclaration->getVertexSize(0);
639         const VertexElement* elemPos = mDeclaration->findElementBySemantic(VES_POSITION);
640         const VertexElement* elemNorm = mDeclaration->findElementBySemantic(VES_NORMAL);
641         const VertexElement* elemDiffuse = mDeclaration->findElementBySemantic(VES_DIFFUSE);
642         const VertexElement* elemTex0 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 0);
643         const VertexElement* elemTex1 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 1);
644 
645         float *pDestReal, *pLeftReal, *pRightReal;
646         unsigned char *pDestChar, *pLeftChar, *pRightChar;
647         unsigned char *pDest, *pLeft, *pRight;
648 
649         // Set up pointers & interpolate
650         pDest = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * destIdx);
651         pLeft = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * leftIdx);
652         pRight = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * rightIdx);
653 
654         // Position
655         elemPos->baseVertexPointerToElement(pDest, &pDestReal);
656         elemPos->baseVertexPointerToElement(pLeft, &pLeftReal);
657         elemPos->baseVertexPointerToElement(pRight, &pRightReal);
658 
659         *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5f;
660         *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5f;
661         *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5f;
662 
663         if (elemNorm)
664         {
665             elemNorm->baseVertexPointerToElement(pDest, &pDestReal);
666             elemNorm->baseVertexPointerToElement(pLeft, &pLeftReal);
667             elemNorm->baseVertexPointerToElement(pRight, &pRightReal);
668             Vector3 norm;
669             norm.x = (*pLeftReal++ + *pRightReal++) * 0.5f;
670             norm.y = (*pLeftReal++ + *pRightReal++) * 0.5f;
671             norm.z = (*pLeftReal++ + *pRightReal++) * 0.5f;
672             norm.normalise();
673 
674             *pDestReal++ = norm.x;
675             *pDestReal++ = norm.y;
676             *pDestReal++ = norm.z;
677         }
678         if (elemDiffuse)
679         {
680             // Blend each byte individually
681             elemDiffuse->baseVertexPointerToElement(pDest, &pDestChar);
682             elemDiffuse->baseVertexPointerToElement(pLeft, &pLeftChar);
683             elemDiffuse->baseVertexPointerToElement(pRight, &pRightChar);
684             // 4 bytes to RGBA
685             *pDestChar++ = static_cast<unsigned char>(((*pLeftChar++) + (*pRightChar++)) * 0.5);
686             *pDestChar++ = static_cast<unsigned char>(((*pLeftChar++) + (*pRightChar++)) * 0.5);
687             *pDestChar++ = static_cast<unsigned char>(((*pLeftChar++) + (*pRightChar++)) * 0.5);
688             *pDestChar++ = static_cast<unsigned char>(((*pLeftChar++) + (*pRightChar++)) * 0.5);
689         }
690         if (elemTex0)
691         {
692             elemTex0->baseVertexPointerToElement(pDest, &pDestReal);
693             elemTex0->baseVertexPointerToElement(pLeft, &pLeftReal);
694             elemTex0->baseVertexPointerToElement(pRight, &pRightReal);
695 
696             for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex0->getType()); ++dim)
697                 *pDestReal++ = ((*pLeftReal++) + (*pRightReal++)) * 0.5f;
698         }
699         if (elemTex1)
700         {
701             elemTex1->baseVertexPointerToElement(pDest, &pDestReal);
702             elemTex1->baseVertexPointerToElement(pLeft, &pLeftReal);
703             elemTex1->baseVertexPointerToElement(pRight, &pRightReal);
704 
705             for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex1->getType()); ++dim)
706                 *pDestReal++ = ((*pLeftReal++) + (*pRightReal++)) * 0.5f;
707         }
708     }
709 
710 }
711 
712