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

OgreVertexIndexData.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-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