source: OGRE/trunk/ogrenew/OgreMain/src/OgreVertexIndexData.cpp @ 657

Revision 657, 21.3 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26#include "OgreVertexIndexData.h"
27#include "OgreHardwareBufferManager.h"
28#include "OgreHardwareVertexBuffer.h"
29#include "OgreHardwareIndexBuffer.h"
30#include "OgreVector3.h"
31#include "OgreAxisAlignedBox.h"
32#include "OgreRoot.h"
33#include "OgreRenderSystem.h"
34#include "OgreException.h"
35
36namespace Ogre {
37
38    //-----------------------------------------------------------------------
39        VertexData::VertexData()
40        {
41                vertexBufferBinding = HardwareBufferManager::getSingleton().
42                        createVertexBufferBinding();
43                vertexDeclaration = HardwareBufferManager::getSingleton().
44                        createVertexDeclaration();
45                vertexCount = 0;
46                vertexStart = 0;
47
48        }
49    //-----------------------------------------------------------------------
50        VertexData::~VertexData()
51        {
52                HardwareBufferManager::getSingleton().
53                        destroyVertexBufferBinding(vertexBufferBinding);
54                HardwareBufferManager::getSingleton().destroyVertexDeclaration(vertexDeclaration);
55
56        }
57    //-----------------------------------------------------------------------
58        VertexData* VertexData::clone(bool copyData) const
59        {
60                VertexData* dest = new VertexData();
61
62                // Copy vertex buffers in turn
63                const VertexBufferBinding::VertexBufferBindingMap bindings =
64                        this->vertexBufferBinding->getBindings();
65                VertexBufferBinding::VertexBufferBindingMap::const_iterator vbi, vbend;
66                vbend = bindings.end();
67                for (vbi = bindings.begin(); vbi != vbend; ++vbi)
68                {
69                        HardwareVertexBufferSharedPtr srcbuf = vbi->second;
70            HardwareVertexBufferSharedPtr dstBuf;
71            if (copyData)
72            {
73                            // create new buffer with the same settings
74                            dstBuf =
75                                    HardwareBufferManager::getSingleton().createVertexBuffer(
76                                            srcbuf->getVertexSize(), srcbuf->getNumVertices(), srcbuf->getUsage(),
77                                            srcbuf->hasShadowBuffer());
78
79                            // copy data
80                            dstBuf->copyData(*srcbuf, 0, 0, srcbuf->getSizeInBytes(), true);
81            }
82            else
83            {
84                // don't copy, point at existing buffer
85                dstBuf = srcbuf;
86            }
87
88                        // Copy binding
89                        dest->vertexBufferBinding->setBinding(vbi->first, dstBuf);
90        }
91
92        // Basic vertex info
93        dest->vertexStart = this->vertexStart;
94                dest->vertexCount = this->vertexCount;
95        // Copy elements
96        const VertexDeclaration::VertexElementList elems =
97            this->vertexDeclaration->getElements();
98        VertexDeclaration::VertexElementList::const_iterator ei, eiend;
99        eiend = elems.end();
100        for (ei = elems.begin(); ei != eiend; ++ei)
101        {
102            dest->vertexDeclaration->addElement(
103                ei->getSource(),
104                ei->getOffset(),
105                ei->getType(),
106                ei->getSemantic(),
107                ei->getIndex() );
108        }
109
110       
111        return dest;
112        }
113    //-----------------------------------------------------------------------
114    void VertexData::prepareForShadowVolume(void)
115    {
116        /* NOTE
117        I would dearly, dearly love to just use a 4D position buffer in order to
118        store the extra 'w' value I need to differentiate between extruded and
119        non-extruded sections of the buffer, so that vertex programs could use that.
120        Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not
121        support 4d position vertices in the fixed-function pipeline. If you use them,
122        you just see nothing. Since we can't know whether the application is going to use
123        fixed function or vertex programs, we have to stick to 3d position vertices and
124        store the 'w' in a separate 1D texture coordinate buffer, which is only used
125        when rendering the shadow.
126        */
127
128        // Upfront, lets check whether we have vertex program capability
129        RenderSystem* rend = Root::getSingleton().getRenderSystem();
130        bool useVertexPrograms = false;
131        if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
132        {
133            useVertexPrograms = true;
134        }
135
136
137        // Look for a position element
138        const VertexElement* posElem = vertexDeclaration->findElementBySemantic(VES_POSITION);
139        if (posElem)
140        {
141            size_t v;
142            unsigned posOldSource = posElem->getSource();
143
144            HardwareVertexBufferSharedPtr vbuf = vertexBufferBinding->getBuffer(posOldSource);
145            bool wasSharedBuffer = false;
146            // Are there other elements in the buffer except for the position?
147            if (vbuf->getVertexSize() > posElem->getSize())
148            {
149                // We need to create another buffer to contain the remaining elements
150                // Most drivers don't like gaps in the declaration, and in any case it's waste
151                wasSharedBuffer = true;
152            }
153            HardwareVertexBufferSharedPtr newPosBuffer, newRemainderBuffer;
154            if (wasSharedBuffer)
155            {
156                newRemainderBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
157                    vbuf->getVertexSize() - posElem->getSize(), vbuf->getNumVertices(), vbuf->getUsage(),
158                    vbuf->hasShadowBuffer());
159            }
160            // Allocate new position buffer, will be FLOAT3 and 2x the size
161            size_t oldVertexCount = vbuf->getNumVertices();
162            size_t newVertexCount = oldVertexCount * 2;
163            newPosBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
164                VertexElement::getTypeSize(VET_FLOAT3), newVertexCount, vbuf->getUsage(),
165                vbuf->hasShadowBuffer());
166
167            // Iterate over the old buffer, copying the appropriate elements and initialising the rest
168            float* pSrc;
169            unsigned char *pBaseSrc = static_cast<unsigned char*>(
170                vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
171            // Point first destination pointer at the start of the new position buffer,
172            // the other one half way along
173            float *pDest = static_cast<float*>(newPosBuffer->lock(HardwareBuffer::HBL_DISCARD));
174            float* pDest2 = pDest + oldVertexCount * 3;
175
176            // Precalculate any dimensions of vertex areas outside the position
177            size_t prePosVertexSize, postPosVertexSize, postPosVertexOffset;
178            unsigned char *pBaseDestRem = 0;
179            if (wasSharedBuffer)
180            {
181                pBaseDestRem = static_cast<unsigned char*>(
182                    newRemainderBuffer->lock(HardwareBuffer::HBL_DISCARD));
183                prePosVertexSize = posElem->getOffset();
184                postPosVertexOffset = prePosVertexSize + posElem->getSize();
185                postPosVertexSize = vbuf->getVertexSize() - postPosVertexOffset;
186                // the 2 separate bits together should be the same size as the remainder buffer vertex
187                assert (newRemainderBuffer->getVertexSize() == prePosVertexSize + postPosVertexSize);
188
189                // Iterate over the vertices
190                for (v = 0; v < oldVertexCount; ++v)
191                {
192                    // Copy position, into both buffers
193                    posElem->baseVertexPointerToElement(pBaseSrc, &pSrc);
194                    *pDest++ = *pDest2++ = *pSrc++;
195                    *pDest++ = *pDest2++ = *pSrc++;
196                    *pDest++ = *pDest2++ = *pSrc++;
197
198                    // now deal with any other elements
199                    // Basically we just memcpy the vertex excluding the position
200                    if (prePosVertexSize > 0)
201                        memcpy(pBaseDestRem, pBaseSrc, prePosVertexSize);
202                    if (postPosVertexSize > 0)
203                        memcpy(pBaseDestRem + prePosVertexSize,
204                            pBaseSrc + postPosVertexOffset, postPosVertexSize);
205                    pBaseDestRem += newRemainderBuffer->getVertexSize();
206
207                    pBaseSrc += vbuf->getVertexSize();
208
209                } // next vertex
210            }
211            else
212            {
213                // Unshared buffer, can block copy the whole thing
214                memcpy(pDest, pBaseSrc, vbuf->getSizeInBytes());
215                memcpy(pDest2, pBaseSrc, vbuf->getSizeInBytes());
216            }
217
218            vbuf->unlock();
219            newPosBuffer->unlock();
220            if (wasSharedBuffer)
221                newRemainderBuffer->unlock();
222
223            // At this stage, he original vertex buffer is going to be destroyed
224            // So we should force the deallocation of any temporary copies
225            HardwareBufferManager::getSingleton()._forceReleaseBufferCopies(vbuf);
226
227            if (useVertexPrograms)
228            {
229                // Now it's time to set up the w buffer
230                hardwareShadowVolWBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
231                    sizeof(float), newVertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
232                // Fill the first half with 1.0, second half with 0.0
233                pDest = static_cast<float*>(
234                    hardwareShadowVolWBuffer->lock(HardwareBuffer::HBL_DISCARD));
235                for (v = 0; v < oldVertexCount; ++v)
236                {
237                    *pDest++ = 1.0f;
238                }
239                for (v = 0; v < oldVertexCount; ++v)
240                {
241                    *pDest++ = 0.0f;
242                }
243                hardwareShadowVolWBuffer->unlock();
244            }
245
246            unsigned short newPosBufferSource;
247            if (wasSharedBuffer)
248            {
249                // Get the a new buffer binding index
250                newPosBufferSource= vertexBufferBinding->getNextIndex();
251                // Re-bind the old index to the remainder buffer
252                vertexBufferBinding->setBinding(posOldSource, newRemainderBuffer);
253            }
254            else
255            {
256                // We can just re-use the same source idex for the new position buffer
257                newPosBufferSource = posOldSource;
258            }
259            // Bind the new position buffer
260            vertexBufferBinding->setBinding(newPosBufferSource, newPosBuffer);
261
262            // Now, alter the vertex declaration to change the position source
263            // and the offsets of elements using the same buffer
264            VertexDeclaration::VertexElementList::const_iterator elemi =
265                vertexDeclaration->getElements().begin();
266            VertexDeclaration::VertexElementList::const_iterator elemiend =
267                vertexDeclaration->getElements().end();
268            unsigned short idx;
269            for(idx = 0; elemi != elemiend; ++elemi, ++idx)
270            {
271                if (&(*elemi) == posElem)
272                {
273                    // Modify position to point at new position buffer
274                    vertexDeclaration->modifyElement(
275                        idx,
276                        newPosBufferSource, // new source buffer
277                        0, // no offset now
278                        VET_FLOAT3,
279                        VES_POSITION);
280                }
281                else if (wasSharedBuffer &&
282                    elemi->getSource() == posOldSource &&
283                    elemi->getOffset() > prePosVertexSize )
284                {
285                    // This element came after position, remove the position's
286                    // size
287                    vertexDeclaration->modifyElement(
288                        idx,
289                        posOldSource, // same old source
290                        elemi->getOffset() - posElem->getSize(), // less offset now
291                        elemi->getType(),
292                        elemi->getSemantic(),
293                        elemi->getIndex());
294
295                }
296
297            }
298
299
300            // Note that we don't change vertexCount, because the other buffer(s) are still the same
301            // size after all
302
303
304        }
305    }
306        //-----------------------------------------------------------------------
307        void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration, const BufferUsageList& bufferUsages)
308        {
309        // Firstly, close up any gaps in the buffer sources which might have arisen
310        newDeclaration->closeGapsInSource();
311
312                // Build up a list of both old and new elements in each buffer
313                unsigned short buf = 0;
314                std::vector<void*> oldBufferLocks;
315        std::vector<size_t> oldBufferVertexSizes;
316                std::vector<void*> newBufferLocks;
317        std::vector<size_t> newBufferVertexSizes;
318                VertexBufferBinding* newBinding =
319                        HardwareBufferManager::getSingleton().createVertexBufferBinding();
320        const VertexBufferBinding::VertexBufferBindingMap& oldBindingMap = vertexBufferBinding->getBindings();
321        VertexBufferBinding::VertexBufferBindingMap::const_iterator itBinding;
322
323        // Pre-allocate old buffer locks
324        if (!oldBindingMap.empty())
325        {
326            size_t count = oldBindingMap.rbegin()->first + 1;
327            oldBufferLocks.resize(count);
328            oldBufferVertexSizes.resize(count);
329        }
330                // Lock all the old buffers for reading
331        for (itBinding = oldBindingMap.begin(); itBinding != oldBindingMap.end(); ++itBinding)
332        {
333            assert(itBinding->second->getNumVertices() >= vertexCount);
334
335            oldBufferVertexSizes[itBinding->first] =
336                itBinding->second->getVertexSize();
337            oldBufferLocks[itBinding->first] =
338                itBinding->second->lock(
339                    HardwareBuffer::HBL_READ_ONLY);
340        }
341               
342                // Create new buffers and lock all for writing
343                buf = 0;
344                while (!newDeclaration->findElementsBySource(buf).empty())
345                {
346            size_t vertexSize = newDeclaration->getVertexSize(buf);
347
348                        HardwareVertexBufferSharedPtr vbuf =
349                                HardwareBufferManager::getSingleton().createVertexBuffer(
350                                        vertexSize,
351                                        vertexCount,
352                                        bufferUsages[buf]);
353                        newBinding->setBinding(buf, vbuf);
354
355            newBufferVertexSizes.push_back(vertexSize);
356                        newBufferLocks.push_back(
357                                vbuf->lock(HardwareBuffer::HBL_DISCARD));
358                        buf++;
359                }
360
361                // Map from new to old elements
362        typedef std::map<const VertexElement*, const VertexElement*> NewToOldElementMap;
363                NewToOldElementMap newToOldElementMap;
364                const VertexDeclaration::VertexElementList& newElemList = newDeclaration->getElements();
365                VertexDeclaration::VertexElementList::const_iterator ei, eiend;
366                eiend = newElemList.end();
367                for (ei = newElemList.begin(); ei != eiend; ++ei)
368                {
369                        // Find corresponding old element
370                        const VertexElement* oldElem =
371                                vertexDeclaration->findElementBySemantic(
372                                        (*ei).getSemantic(), (*ei).getIndex());
373                        if (!oldElem)
374                        {
375                                // Error, cannot create new elements with this method
376                                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
377                                        "Element not found in old vertex declaration",
378                                        "VertexData::reorganiseBuffers");
379                        }
380                        newToOldElementMap[&(*ei)] = oldElem;
381                }
382                // Now iterate over the new buffers, pulling data out of the old ones
383                // For each vertex
384                for (size_t v = 0; v < vertexCount; ++v)
385                {
386                        // For each (new) element
387                        for (ei = newElemList.begin(); ei != eiend; ++ei)
388                        {
389                                const VertexElement* newElem = &(*ei);
390                NewToOldElementMap::iterator noi = newToOldElementMap.find(newElem);
391                                const VertexElement* oldElem = noi->second;
392                                unsigned short oldBufferNo = oldElem->getSource();
393                                unsigned short newBufferNo = newElem->getSource();
394                                void* pSrcBase = static_cast<void*>(
395                                        static_cast<unsigned char*>(oldBufferLocks[oldBufferNo])
396                                        + v * oldBufferVertexSizes[oldBufferNo]);
397                                void* pDstBase = static_cast<void*>(
398                                        static_cast<unsigned char*>(newBufferLocks[newBufferNo])
399                                        + v * newBufferVertexSizes[newBufferNo]);
400                                void *pSrc, *pDst;
401                                oldElem->baseVertexPointerToElement(pSrcBase, &pSrc);
402                                newElem->baseVertexPointerToElement(pDstBase, &pDst);
403                               
404                                memcpy(pDst, pSrc, newElem->getSize());
405                               
406                        }
407                }
408
409                // Unlock all buffers
410        for (itBinding = oldBindingMap.begin(); itBinding != oldBindingMap.end(); ++itBinding)
411        {
412            itBinding->second->unlock();
413        }
414        for (buf = 0; buf < newBinding->getBufferCount(); ++buf)
415        {
416            newBinding->getBuffer(buf)->unlock();
417        }
418
419                // Delete old binding & declaration
420                HardwareBufferManager::getSingleton().
421                        destroyVertexBufferBinding(vertexBufferBinding);
422                HardwareBufferManager::getSingleton().destroyVertexDeclaration(vertexDeclaration);
423
424                // Assign new binding and declaration
425                vertexDeclaration = newDeclaration;
426                vertexBufferBinding = newBinding;               
427
428        }
429    //-----------------------------------------------------------------------
430    void VertexData::reorganiseBuffers(VertexDeclaration* newDeclaration)
431    {
432        // Derive the buffer usages from looking at where the source has come
433        // from
434        BufferUsageList usages;
435        for (unsigned short b = 0; b <= newDeclaration->getMaxSource(); ++b)
436        {
437            VertexDeclaration::VertexElementList destElems = newDeclaration->findElementsBySource(b);
438            // Initialise with most restrictive version
439            // (not really a usable option, but these flags will be removed)
440            HardwareBuffer::Usage final = static_cast<HardwareBuffer::Usage>(
441                HardwareBuffer::HBU_STATIC_WRITE_ONLY | HardwareBuffer::HBU_DISCARDABLE);
442            VertexDeclaration::VertexElementList::iterator v;
443            for (v = destElems.begin(); v != destElems.end(); ++v)
444            {
445                VertexElement& destelem = *v;
446                // get source
447                const VertexElement* srcelem =
448                    vertexDeclaration->findElementBySemantic(
449                        destelem.getSemantic(), destelem.getIndex());
450                // get buffer
451                HardwareVertexBufferSharedPtr srcbuf =
452                    vertexBufferBinding->getBuffer(srcelem->getIndex());
453                // improve flexibility only
454                if (srcbuf->getUsage() & HardwareBuffer::HBU_DYNAMIC)
455                {
456                    // remove static
457                    final = static_cast<HardwareBuffer::Usage>(
458                        final & ~HardwareBuffer::HBU_STATIC);
459                    // add dynamic
460                    final = static_cast<HardwareBuffer::Usage>(
461                        final | HardwareBuffer::HBU_DYNAMIC);
462                }
463                if (!(srcbuf->getUsage() & HardwareBuffer::HBU_WRITE_ONLY))
464                {
465                    // remove write only
466                    final = static_cast<HardwareBuffer::Usage>(
467                        final & ~HardwareBuffer::HBU_WRITE_ONLY);
468                }
469                if (!(srcbuf->getUsage() & HardwareBuffer::HBU_DISCARDABLE))
470                {
471                    // remove discardable
472                    final = static_cast<HardwareBuffer::Usage>(
473                        final & ~HardwareBuffer::HBU_DISCARDABLE);
474                }
475               
476            }
477            usages.push_back(final);
478        }
479        // Call specific method
480        reorganiseBuffers(newDeclaration, usages);
481
482    }
483    //-----------------------------------------------------------------------
484        //-----------------------------------------------------------------------
485        IndexData::IndexData()
486        {
487                indexCount = 0;
488                indexStart = 0;
489               
490        }
491    //-----------------------------------------------------------------------
492        IndexData::~IndexData()
493        {
494        }
495    //-----------------------------------------------------------------------
496        IndexData* IndexData::clone(bool copyData) const
497        {
498                IndexData* dest = new IndexData();
499                if (indexBuffer.get())
500                {
501            if (copyData)
502            {
503                            dest->indexBuffer = HardwareBufferManager::getSingleton().
504                                    createIndexBuffer(indexBuffer->getType(), indexBuffer->getNumIndexes(),
505                                    indexBuffer->getUsage(), indexBuffer->hasShadowBuffer());
506                            dest->indexBuffer->copyData(*indexBuffer, 0, 0, indexBuffer->getSizeInBytes(), true);
507            }
508            else
509            {
510                dest->indexBuffer = indexBuffer;
511            }
512        }
513                dest->indexCount = indexCount;
514                dest->indexStart = indexStart;
515                return dest;
516        }
517
518}
Note: See TracBrowser for help on using the repository browser.