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-2003 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 #include "OgreVertexIndexData.h" 00027 #include "OgreHardwareBufferManager.h" 00028 #include "OgreHardwareVertexBuffer.h" 00029 #include "OgreHardwareIndexBuffer.h" 00030 #include "OgreVector3.h" 00031 #include "OgreAxisAlignedBox.h" 00032 #include "OgreRoot.h" 00033 #include "OgreRenderSystem.h" 00034 #include "OgreException.h" 00035 00036 namespace Ogre { 00037 00038 //----------------------------------------------------------------------- 00039 VertexData::VertexData() 00040 { 00041 vertexBufferBinding = HardwareBufferManager::getSingleton(). 00042 createVertexBufferBinding(); 00043 vertexDeclaration = HardwareBufferManager::getSingleton(). 00044 createVertexDeclaration(); 00045 vertexCount = 0; 00046 vertexStart = 0; 00047 00048 } 00049 //----------------------------------------------------------------------- 00050 VertexData::~VertexData() 00051 { 00052 HardwareBufferManager::getSingleton(). 00053 destroyVertexBufferBinding(vertexBufferBinding); 00054 HardwareBufferManager::getSingleton().destroyVertexDeclaration(vertexDeclaration); 00055 00056 } 00057 //----------------------------------------------------------------------- 00058 VertexData* VertexData::clone(bool copyData) const 00059 { 00060 VertexData* dest = new VertexData(); 00061 00062 // Copy vertex buffers in turn 00063 const VertexBufferBinding::VertexBufferBindingMap bindings = 00064 this->vertexBufferBinding->getBindings(); 00065 VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbend; 00066 vbend = bindings.end(); 00067 for (vbi = bindings.begin(); vbi != vbend; ++vbi) 00068 { 00069 HardwareVertexBufferSharedPtr srcbuf = vbi->second; 00070 HardwareVertexBufferSharedPtr dstBuf; 00071 if (copyData) 00072 { 00073 // create new buffer with the same settings 00074 dstBuf = 00075 HardwareBufferManager::getSingleton().createVertexBuffer( 00076 srcbuf->getVertexSize(), srcbuf->getNumVertices(), srcbuf->getUsage(), 00077 srcbuf->hasShadowBuffer()); 00078 00079 // copy data 00080 dstBuf->copyData(*srcbuf, 0, 0, srcbuf->getSizeInBytes(), true); 00081 } 00082 else 00083 { 00084 // don't copy, point at existing buffer 00085 dstBuf = srcbuf; 00086 } 00087 00088 // Copy binding 00089 dest->vertexBufferBinding->setBinding(vbi->first, dstBuf); 00090 } 00091 00092 // Basic vertex info 00093 dest->vertexStart = this->vertexStart; 00094 dest->vertexCount = this->vertexCount; 00095 // Copy elements 00096 const VertexDeclaration::VertexElementList elems = 00097 this->vertexDeclaration->getElements(); 00098 VertexDeclaration::VertexElementList::const_iterator ei, eiend; 00099 eiend = elems.end(); 00100 for (ei = elems.begin(); ei != eiend; ++ei) 00101 { 00102 dest->vertexDeclaration->addElement( 00103 ei->getSource(), 00104 ei->getOffset(), 00105 ei->getType(), 00106 ei->getSemantic(), 00107 ei->getIndex() ); 00108 } 00109 00110 00111 return dest; 00112 } 00113 //----------------------------------------------------------------------- 00114 void VertexData::prepareForShadowVolume(void) 00115 { 00116 /* NOTE 00117 I would dearly, dearly love to just use a 4D position buffer in order to 00118 store the extra 'w' value I need to differentiate between extruded and 00119 non-extruded sections of the buffer, so that vertex programs could use that. 00120 Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not 00121 support 4d position vertices in the fixed-function pipeline. If you use them, 00122 you just see nothing. Since we can't know whether the application is going to use 00123 fixed function or vertex programs, we have to stick to 3d position vertices and 00124 store the 'w' in a separate 1D texture coordinate buffer, which is only used 00125 when rendering the shadow. 00126 */ 00127 00128 // Upfront, lets check whether we have vertex program capability 00129 RenderSystem* rend = Root::getSingleton().getRenderSystem(); 00130 bool useVertexPrograms = false; 00131 if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM)) 00132 { 00133 useVertexPrograms = true; 00134 } 00135 00136 00137 // Look for a position element 00138 const VertexElement* posElem = vertexDeclaration->findElementBySemantic(VES_POSITION); 00139 if (posElem) 00140 { 00141 size_t v; 00142 unsigned posOldSource = posElem->getSource(); 00143 00144 HardwareVertexBufferSharedPtr vbuf = vertexBufferBinding->getBuffer(posOldSource); 00145 bool wasSharedBuffer = false; 00146 // Are there other elements in the buffer except for the position? 00147 if (vbuf->getVertexSize() > posElem->getSize()) 00148 { 00149 // We need to create another buffer to contain the remaining elements 00150 // Most drivers don't like gaps in the declaration, and in any case it's waste 00151 wasSharedBuffer = true; 00152 } 00153 HardwareVertexBufferSharedPtr newPosBuffer, newRemainderBuffer; 00154 if (wasSharedBuffer) 00155 { 00156 newRemainderBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 00157 vbuf->getVertexSize() - posElem->getSize(), vbuf->getNumVertices(), vbuf->getUsage(), 00158 vbuf->hasShadowBuffer()); 00159 } 00160 // Allocate new position buffer, will be FLOAT3 and 2x the size 00161 size_t oldVertexCount = vbuf->getNumVertices(); 00162 size_t newVertexCount = oldVertexCount * 2; 00163 newPosBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 00164 VertexElement::getTypeSize(VET_FLOAT3), newVertexCount, vbuf->getUsage(), 00165 vbuf->hasShadowBuffer()); 00166 00167 // Iterate over the old buffer, copying the appropriate elements and initialising the rest 00168 Real* pSrc; 00169 unsigned char *pBaseSrc = static_cast<unsigned char*>( 00170 vbuf->lock(HardwareBuffer::HBL_READ_ONLY)); 00171 // Point first destination pointer at the start of the new position buffer, 00172 // the other one half way along 00173 Real *pDest = static_cast<Real*>(newPosBuffer->lock(HardwareBuffer::HBL_DISCARD)); 00174 Real* pDest2 = pDest + oldVertexCount * 3; 00175 00176 // Precalculate any dimensions of vertex areas outside the position 00177 size_t prePosVertexSize, postPosVertexSize, postPosVertexOffset; 00178 unsigned char *pBaseDestRem = 0; 00179 if (wasSharedBuffer) 00180 { 00181 pBaseDestRem = static_cast<unsigned char*>( 00182 newRemainderBuffer->lock(HardwareBuffer::HBL_DISCARD)); 00183 prePosVertexSize = posElem->getOffset(); 00184 postPosVertexOffset = prePosVertexSize + posElem->getSize(); 00185 postPosVertexSize = vbuf->getVertexSize() - postPosVertexOffset; 00186 // the 2 separate bits together should be the same size as the remainder buffer vertex 00187 assert (newRemainderBuffer->getVertexSize() == prePosVertexSize + postPosVertexSize); 00188 00189 // Iterate over the vertices 00190 for (v = 0; v < oldVertexCount; ++v) 00191 { 00192 // Copy position, into both buffers 00193 posElem->baseVertexPointerToElement(pBaseSrc, &pSrc); 00194 *pDest++ = *pDest2++ = *pSrc++; 00195 *pDest++ = *pDest2++ = *pSrc++; 00196 *pDest++ = *pDest2++ = *pSrc++; 00197 00198 // now deal with any other elements 00199 // Basically we just memcpy the vertex excluding the position 00200 if (prePosVertexSize > 0) 00201 memcpy(pBaseDestRem, pBaseSrc, prePosVertexSize); 00202 if (postPosVertexSize > 0) 00203 memcpy(pBaseDestRem + prePosVertexSize, 00204 pBaseSrc + postPosVertexOffset, postPosVertexSize); 00205 pBaseDestRem += newRemainderBuffer->getVertexSize(); 00206 00207 pBaseSrc += vbuf->getVertexSize(); 00208 00209 } // next vertex 00210 } 00211 else 00212 { 00213 // Unshared buffer, can block copy the whole thing 00214 memcpy(pDest, pBaseSrc, vbuf->getSizeInBytes()); 00215 memcpy(pDest2, pBaseSrc, vbuf->getSizeInBytes()); 00216 } 00217 00218 vbuf->unlock(); 00219 newPosBuffer->unlock(); 00220 if (wasSharedBuffer) 00221 newRemainderBuffer->unlock(); 00222 00223 // At this stage, he original vertex buffer is going to be destroyed 00224 // So we should force the deallocation of any temporary copies 00225 HardwareBufferManager::getSingleton()._forceReleaseBufferCopies(vbuf); 00226 00227 if (useVertexPrograms) 00228 { 00229 // Now it's time to set up the w buffer 00230 hardwareShadowVolWBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 00231 sizeof(Real), newVertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); 00232 // Fill the first half with 1.0, second half with 0.0 00233 pDest = static_cast<Real*>( 00234 hardwareShadowVolWBuffer->lock(HardwareBuffer::HBL_DISCARD)); 00235 for (v = 0; v < oldVertexCount; ++v) 00236 { 00237 *pDest++ = 1.0f; 00238 } 00239 for (v = 0; v < oldVertexCount; ++v) 00240 { 00241 *pDest++ = 0.0f; 00242 } 00243 hardwareShadowVolWBuffer->unlock(); 00244 } 00245 00246 unsigned short newPosBufferSource; 00247 if (wasSharedBuffer) 00248 { 00249 // Get the a new buffer binding index 00250 newPosBufferSource= vertexBufferBinding->getNextIndex(); 00251 // Re-bind the old index to the remainder buffer 00252 vertexBufferBinding->setBinding(posOldSource, newRemainderBuffer); 00253 } 00254 else 00255 { 00256 // We can just re-use the same source idex for the new position buffer 00257 newPosBufferSource = posOldSource; 00258 } 00259 // Bind the new position buffer 00260 vertexBufferBinding->setBinding(newPosBufferSource, newPosBuffer); 00261 00262 // Now, alter the vertex declaration to change the position source 00263 // and the offsets of elements using the same buffer 00264 VertexDeclaration::VertexElementList::const_iterator elemi = 00265 vertexDeclaration->getElements().begin(); 00266 VertexDeclaration::VertexElementList::const_iterator elemiend = 00267 vertexDeclaration->getElements().end(); 00268 unsigned short idx; 00269 for(idx = 0; elemi != elemiend; ++elemi, ++idx) 00270 { 00271 if (&(*elemi) == posElem) 00272 { 00273 // Modify position to point at new position buffer 00274 vertexDeclaration->modifyElement( 00275 idx, 00276 newPosBufferSource, // new source buffer 00277 0, // no offset now 00278 VET_FLOAT3, 00279 VES_POSITION); 00280 } 00281 else if (wasSharedBuffer && 00282 elemi->getSource() == posOldSource && 00283 elemi->getOffset() > prePosVertexSize ) 00284 { 00285 // This element came after position, remove the position's 00286 // size 00287 vertexDeclaration->modifyElement( 00288 idx, 00289 posOldSource, // same old source 00290 elemi->getOffset() - posElem->getSize(), // less offset now 00291 elemi->getType(), 00292 elemi->getSemantic(), 00293 elemi->getIndex()); 00294 00295 } 00296 00297 } 00298 00299 00300 // Note that we don't change vertexCount, because the other buffer(s) are still the same 00301 // size after all 00302 00303 00304 } 00305 } 00306 //----------------------------------------------------------------------- 00307 void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration, BufferUsageList bufferUsages) 00308 { 00309 // Firstly, close up any gaps in the buffer sources which might have arisen 00310 newDeclaration->closeGapsInSource(); 00311 00312 // Build up a list of both old and new elements in each buffer 00313 unsigned short buf = 0; 00314 std::vector<void*> oldBufferLocks; 00315 std::vector<void*> newBufferLocks; 00316 VertexBufferBinding* newBinding = 00317 HardwareBufferManager::getSingleton().createVertexBufferBinding(); 00318 // Lock all the old buffers for reading 00319 try 00320 { 00321 while (1) 00322 { 00323 oldBufferLocks.push_back( 00324 vertexBufferBinding->getBuffer(buf++)->lock( 00325 HardwareBuffer::HBL_READ_ONLY)); 00326 } 00327 } 00328 catch(Exception& e) 00329 { 00330 // Catch 'no buffer' exception and ignore 00331 } 00332 00333 // Create new buffers and lock all for writing 00334 buf = 0; 00335 while (!newDeclaration->findElementsBySource(buf).empty()) 00336 { 00337 HardwareVertexBufferSharedPtr vbuf = 00338 HardwareBufferManager::getSingleton().createVertexBuffer( 00339 newDeclaration->getVertexSize(buf), 00340 vertexCount, 00341 bufferUsages[buf]); 00342 newBinding->setBinding(buf, vbuf); 00343 00344 newBufferLocks.push_back( 00345 vbuf->lock(HardwareBuffer::HBL_DISCARD)); 00346 buf++; 00347 } 00348 00349 // Map from new to old elements 00350 typedef std::map<const VertexElement*, const VertexElement*> NewToOldElementMap; 00351 NewToOldElementMap newToOldElementMap; 00352 const VertexDeclaration::VertexElementList& newElemList = newDeclaration->getElements(); 00353 VertexDeclaration::VertexElementList::const_iterator ei, eiend; 00354 eiend = newElemList.end(); 00355 for (ei = newElemList.begin(); ei != eiend; ++ei) 00356 { 00357 // Find corresponding old element 00358 const VertexElement* oldElem = 00359 vertexDeclaration->findElementBySemantic( 00360 (*ei).getSemantic(), (*ei).getIndex()); 00361 if (!oldElem) 00362 { 00363 // Error, cannot create new elements with this method 00364 Except(Exception::ERR_ITEM_NOT_FOUND, 00365 "Element not found in old vertex declaration", 00366 "VertexData::reorganiseBuffers"); 00367 } 00368 newToOldElementMap[&(*ei)] = oldElem; 00369 } 00370 // Now iterate over the new buffers, pulling data out of the old ones 00371 // For each vertex 00372 for (size_t v = 0; v < vertexCount; ++v) 00373 { 00374 // For each (new) element 00375 for (ei = newElemList.begin(); ei != eiend; ++ei) 00376 { 00377 const VertexElement* newElem = &(*ei); 00378 NewToOldElementMap::iterator noi = newToOldElementMap.find(newElem); 00379 const VertexElement* oldElem = noi->second; 00380 unsigned short oldBufferNo = oldElem->getSource(); 00381 unsigned short newBufferNo = newElem->getSource(); 00382 void* pSrcBase = static_cast<void*>( 00383 static_cast<unsigned char*>(oldBufferLocks[oldBufferNo]) 00384 + v * vertexBufferBinding->getBuffer(oldBufferNo)->getVertexSize()); 00385 void* pDstBase = static_cast<void*>( 00386 static_cast<unsigned char*>(newBufferLocks[newBufferNo]) 00387 + v * newBinding->getBuffer(newBufferNo)->getVertexSize()); 00388 void *pSrc, *pDst; 00389 oldElem->baseVertexPointerToElement(pSrcBase, &pSrc); 00390 newElem->baseVertexPointerToElement(pDstBase, &pDst); 00391 00392 memcpy(pDst, pSrc, newElem->getSize()); 00393 00394 } 00395 } 00396 00397 // Unlock all buffers 00398 buf = 0; 00399 try 00400 { 00401 while (1) 00402 { 00403 vertexBufferBinding->getBuffer(buf++)->unlock(); 00404 } 00405 } 00406 catch(Exception& e) 00407 { 00408 // Catch 'no buffer' exception and ignore 00409 } 00410 buf = 0; 00411 try 00412 { 00413 while (1) 00414 { 00415 newBinding->getBuffer(buf++)->unlock(); 00416 } 00417 } 00418 catch(Exception& e) 00419 { 00420 // Catch 'no buffer' exception and ignore 00421 } 00422 00423 // Delete old binding & declaration 00424 HardwareBufferManager::getSingleton(). 00425 destroyVertexBufferBinding(vertexBufferBinding); 00426 HardwareBufferManager::getSingleton().destroyVertexDeclaration(vertexDeclaration); 00427 00428 // Assign new binding and declaration 00429 vertexDeclaration = newDeclaration; 00430 vertexBufferBinding = newBinding; 00431 00432 } 00433 //----------------------------------------------------------------------- 00434 void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration) 00435 { 00436 // Derive the buffer usages from looking at where the source has come 00437 // from 00438 BufferUsageList usages; 00439 for (unsigned short b = 0; b <= newDeclaration->getMaxSource(); ++b) 00440 { 00441 VertexDeclaration::VertexElementList destElems = newDeclaration->findElementsBySource(b); 00442 // Initialise with most restrictive version 00443 // (not really a usable option, but these flags will be removed) 00444 HardwareBuffer::Usage final = static_cast<HardwareBuffer::Usage>( 00445 HardwareBuffer::HBU_STATIC_WRITE_ONLY | HardwareBuffer::HBU_DISCARDABLE); 00446 VertexDeclaration::VertexElementList::iterator v; 00447 for (v = destElems.begin(); v != destElems.end(); ++v) 00448 { 00449 VertexElement& destelem = *v; 00450 // get source 00451 const VertexElement* srcelem = 00452 vertexDeclaration->findElementBySemantic( 00453 destelem.getSemantic(), destelem.getIndex()); 00454 // get buffer 00455 HardwareVertexBufferSharedPtr srcbuf = 00456 vertexBufferBinding->getBuffer(srcelem->getIndex()); 00457 // improve flexibility only 00458 if (srcbuf->getUsage() & HardwareBuffer::HBU_DYNAMIC) 00459 { 00460 // remove static 00461 final = static_cast<HardwareBuffer::Usage>( 00462 final & ~HardwareBuffer::HBU_STATIC); 00463 // add dynamic 00464 final = static_cast<HardwareBuffer::Usage>( 00465 final | HardwareBuffer::HBU_DYNAMIC); 00466 } 00467 if (!(srcbuf->getUsage() & HardwareBuffer::HBU_WRITE_ONLY)) 00468 { 00469 // remove write only 00470 final = static_cast<HardwareBuffer::Usage>( 00471 final & ~HardwareBuffer::HBU_WRITE_ONLY); 00472 } 00473 if (!(srcbuf->getUsage() & HardwareBuffer::HBU_DISCARDABLE)) 00474 { 00475 // remove discardable 00476 final = static_cast<HardwareBuffer::Usage>( 00477 final & ~HardwareBuffer::HBU_DISCARDABLE); 00478 } 00479 00480 } 00481 usages.push_back(final); 00482 } 00483 // Call specific method 00484 reorganiseBuffers(newDeclaration, usages); 00485 00486 } 00487 //----------------------------------------------------------------------- 00488 //----------------------------------------------------------------------- 00489 IndexData::IndexData() 00490 { 00491 indexCount = 0; 00492 indexStart = 0; 00493 00494 } 00495 //----------------------------------------------------------------------- 00496 IndexData::~IndexData() 00497 { 00498 } 00499 //----------------------------------------------------------------------- 00500 IndexData* IndexData::clone(bool copyData) const 00501 { 00502 IndexData* dest = new IndexData(); 00503 if (indexBuffer.get()) 00504 { 00505 if (copyData) 00506 { 00507 dest->indexBuffer = HardwareBufferManager::getSingleton(). 00508 createIndexBuffer(indexBuffer->getType(), indexBuffer->getNumIndexes(), 00509 indexBuffer->getUsage(), indexBuffer->hasShadowBuffer()); 00510 dest->indexBuffer->copyData(*indexBuffer, 0, 0, indexBuffer->getSizeInBytes(), true); 00511 } 00512 else 00513 { 00514 dest->indexBuffer = indexBuffer; 00515 } 00516 } 00517 dest->indexCount = indexCount; 00518 dest->indexStart = indexStart; 00519 return dest; 00520 } 00521 00522 }
Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:51 2004