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