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