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 mSubdivisionFactor = factor; 00268 mULevel = factor * mMaxULevel; 00269 mVLevel = factor * mMaxVLevel; 00270 00271 makeTriangles(); 00272 00273 00274 } 00275 //----------------------------------------------------------------------- 00276 Real PatchSurface::getSubdivisionFactor(void) const 00277 { 00278 return mSubdivisionFactor; 00279 } 00280 //----------------------------------------------------------------------- 00281 size_t PatchSurface::getCurrentIndexCount(void) const 00282 { 00283 return mCurrIndexCount; 00284 } 00285 //----------------------------------------------------------------------- 00286 size_t PatchSurface::findLevel(Vector3& a, Vector3& b, Vector3& c) 00287 { 00288 // Derived from work by Bart Sekura in rogl 00289 // Apart from I think I fixed a bug - see below 00290 // I also commented the code, the only thing wrong with rogl is almost no comments!! 00291 00292 const size_t max_levels = 5; 00293 const float subdiv = 10; 00294 size_t level; 00295 00296 float test=subdiv*subdiv; 00297 Vector3 s,t,d; 00298 for(level=0; level<max_levels-1; level++) 00299 { 00300 // Subdivide the 2 lines 00301 s = a.midPoint(b); 00302 t = b.midPoint(c); 00303 // Find the midpoint between the 2 midpoints 00304 c = s.midPoint(t); 00305 // Get the vector between this subdivided midpoint and the middle point of the original line 00306 d = c - b; 00307 // Find the squared length, and break when small enough 00308 if(d.dotProduct(d) < test) { 00309 break; 00310 } 00311 b=a; 00312 } 00313 00314 return level; 00315 00316 } 00317 00318 /* 00319 //----------------------------------------------------------------------- 00320 void PatchSurface::allocateMemory(void) 00321 { 00322 if (mMemoryAllocated) 00323 deallocateMemory(); 00324 00325 // Allocate to the size of max level 00326 00327 // Create mesh 00328 mMesh = MeshManager::getSingleton().createManual(mMeshName); 00329 mMesh->sharedVertexData = new VertexData(); 00330 // Copy all vertex parameters 00331 mMesh->sharedVertexData->vertexStart = 0; 00332 // Vertex count will be set on build() because it depends on current level 00333 // NB clone the declaration because Mesh's VertexData will destroy it 00334 mMesh->sharedVertexData->vertexDeclaration = mDeclaration->clone(); 00335 // Create buffer (only a single buffer) 00336 // Allocate enough buffer memory for maximum subdivision, not current subdivision 00337 HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton(). 00338 createVertexBuffer( 00339 mDeclaration->getVertexSize(0), 00340 mMaxMeshHeight * mMaxMeshWidth, // maximum size 00341 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // dynamic for changing level 00342 00343 // Set binding 00344 mMesh->sharedVertexData->vertexBufferBinding->setBinding(0, vbuf); 00345 00346 SubMesh* sm = mMesh->createSubMesh(); 00347 // Allocate enough index data for max subdivision 00348 sm->indexData->indexStart = 0; 00349 // Index count will be set on build() 00350 unsigned short iterations = (mVSide == VS_BOTH ? 2 : 1); 00351 sm->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer( 00352 HardwareIndexBuffer::IT_16BIT, 00353 (mMaxMeshWidth-1) * (mMaxMeshHeight-1) * 2 * iterations * 3, 00354 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); 00355 00356 mMesh->load(); 00357 00358 // Derive bounds from control points, cannot stray outside that 00359 Vector3 min, max; 00360 Real maxSquaredRadius; 00361 bool first = true; 00362 std::vector<Vector3>::iterator i, iend; 00363 iend = mVecCtlPoints.end(); 00364 for (i = mVecCtlPoints.begin(); i != iend; ++i) 00365 { 00366 if (first) 00367 { 00368 min = max = *i; 00369 maxSquaredRadius = i->squaredLength(); 00370 } 00371 else 00372 { 00373 min.makeFloor(*i); 00374 max.makeCeil(*i); 00375 maxSquaredRadius = std::max(maxSquaredRadius, i->squaredLength()); 00376 } 00377 00378 } 00379 mMesh->_setBounds(AxisAlignedBox(min, max)); 00380 mMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius)); 00381 00382 00383 00384 } 00385 */ 00386 //----------------------------------------------------------------------- 00387 void PatchSurface::distributeControlPoints(void* lockedBuffer) 00388 { 00389 // Insert original control points into expanded mesh 00390 size_t uStep = 1 << mULevel; 00391 size_t vStep = 1 << mVLevel; 00392 00393 00394 void* pSrc = mControlPointBuffer; 00395 size_t vertexSize = mDeclaration->getVertexSize(0); 00396 Real *pSrcReal, *pDestReal; 00397 RGBA *pSrcRGBA, *pDestRGBA; 00398 void* pDest; 00399 const VertexElement* elemPos = mDeclaration->findElementBySemantic(VES_POSITION); 00400 const VertexElement* elemNorm = mDeclaration->findElementBySemantic(VES_NORMAL); 00401 const VertexElement* elemTex0 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 0); 00402 const VertexElement* elemTex1 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 1); 00403 const VertexElement* elemDiffuse = mDeclaration->findElementBySemantic(VES_DIFFUSE); 00404 for (size_t v = 0; v < mMeshHeight; v += vStep) 00405 { 00406 // set dest by v from base 00407 pDest = static_cast<void*>( 00408 static_cast<unsigned char*>(lockedBuffer) + (vertexSize * mMeshWidth * v)); 00409 for (size_t u = 0; u < mMeshWidth; u += uStep) 00410 { 00411 00412 // Copy Position 00413 elemPos->baseVertexPointerToElement(pSrc, &pSrcReal); 00414 elemPos->baseVertexPointerToElement(pDest, &pDestReal); 00415 *pDestReal++ = *pSrcReal++; 00416 *pDestReal++ = *pSrcReal++; 00417 *pDestReal++ = *pSrcReal++; 00418 00419 // Copy Normals 00420 if (elemNorm) 00421 { 00422 elemNorm->baseVertexPointerToElement(pSrc, &pSrcReal); 00423 elemNorm->baseVertexPointerToElement(pDest, &pDestReal); 00424 *pDestReal++ = *pSrcReal++; 00425 *pDestReal++ = *pSrcReal++; 00426 *pDestReal++ = *pSrcReal++; 00427 } 00428 00429 // Copy Diffuse 00430 if (elemDiffuse) 00431 { 00432 elemDiffuse->baseVertexPointerToElement(pSrc, &pSrcRGBA); 00433 elemDiffuse->baseVertexPointerToElement(pDest, &pDestRGBA); 00434 *pDestRGBA++ = *pSrcRGBA++; 00435 } 00436 00437 // Copy texture coords 00438 if (elemTex0) 00439 { 00440 elemTex0->baseVertexPointerToElement(pSrc, &pSrcReal); 00441 elemTex0->baseVertexPointerToElement(pDest, &pDestReal); 00442 for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex0->getType()); ++dim) 00443 *pDestReal++ = *pSrcReal++; 00444 } 00445 if (elemTex1) 00446 { 00447 elemTex1->baseVertexPointerToElement(pSrc, &pSrcReal); 00448 elemTex1->baseVertexPointerToElement(pDest, &pDestReal); 00449 for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex1->getType()); ++dim) 00450 *pDestReal++ = *pSrcReal++; 00451 } 00452 00453 // Increment source by one vertex 00454 pSrc = static_cast<void*>( 00455 static_cast<unsigned char*>(pSrc) + vertexSize); 00456 // Increment dest by 1 vertex * uStep 00457 pDest = static_cast<void*>( 00458 static_cast<unsigned char*>(pDest) + (vertexSize * uStep)); 00459 } // u 00460 } // v 00461 00462 00463 } 00464 //----------------------------------------------------------------------- 00465 void PatchSurface::subdivideCurve(void* lockedBuffer, size_t startIdx, size_t stepSize, size_t numSteps, size_t iterations) 00466 { 00467 // Subdivides a curve within a sparsely populated buffer (gaps are already there to be interpolated into) 00468 size_t leftIdx, rightIdx, destIdx, halfStep, maxIdx; 00469 bool firstSegment; 00470 00471 maxIdx = startIdx + (numSteps * stepSize); 00472 size_t step = stepSize; 00473 00474 while(iterations--) 00475 { 00476 halfStep = step / 2; 00477 leftIdx = startIdx; 00478 destIdx = leftIdx + halfStep; 00479 rightIdx = leftIdx + step; 00480 firstSegment = true; 00481 while (leftIdx < maxIdx) 00482 { 00483 // Interpolate 00484 interpolateVertexData(lockedBuffer, leftIdx, rightIdx, destIdx); 00485 00486 // If 2nd or more segment, interpolate current left between current and last mid points 00487 if (!firstSegment) 00488 { 00489 interpolateVertexData(lockedBuffer, leftIdx - halfStep, leftIdx + halfStep, leftIdx); 00490 } 00491 // Next segment 00492 leftIdx = rightIdx; 00493 destIdx = leftIdx + halfStep; 00494 rightIdx = leftIdx + step; 00495 firstSegment = false; 00496 } 00497 00498 step = halfStep; 00499 } 00500 } 00501 //----------------------------------------------------------------------- 00502 void PatchSurface::makeTriangles(void) 00503 { 00504 // Our vertex buffer is subdivided to the highest level, we need to generate tris 00505 // which step over the vertices we don't need for this level of detail. 00506 00507 // Calculate steps 00508 int vStep = 1 << (mMaxVLevel - mVLevel); 00509 int uStep = 1 << (mMaxULevel - mULevel); 00510 size_t currWidth = (LEVEL_WIDTH(mULevel)-1) * ((mCtlWidth-1)/2) + 1; 00511 size_t currHeight = (LEVEL_WIDTH(mVLevel)-1) * ((mCtlHeight-1)/2) + 1; 00512 00513 bool use32bitindexes = (mIndexBuffer->getType() == HardwareIndexBuffer::IT_32BIT); 00514 00515 // The mesh is built, just make a list of indexes to spit out the triangles 00516 int vInc, uInc; 00517 00518 size_t vCount, uCount, v, u, iterations; 00519 00520 if (mVSide == VS_BOTH) 00521 { 00522 iterations = 2; 00523 vInc = vStep; 00524 v = 0; // Start with front 00525 } 00526 else 00527 { 00528 iterations = 1; 00529 if (mVSide == VS_FRONT) 00530 { 00531 vInc = vStep; 00532 v = 0; 00533 } 00534 else 00535 { 00536 vInc = -vStep; 00537 v = mMeshHeight - 1; 00538 } 00539 } 00540 00541 // Calc num indexes 00542 mCurrIndexCount = (currWidth - 1) * (currHeight - 1) * 6 * iterations; 00543 00544 size_t v1, v2, v3; 00545 // Lock just the section of the buffer we need 00546 unsigned short* p16; 00547 unsigned int* p32; 00548 if (use32bitindexes) 00549 { 00550 p32 = static_cast<unsigned int*>( 00551 mIndexBuffer->lock( 00552 mIndexOffset * sizeof(unsigned int), 00553 mRequiredIndexCount * sizeof(unsigned int), 00554 HardwareBuffer::HBL_NO_OVERWRITE)); 00555 } 00556 else 00557 { 00558 p16 = static_cast<unsigned short*>( 00559 mIndexBuffer->lock( 00560 mIndexOffset * sizeof(unsigned short), 00561 mRequiredIndexCount * sizeof(unsigned short), 00562 HardwareBuffer::HBL_NO_OVERWRITE)); 00563 } 00564 00565 while (iterations--) 00566 { 00567 // Make tris in a zigzag pattern (compatible with strips) 00568 u = 0; 00569 uInc = uStep; // Start with moving +u 00570 00571 vCount = currHeight - 1; 00572 while (vCount--) 00573 { 00574 uCount = currWidth - 1; 00575 while (uCount--) 00576 { 00577 // First Tri in cell 00578 // ----------------- 00579 v1 = ((v + vInc) * mMeshWidth) + u; 00580 v2 = (v * mMeshWidth) + u; 00581 v3 = ((v + vInc) * mMeshWidth) + (u + uInc); 00582 // Output indexes 00583 if (use32bitindexes) 00584 { 00585 *p32++ = static_cast<unsigned int>(v1); 00586 *p32++ = static_cast<unsigned int>(v2); 00587 *p32++ = static_cast<unsigned int>(v3); 00588 } 00589 else 00590 { 00591 *p16++ = static_cast<unsigned short>(v1); 00592 *p16++ = static_cast<unsigned short>(v2); 00593 *p16++ = static_cast<unsigned short>(v3); 00594 } 00595 // Second Tri in cell 00596 // ------------------ 00597 v1 = ((v + vInc) * mMeshWidth) + (u + uInc); 00598 v2 = (v * mMeshWidth) + u; 00599 v3 = (v * mMeshWidth) + (u + uInc); 00600 // Output indexes 00601 if (use32bitindexes) 00602 { 00603 *p32++ = static_cast<unsigned int>(v1); 00604 *p32++ = static_cast<unsigned int>(v2); 00605 *p32++ = static_cast<unsigned int>(v3); 00606 } 00607 else 00608 { 00609 *p16++ = static_cast<unsigned short>(v1); 00610 *p16++ = static_cast<unsigned short>(v2); 00611 *p16++ = static_cast<unsigned short>(v3); 00612 } 00613 00614 // Next column 00615 u += uInc; 00616 } 00617 // Next row 00618 v += vInc; 00619 u = 0; 00620 00621 00622 } 00623 00624 // Reverse vInc for double sided 00625 v = mMeshHeight - 1; 00626 vInc = -vInc; 00627 00628 } 00629 00630 mIndexBuffer->unlock(); 00631 00632 00633 } 00634 //----------------------------------------------------------------------- 00635 void PatchSurface::interpolateVertexData(void* lockedBuffer, size_t leftIdx, size_t rightIdx, size_t destIdx) 00636 { 00637 size_t vertexSize = mDeclaration->getVertexSize(0); 00638 const VertexElement* elemPos = mDeclaration->findElementBySemantic(VES_POSITION); 00639 const VertexElement* elemNorm = mDeclaration->findElementBySemantic(VES_NORMAL); 00640 const VertexElement* elemDiffuse = mDeclaration->findElementBySemantic(VES_DIFFUSE); 00641 const VertexElement* elemTex0 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 0); 00642 const VertexElement* elemTex1 = mDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, 1); 00643 00644 Real *pDestReal, *pLeftReal, *pRightReal; 00645 unsigned char *pDestChar, *pLeftChar, *pRightChar; 00646 unsigned char *pDest, *pLeft, *pRight; 00647 00648 // Set up pointers & interpolate 00649 pDest = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * destIdx); 00650 pLeft = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * leftIdx); 00651 pRight = static_cast<unsigned char*>(lockedBuffer) + (vertexSize * rightIdx); 00652 00653 // Position 00654 elemPos->baseVertexPointerToElement(pDest, &pDestReal); 00655 elemPos->baseVertexPointerToElement(pLeft, &pLeftReal); 00656 elemPos->baseVertexPointerToElement(pRight, &pRightReal); 00657 00658 *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5; 00659 *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5; 00660 *pDestReal++ = (*pLeftReal++ + *pRightReal++) * 0.5; 00661 00662 if (elemNorm) 00663 { 00664 elemNorm->baseVertexPointerToElement(pDest, &pDestReal); 00665 elemNorm->baseVertexPointerToElement(pLeft, &pLeftReal); 00666 elemNorm->baseVertexPointerToElement(pRight, &pRightReal); 00667 Vector3 norm; 00668 norm.x = (*pLeftReal++ + *pRightReal++) * 0.5; 00669 norm.y = (*pLeftReal++ + *pRightReal++) * 0.5; 00670 norm.z = (*pLeftReal++ + *pRightReal++) * 0.5; 00671 norm.normalise(); 00672 00673 *pDestReal++ = norm.x; 00674 *pDestReal++ = norm.y; 00675 *pDestReal++ = norm.z; 00676 } 00677 if (elemDiffuse) 00678 { 00679 // Blend each byte individually 00680 elemDiffuse->baseVertexPointerToElement(pDest, &pDestChar); 00681 elemDiffuse->baseVertexPointerToElement(pLeft, &pLeftChar); 00682 elemDiffuse->baseVertexPointerToElement(pRight, &pRightChar); 00683 // 4 bytes to RGBA 00684 *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5; 00685 *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5; 00686 *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5; 00687 *pDestChar++ = ((*pLeftChar++) + (*pRightChar++)) * 0.5; 00688 } 00689 if (elemTex0) 00690 { 00691 elemTex0->baseVertexPointerToElement(pDest, &pDestReal); 00692 elemTex0->baseVertexPointerToElement(pLeft, &pLeftReal); 00693 elemTex0->baseVertexPointerToElement(pRight, &pRightReal); 00694 00695 for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex0->getType()); ++dim) 00696 *pDestReal++ = ((*pLeftReal++) + (*pRightReal++)) * 0.5; 00697 } 00698 if (elemTex1) 00699 { 00700 elemTex1->baseVertexPointerToElement(pDest, &pDestReal); 00701 elemTex1->baseVertexPointerToElement(pLeft, &pLeftReal); 00702 elemTex1->baseVertexPointerToElement(pRight, &pRightReal); 00703 00704 for (size_t dim = 0; dim < VertexElement::getTypeCount(elemTex1->getType()); ++dim) 00705 *pDestReal++ = ((*pLeftReal++) + (*pRightReal++)) * 0.5; 00706 } 00707 } 00708 00709 } 00710
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:33 2004