Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/OgreMain/src/OgreProgressiveMesh.cpp @ 45

Last change on this file since 45 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

File size: 33.2 KB
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-2006 Torus Knot Software Ltd
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
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30
31// The algorithm in this file is based heavily on:
32/*
33*  Progressive Mesh type Polygon Reduction Algorithm
34*  by Stan Melax (c) 1998
35*/
36
37#include "OgreProgressiveMesh.h"
38#include "OgreString.h"
39#include "OgreHardwareBufferManager.h"
40#include <algorithm>
41
42#include <iostream>
43
44#if OGRE_DEBUG_MODE
45std::ofstream ofdebug;
46#endif
47
48namespace Ogre {
49        #define NEVER_COLLAPSE_COST 99999.9f
50
51
52    /** Comparator for unique vertex list
53    */
54    struct vectorLess
55    {
56                _OgreExport bool operator()(const Vector3& v1, const Vector3& v2) const
57        {
58                        if (v1.x < v2.x) return true;
59                        if (v1.x == v2.x && v1.y < v2.y) return true;
60                        if (v1.x == v2.x && v1.y == v2.y && v1.z < v2.z) return true;
61
62                        return false;
63                }
64        };
65    //---------------------------------------------------------------------
66    ProgressiveMesh::ProgressiveMesh(const VertexData* vertexData, 
67        const IndexData* indexData)
68    {
69        addWorkingData(vertexData, indexData);
70        mpVertexData = vertexData;
71        mpIndexData = indexData;
72        mWorstCosts.resize(vertexData->vertexCount);
73
74
75
76    }
77    //---------------------------------------------------------------------
78    ProgressiveMesh::~ProgressiveMesh()
79    {
80    }
81    //---------------------------------------------------------------------
82    void ProgressiveMesh::addExtraVertexPositionBuffer(const VertexData* vertexData)
83    {
84        addWorkingData(vertexData, mpIndexData);
85    }
86    //---------------------------------------------------------------------
87    void ProgressiveMesh::build(ushort numLevels, LODFaceList* outList, 
88                        VertexReductionQuota quota, Real reductionValue)
89    {
90        IndexData* newLod;
91
92        computeAllCosts();
93
94#if OGRE_DEBUG_MODE
95                dumpContents("pm_before.log");
96#endif
97
98        // Init
99        mCurrNumIndexes = mpIndexData->indexCount;
100        size_t numVerts, numCollapses;
101        // Use COMMON vert count, not original vert count
102        // Since collapsing 1 common vert position is equivalent to collapsing them all
103        numVerts = mNumCommonVertices;
104               
105#if OGRE_DEBUG_MODE
106                ofdebug.open("progressivemesh.log");
107#endif
108                numCollapses = 0;
109                bool abandon = false;
110                while (numLevels--)
111        {
112            // NB idf 'abandon' is set, we stop reducing
113            // However, we still bake the number of LODs requested, even if it
114            // means they are the same
115            if (!abandon)
116            {
117                            if (quota == VRQ_PROPORTIONAL)
118                            {
119                                    numCollapses = static_cast<size_t>(numVerts * reductionValue);
120                            }
121                            else 
122                            {
123                                    numCollapses = static_cast<size_t>(reductionValue);
124                            }
125                // Minimum 3 verts!
126                if ( (numVerts - numCollapses) < 3) 
127                    numCollapses = numVerts - 3;
128                            // Store new number of verts
129                            numVerts = numVerts - numCollapses;
130
131                            while(numCollapses-- && !abandon)
132                {
133                    size_t nextIndex = getNextCollapser();
134                    // Collapse on every buffer
135                    WorkingDataList::iterator idata, idataend;
136                    idataend = mWorkingData.end();
137                    for (idata = mWorkingData.begin(); idata != idataend; ++idata)
138                    {
139                        PMVertex* collapser = &( idata->mVertList.at( nextIndex ) );
140                        // This will reduce mCurrNumIndexes and recalc costs as required
141                                            if (collapser->collapseTo == NULL)
142                                            {
143                                                    // Must have run out of valid collapsables
144                                                    abandon = true;
145                                                    break;
146                                            }
147#if OGRE_DEBUG_MODE
148                                            ofdebug << "Collapsing index " << (unsigned int)collapser->index << "(border: "<< collapser->isBorder() <<
149                                                    ") to " << (unsigned int)collapser->collapseTo->index << "(border: "<< collapser->collapseTo->isBorder() <<
150                                                    ")" << std::endl;
151#endif
152                                            assert(collapser->collapseTo->removed == false);
153
154                        collapse(collapser);
155                    }
156
157                }
158            }
159#if OGRE_DEBUG_MODE
160                        StringUtil::StrStreamType logname;
161                        logname << "pm_level" << numLevels << ".log";
162                        dumpContents(logname.str());
163#endif
164
165            // Bake a new LOD and add it to the list
166            newLod = new IndexData();
167            bakeNewLOD(newLod);
168            outList->push_back(newLod);
169                       
170        }
171
172
173
174    }
175    //---------------------------------------------------------------------
176    void ProgressiveMesh::addWorkingData(const VertexData * vertexData, 
177        const IndexData * indexData)
178    {
179        // Insert blank working data, then fill
180        mWorkingData.push_back(PMWorkingData());
181
182        PMWorkingData& work = mWorkingData.back();
183
184        // Build vertex list
185                // Resize face list (this will always be this big)
186                work.mFaceVertList.resize(vertexData->vertexCount);
187                // Also resize common vert list to max, to avoid reallocations
188                work.mVertList.resize(vertexData->vertexCount);
189
190                // locate position element & hte buffer to go with it
191                const VertexElement* posElem = vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
192                HardwareVertexBufferSharedPtr vbuf = 
193                        vertexData->vertexBufferBinding->getBuffer(posElem->getSource());
194                // lock the buffer for reading
195                unsigned char* pVertex = static_cast<unsigned char*>(
196                        vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
197                float* pFloat;
198                Vector3 pos;
199                // Map for identifying duplicate position vertices
200                typedef std::map<Vector3, size_t, vectorLess> CommonVertexMap;
201                CommonVertexMap commonVertexMap;
202                CommonVertexMap::iterator iCommonVertex;
203                size_t numCommon = 0;
204        size_t i = 0;
205        for (i = 0; i < vertexData->vertexCount; ++i, pVertex += vbuf->getVertexSize())
206        {
207                        posElem->baseVertexPointerToElement(pVertex, &pFloat);
208
209            pos.x = *pFloat++;
210            pos.y = *pFloat++;
211            pos.z = *pFloat++;
212
213                        // Try to find this position in the existing map
214                        iCommonVertex = commonVertexMap.find(pos);
215                        if (iCommonVertex == commonVertexMap.end())
216                        {
217                                // Doesn't exist, so create it
218                                PMVertex* commonVert = &(work.mVertList[numCommon]);
219                                commonVert->setDetails(pos, numCommon);
220                                commonVert->removed = false;
221                                commonVert->toBeRemoved = false;
222                                commonVert->seam = false;
223
224                                // Enter it in the map
225                                commonVertexMap.insert(CommonVertexMap::value_type(pos, numCommon) );
226                                // Increment common index
227                                ++numCommon;
228
229                                work.mFaceVertList[i].commonVertex = commonVert;
230                                work.mFaceVertList[i].realIndex = i;
231                        }
232                        else
233                        {
234                                // Exists already, reference it
235                                PMVertex* existingVert = &(work.mVertList[iCommonVertex->second]);
236                                work.mFaceVertList[i].commonVertex = existingVert;
237                                work.mFaceVertList[i].realIndex = i;
238
239                                // Also tag original as a seam since duplicates at this location
240                                work.mFaceVertList[i].commonVertex->seam = true;
241
242                        }
243                       
244        }
245                vbuf->unlock();
246
247                mNumCommonVertices = numCommon;
248
249        // Build tri list
250        size_t numTris = indexData->indexCount / 3;
251                unsigned short* pShort;
252                unsigned int* pInt;
253                HardwareIndexBufferSharedPtr ibuf = indexData->indexBuffer;
254                bool use32bitindexes = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
255                if (use32bitindexes)
256                {
257                        pInt = static_cast<unsigned int*>(
258                                ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
259                }
260                else
261                {
262                        pShort = static_cast<unsigned short*>(
263                                ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
264                }
265        work.mTriList.resize(numTris); // assumed tri list
266        for (i = 0; i < numTris; ++i)
267        {
268                        PMFaceVertex *v0, *v1, *v2;
269                        // use 32-bit index always since we're not storing
270                        unsigned int vindex = use32bitindexes? *pInt++ : *pShort++;
271                        v0 = &(work.mFaceVertList[vindex]);
272                        vindex = use32bitindexes? *pInt++ : *pShort++;
273                        v1 = &(work.mFaceVertList[vindex]);
274                        vindex = use32bitindexes? *pInt++ : *pShort++;
275                        v2 = &(work.mFaceVertList[vindex]);
276
277                        work.mTriList[i].setDetails(i, v0, v1, v2);
278
279            work.mTriList[i].removed = false;
280
281        }
282                ibuf->unlock();
283
284    }
285    //---------------------------------------------------------------------
286    Real ProgressiveMesh::computeEdgeCollapseCost(PMVertex *src, PMVertex *dest)
287    {
288        // if we collapse edge uv by moving src to dest then how
289        // much different will the model change, i.e. how much "error".
290        // The method of determining cost was designed in order
291        // to exploit small and coplanar regions for
292        // effective polygon reduction.
293        Vector3 edgeVector = src->position - dest->position;
294
295        Real cost;
296                Real curvature = 0.001f;
297
298        // find the "sides" triangles that are on the edge uv
299        PMVertex::FaceList sides;
300        PMVertex::FaceList::iterator srcface, srcfaceEnd;
301        srcfaceEnd = src->face.end();
302        // Iterate over src's faces and find 'sides' of the shared edge which is being collapsed
303        for(srcface = src->face.begin(); srcface != srcfaceEnd; ++srcface)
304        {
305            // Check if this tri also has dest in it (shared edge)
306            if( (*srcface)->hasCommonVertex(dest) )
307            {
308                sides.insert(*srcface);
309            }
310        }
311
312                // Special cases
313                // If we're looking at a border vertex
314        if(src->isBorder())
315        {
316                        if (sides.size() > 1) 
317                        {
318                                // src is on a border, but the src-dest edge has more than one tri on it
319                                // So it must be collapsing inwards
320                                // Mark as very high-value cost
321                                // curvature = 1.0f;
322                                cost = 1.0f;
323                        }
324                        else
325                        {
326                                // Collapsing ALONG a border
327                                // We can't use curvature to measure the effect on the model
328                                // Instead, see what effect it has on 'pulling' the other border edges
329                                // The more colinear, the less effect it will have
330                                // So measure the 'kinkiness' (for want of a better term)
331                                // Normally there can be at most 1 other border edge attached to this
332                                // However in weird cases there may be more, so find the worst
333                                Vector3 collapseEdge, otherBorderEdge;
334                                Real kinkiness, maxKinkiness;
335                                PMVertex::NeighborList::iterator n, nend;
336                                nend = src->neighbor.end();
337                                maxKinkiness = 0.0f;
338                                edgeVector.normalise();
339                                collapseEdge = edgeVector;
340                                for (n = src->neighbor.begin(); n != nend; ++n)
341                                {
342                                        if (*n != dest && (*n)->isManifoldEdgeWith(src))
343                                        {
344                                                otherBorderEdge = src->position - (*n)->position;
345                                                otherBorderEdge.normalise();
346                                                // This time, the nearer the dot is to -1, the better, because that means
347                                                // the edges are opposite each other, therefore less kinkiness
348                                                // Scale into [0..1]
349                                                kinkiness = (otherBorderEdge.dotProduct(collapseEdge) + 1.002f) * 0.5f;
350                                                maxKinkiness = std::max(kinkiness, maxKinkiness);
351
352                                        }
353                                }
354
355                                cost = maxKinkiness; 
356
357                        }
358        } 
359                else // not a border
360                {
361
362                        // Standard inner vertex
363                        // Calculate curvature
364                        // use the triangle facing most away from the sides
365                        // to determine our curvature term
366                        // Iterate over src's faces again
367                        for(srcface = src->face.begin(); srcface != srcfaceEnd; ++srcface) 
368                        {
369                                Real mincurv = 1.0f; // curve for face i and closer side to it
370                                // Iterate over the sides
371                                PMVertex::FaceList::iterator sidesFace, sidesFaceEnd;
372                                sidesFaceEnd = sides.end();
373                                for(sidesFace = sides.begin(); sidesFace != sidesFaceEnd; ++sidesFace) 
374                                {
375                                        // Dot product of face normal gives a good delta angle
376                                        Real dotprod = (*srcface)->normal.dotProduct( (*sidesFace)->normal );
377                                        // NB we do (1-..) to invert curvature where 1 is high curvature [0..1]
378                                        // Whilst dot product is high when angle difference is low
379                                        mincurv =  std::min(mincurv,(1.002f - dotprod) * 0.5f);
380                                }
381                                curvature = std::max(curvature, mincurv);
382                        }
383                        cost = curvature;
384                }
385
386        // check for texture seam ripping
387                if (src->seam && !dest->seam)
388                {
389                        cost = 1.0f;
390                }
391
392        // Check for singular triangle destruction
393        // If src and dest both only have 1 triangle (and it must be a shared one)
394        // then this would destroy the shape, so don't do this
395        if (src->face.size() == 1 && dest->face.size() == 1)
396        {
397            cost = NEVER_COLLAPSE_COST;
398        }
399
400
401                // Degenerate case check
402                // Are we going to invert a face normal of one of the neighbouring faces?
403                // Can occur when we have a very small remaining edge and collapse crosses it
404                // Look for a face normal changing by > 90 degrees
405                for(srcface = src->face.begin(); srcface != srcfaceEnd; ++srcface) 
406                {
407                        // Ignore the deleted faces (those including src & dest)
408                        if( !(*srcface)->hasCommonVertex(dest) )
409                        {
410                                // Test the new face normal
411                                PMVertex *v0, *v1, *v2;
412                                // Replace src with dest wherever it is
413                                v0 = ( (*srcface)->vertex[0]->commonVertex == src) ? dest : (*srcface)->vertex[0]->commonVertex;
414                                v1 = ( (*srcface)->vertex[1]->commonVertex == src) ? dest : (*srcface)->vertex[1]->commonVertex;
415                                v2 = ( (*srcface)->vertex[2]->commonVertex == src) ? dest : (*srcface)->vertex[2]->commonVertex;
416
417                                // Cross-product 2 edges
418                                Vector3 e1 = v1->position - v0->position; 
419                                Vector3 e2 = v2->position - v1->position;
420
421                                Vector3 newNormal = e1.crossProduct(e2);
422                                newNormal.normalise();
423
424                                // Dot old and new face normal
425                                // If < 0 then more than 90 degree difference
426                                if (newNormal.dotProduct( (*srcface)->normal ) < 0.0f )
427                                {
428                                        // Don't do it!
429                                        cost = NEVER_COLLAPSE_COST;
430                                        break; // No point continuing
431                                }
432
433
434                        }
435                }
436               
437
438                assert (cost >= 0);
439                return cost;
440    }
441    //---------------------------------------------------------------------
442    void ProgressiveMesh::initialiseEdgeCollapseCosts(void)
443    {
444        WorkingDataList::iterator i, iend;
445        iend = mWorkingData.end();
446        for (i = mWorkingData.begin(); i != iend; ++i)
447        {
448            CommonVertexList::iterator v, vend;
449            vend = i->mVertList.end();
450            for (v = i->mVertList.begin(); v != vend; ++v)
451            {
452                v->collapseTo = NULL;
453                v->collapseCost = NEVER_COLLAPSE_COST;
454            }
455        }
456
457       
458    }
459    //---------------------------------------------------------------------
460    Real ProgressiveMesh::computeEdgeCostAtVertexForBuffer(WorkingDataList::iterator idata, size_t vertIndex)
461    {
462        // compute the edge collapse cost for all edges that start
463        // from vertex v.  Since we are only interested in reducing
464        // the object by selecting the min cost edge at each step, we
465        // only cache the cost of the least cost edge at this vertex
466        // (in member variable collapse) as well as the value of the
467        // cost (in member variable objdist).
468
469        CommonVertexList::iterator v = idata->mVertList.begin();
470        v += vertIndex;
471
472        if(v->neighbor.empty()) {
473            // v doesn't have neighbors so nothing to collapse
474            v->notifyRemoved();
475            return v->collapseCost;
476        }
477
478        // Init metrics
479        v->collapseCost = NEVER_COLLAPSE_COST;
480        v->collapseTo = NULL;
481
482        // search all neighboring edges for "least cost" edge
483        PMVertex::NeighborList::iterator n, nend;
484        nend = v->neighbor.end();
485        Real cost;
486        for(n = v->neighbor.begin(); n != nend; ++n) 
487        {
488            cost = computeEdgeCollapseCost(&(*v), *n);
489            if( (!v->collapseTo) || cost < v->collapseCost) 
490            {
491                v->collapseTo = *n;  // candidate for edge collapse
492                v->collapseCost = cost;             // cost of the collapse
493            }
494        }
495
496        return v->collapseCost;
497    }
498    //---------------------------------------------------------------------
499    void ProgressiveMesh::computeAllCosts(void)
500    {
501        initialiseEdgeCollapseCosts();
502        size_t i;
503        for (i = 0; i < mpVertexData->vertexCount; ++i)
504        {
505            computeEdgeCostAtVertex(i);
506        }
507    }
508    //---------------------------------------------------------------------
509    void ProgressiveMesh::collapse(ProgressiveMesh::PMVertex *src)
510    {
511        PMVertex *dest = src->collapseTo;
512                std::set<PMVertex*> recomputeSet;
513
514                // Abort if we're never supposed to collapse
515                if (src->collapseCost == NEVER_COLLAPSE_COST) 
516                        return;
517
518                // Remove this vertex from the running for the next check
519                src->collapseTo = NULL;
520                src->collapseCost = NEVER_COLLAPSE_COST;
521                mWorstCosts[src->index] = NEVER_COLLAPSE_COST;
522
523                // Collapse the edge uv by moving vertex u onto v
524            // Actually remove tris on uv, then update tris that
525            // have u to have v, and then remove u.
526            if(!dest) {
527                    // src is a vertex all by itself
528#if OGRE_DEBUG_MODE
529                        ofdebug << "Aborting collapse, orphan vertex. " << std::endl;
530#endif
531                        return;
532            }
533
534                // Add dest and all the neighbours of source and dest to recompute list
535                recomputeSet.insert(dest);
536                PMVertex::NeighborList::iterator n, nend;
537        nend = src->neighbor.end();
538
539                PMVertex* temp;
540
541            for(n = src->neighbor.begin(); n != nend; ++n)
542        {
543                        temp = *n;
544                        recomputeSet.insert( *n );
545                }
546        nend = dest->neighbor.end();
547            for(n = dest->neighbor.begin(); n != nend; ++n)
548        {
549                        temp = *n;
550                        recomputeSet.insert( *n );
551                }
552
553            // delete triangles on edge src-dest
554        // Notify others to replace src with dest
555        PMVertex::FaceList::iterator f, fend;
556        fend = src->face.end();
557                // Queue of faces for removal / replacement
558                // prevents us screwing up the iterators while we parse
559                PMVertex::FaceList faceRemovalList, faceReplacementList;
560            for(f = src->face.begin(); f != fend; ++f) 
561        {
562                    if((*f)->hasCommonVertex(dest)) 
563            {
564                // Tri is on src-dest therefore is gone
565                                faceRemovalList.insert(*f);
566                // Reduce index count by 3 (useful for quick allocation later)
567                mCurrNumIndexes -= 3;
568                    }
569            else
570            {
571                // Only src involved, replace with dest
572                                faceReplacementList.insert(*f);
573            }
574            }
575
576                src->toBeRemoved = true;
577                // Replace all the faces queued for replacement
578            for(f = faceReplacementList.begin(); f != faceReplacementList.end(); ++f) 
579                {
580                        /* Locate the face vertex which corresponds with the common 'dest' vertex
581                        To to this, find a removed face which has the FACE vertex corresponding with
582                        src, and use it's FACE vertex version of dest.
583                        */
584                        PMFaceVertex* srcFaceVert = (*f)->getFaceVertexFromCommon(src);
585                        PMFaceVertex* destFaceVert = NULL;
586                        PMVertex::FaceList::iterator iremoved;
587                        for(iremoved = faceRemovalList.begin(); iremoved != faceRemovalList.end(); ++iremoved) 
588                        {
589                                //if ( (*iremoved)->hasFaceVertex(srcFaceVert) )
590                                //{
591                                        destFaceVert = (*iremoved)->getFaceVertexFromCommon(dest); 
592                                //}
593                        }
594                       
595                        assert(destFaceVert);
596
597#if OGRE_DEBUG_MODE
598                        ofdebug << "Replacing vertex on face " << (unsigned int)(*f)->index << std::endl;
599#endif
600            (*f)->replaceVertex(srcFaceVert, destFaceVert);
601                }
602                // Remove all the faces queued for removal
603            for(f = faceRemovalList.begin(); f != faceRemovalList.end(); ++f) 
604                {
605#if OGRE_DEBUG_MODE
606                        ofdebug << "Removing face " << (unsigned int)(*f)->index << std::endl;
607#endif
608                        (*f)->notifyRemoved();
609                }
610
611        // Notify the vertex that it is gone
612        src->notifyRemoved();
613
614        // recompute costs
615                std::set<PMVertex*>::iterator irecomp, irecompend;
616                irecompend = recomputeSet.end();
617                for (irecomp = recomputeSet.begin(); irecomp != irecompend; ++irecomp)
618                {
619                        temp = (*irecomp);
620                        computeEdgeCostAtVertex( (*irecomp)->index );
621                }
622               
623    }
624    //---------------------------------------------------------------------
625    void ProgressiveMesh::computeEdgeCostAtVertex(size_t vertIndex)
626    {
627                // Call computer for each buffer on this vertex
628        Real worstCost = -0.01f;
629        WorkingDataList::iterator i, iend;
630        iend = mWorkingData.end();
631        for (i = mWorkingData.begin(); i != iend; ++i)
632        {
633            worstCost = std::max(worstCost, 
634                computeEdgeCostAtVertexForBuffer(i, vertIndex));
635        }
636        // Save the worst cost
637        mWorstCosts[vertIndex] = worstCost;
638    }
639    //---------------------------------------------------------------------
640    size_t ProgressiveMesh::getNextCollapser(void)
641    {
642        // Scan
643        // Not done as a sort because want to keep the lookup simple for now
644        Real bestVal = NEVER_COLLAPSE_COST;
645        size_t i, bestIndex;
646                bestIndex = 0; // NB this is ok since if nothing is better than this, nothing will collapse
647        for (i = 0; i < mNumCommonVertices; ++i)
648        {
649            if (mWorstCosts[i] < bestVal)
650            {
651                bestVal = mWorstCosts[i];
652                bestIndex = i;
653            }
654        }
655        return bestIndex;
656    }
657    //---------------------------------------------------------------------
658    void ProgressiveMesh::bakeNewLOD(IndexData* pData)
659    {
660        assert(mCurrNumIndexes > 0 && "No triangles to bake!");
661        // Zip through the tri list of any working data copy and bake
662        pData->indexCount = mCurrNumIndexes;
663                pData->indexStart = 0;
664                // Base size of indexes on original
665                bool use32bitindexes = 
666                        (mpIndexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
667
668                // Create index buffer, we don't need to read it back or modify it a lot
669                pData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
670                        use32bitindexes? HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT,
671                        pData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
672
673        unsigned short* pShort;
674                unsigned int* pInt;
675                if (use32bitindexes)
676                {
677                        pInt = static_cast<unsigned int*>(
678                                pData->indexBuffer->lock( 0,
679                                        pData->indexBuffer->getSizeInBytes(),
680                                        HardwareBuffer::HBL_DISCARD));
681                }
682                else
683                {
684                        pShort = static_cast<unsigned short*>(
685                                pData->indexBuffer->lock( 0,
686                                        pData->indexBuffer->getSizeInBytes(),
687                                        HardwareBuffer::HBL_DISCARD));
688                }
689        TriangleList::iterator tri, triend;
690        // Use the first working data buffer, they are all the same index-wise
691        WorkingDataList::iterator pWork = mWorkingData.begin();
692        triend = pWork->mTriList.end();
693        for (tri = pWork->mTriList.begin(); tri != triend; ++tri)
694        {
695            if (!tri->removed)
696            {
697                                if (use32bitindexes)
698                                {
699                                        *pInt++ = static_cast<unsigned int>(tri->vertex[0]->realIndex);
700                                        *pInt++ = static_cast<unsigned int>(tri->vertex[1]->realIndex);
701                                        *pInt++ = static_cast<unsigned int>(tri->vertex[2]->realIndex);
702                                }
703                                else
704                                {
705                                        *pShort++ = static_cast<unsigned short>(tri->vertex[0]->realIndex);
706                                        *pShort++ = static_cast<unsigned short>(tri->vertex[1]->realIndex);
707                                        *pShort++ = static_cast<unsigned short>(tri->vertex[2]->realIndex);
708                                }
709            }
710        }
711                pData->indexBuffer->unlock();
712
713    }
714    //---------------------------------------------------------------------
715    ProgressiveMesh::PMTriangle::PMTriangle() : removed(false)
716    {
717    }
718    //---------------------------------------------------------------------
719    void ProgressiveMesh::PMTriangle::setDetails(size_t newindex, 
720                ProgressiveMesh::PMFaceVertex *v0, ProgressiveMesh::PMFaceVertex *v1, 
721        ProgressiveMesh::PMFaceVertex *v2)
722    {
723        assert(v0!=v1 && v1!=v2 && v2!=v0);
724
725        index = newindex;
726                vertex[0]=v0;
727        vertex[1]=v1;
728        vertex[2]=v2;
729
730        computeNormal();
731
732        // Add tri to vertices
733        // Also tell vertices they are neighbours
734        for(int i=0;i<3;i++) {
735            vertex[i]->commonVertex->face.insert(this);
736            for(int j=0;j<3;j++) if(i!=j) {
737                vertex[i]->commonVertex->neighbor.insert(vertex[j]->commonVertex);
738            }
739        }
740    }
741    //---------------------------------------------------------------------
742    void ProgressiveMesh::PMTriangle::notifyRemoved(void)
743    {
744        int i;
745        for(i=0; i<3; i++) {
746            // remove this tri from the vertices
747            if(vertex[i]) vertex[i]->commonVertex->face.erase(this);
748        }
749        for(i=0; i<3; i++) {
750            int i2 = (i+1)%3;
751            if(!vertex[i] || !vertex[i2]) continue;
752            // Check remaining vertices and remove if not neighbours anymore
753            // NB May remain neighbours if other tris link them
754            vertex[i ]->commonVertex->removeIfNonNeighbor(vertex[i2]->commonVertex);
755            vertex[i2]->commonVertex->removeIfNonNeighbor(vertex[i ]->commonVertex);
756        }
757
758        removed = true;
759    }
760    //---------------------------------------------------------------------
761    bool ProgressiveMesh::PMTriangle::hasCommonVertex(ProgressiveMesh::PMVertex *v) const
762    {
763        return (v == vertex[0]->commonVertex ||
764                        v == vertex[1]->commonVertex || 
765                        v == vertex[2]->commonVertex);
766    }
767    //---------------------------------------------------------------------
768        bool ProgressiveMesh::PMTriangle::hasFaceVertex(ProgressiveMesh::PMFaceVertex *v) const
769        {
770                return (v == vertex[0] ||
771                                v == vertex[1] || 
772                                v == vertex[2]);
773        }
774    //---------------------------------------------------------------------
775        ProgressiveMesh::PMFaceVertex* 
776        ProgressiveMesh::PMTriangle::getFaceVertexFromCommon(ProgressiveMesh::PMVertex* commonVert)
777        {
778                if (vertex[0]->commonVertex == commonVert) return vertex[0];
779                if (vertex[1]->commonVertex == commonVert) return vertex[1];
780                if (vertex[2]->commonVertex == commonVert) return vertex[2];
781
782                return NULL;
783
784        }
785    //---------------------------------------------------------------------
786    void ProgressiveMesh::PMTriangle::computeNormal()
787    {
788        Vector3 v0=vertex[0]->commonVertex->position;
789        Vector3 v1=vertex[1]->commonVertex->position;
790        Vector3 v2=vertex[2]->commonVertex->position;
791        // Cross-product 2 edges
792        Vector3 e1 = v1 - v0; 
793        Vector3 e2 = v2 - v1;
794
795        normal = e1.crossProduct(e2);
796        normal.normalise();
797    }
798    //---------------------------------------------------------------------
799    void ProgressiveMesh::PMTriangle::replaceVertex(
800                ProgressiveMesh::PMFaceVertex *vold, ProgressiveMesh::PMFaceVertex *vnew) 
801    {
802        assert(vold && vnew);
803        assert(vold==vertex[0] || vold==vertex[1] || vold==vertex[2]);
804        assert(vnew!=vertex[0] && vnew!=vertex[1] && vnew!=vertex[2]);
805        if(vold==vertex[0]){
806            vertex[0]=vnew;
807        }
808        else if(vold==vertex[1]){
809            vertex[1]=vnew;
810        }
811        else {
812            assert(vold==vertex[2]);
813            vertex[2]=vnew;
814        }
815        int i;
816        vold->commonVertex->face.erase(this);
817        vnew->commonVertex->face.insert(this);
818        for(i=0;i<3;i++) {
819            vold->commonVertex->removeIfNonNeighbor(vertex[i]->commonVertex);
820            vertex[i]->commonVertex->removeIfNonNeighbor(vold->commonVertex);
821        }
822        for(i=0;i<3;i++) {
823            assert(vertex[i]->commonVertex->face.find(this) != vertex[i]->commonVertex->face.end());
824            for(int j=0;j<3;j++) if(i!=j) {
825#if OGRE_DEBUG_MODE
826                                ofdebug << "Adding vertex " << (unsigned int)vertex[j]->commonVertex->index << " to the neighbor list "
827                                        "of vertex " << (unsigned int)vertex[i]->commonVertex->index << std::endl;
828#endif
829                vertex[i]->commonVertex->neighbor.insert(vertex[j]->commonVertex);
830            }
831        }
832        computeNormal();
833    }
834    //---------------------------------------------------------------------
835    ProgressiveMesh::PMVertex::PMVertex() : removed(false)
836    {
837    }
838    //---------------------------------------------------------------------
839    void ProgressiveMesh::PMVertex::setDetails(const Vector3& v, size_t newindex)
840    {
841        position = v;
842        index = newindex;
843    }
844    //---------------------------------------------------------------------
845    void ProgressiveMesh::PMVertex::notifyRemoved(void)
846    {
847        NeighborList::iterator i, iend;
848        iend = neighbor.end();
849        for (i = neighbor.begin(); i != iend; ++i)
850        {
851            // Remove me from neighbor
852            (*i)->neighbor.erase(this);
853        }
854        removed = true;
855                this->collapseTo = NULL;
856        this->collapseCost = NEVER_COLLAPSE_COST;
857    }
858    //---------------------------------------------------------------------
859    bool ProgressiveMesh::PMVertex::isBorder() 
860    {
861        // Look for edges which only have one tri attached, this is a border
862
863        NeighborList::iterator i, iend;
864        iend = neighbor.end();
865        // Loop for each neighbor
866        for(i = neighbor.begin(); i != iend; ++i) 
867        {
868            // Count of tris shared between the edge between this and neighbor
869            ushort count = 0;
870            // Loop over each face, looking for shared ones
871            FaceList::iterator j, jend;
872            jend = face.end();
873            for(j = face.begin(); j != jend; ++j) 
874            {
875                if((*j)->hasCommonVertex(*i))
876                {
877                    // Shared tri
878                    count ++;
879                }
880            }
881            //assert(count>0); // Must be at least one!
882            // This edge has only 1 tri on it, it's a border
883            if(count == 1) 
884                                return true;
885        }
886        return false;
887    } 
888        //---------------------------------------------------------------------
889        bool ProgressiveMesh::PMVertex::isManifoldEdgeWith(ProgressiveMesh::PMVertex* v)
890        {
891                // Check the sides involving both these verts
892                // If there is only 1 this is a manifold edge
893                ushort sidesCount = 0;
894                FaceList::iterator i, iend;
895                iend = face.end();
896                for (i = face.begin(); i != iend; ++i)
897                {
898                        if ((*i)->hasCommonVertex(v))
899                        {
900                                sidesCount++;
901                        }
902                }
903
904                return (sidesCount == 1);
905        }
906        //---------------------------------------------------------------------
907    void ProgressiveMesh::PMVertex::removeIfNonNeighbor(ProgressiveMesh::PMVertex *n) 
908    {
909        // removes n from neighbor list if n isn't a neighbor.
910        NeighborList::iterator i = neighbor.find(n);
911        if (i == neighbor.end())
912            return; // Not in neighbor list anyway
913
914        FaceList::iterator f, fend;
915        fend = face.end();
916        for(f = face.begin(); f != fend; ++f) 
917        {
918            if((*f)->hasCommonVertex(n)) return; // Still a neighbor
919        }
920
921#if OGRE_DEBUG_MODE
922                ofdebug << "Vertex " << (unsigned int)n->index << " is no longer a neighbour of vertex " << (unsigned int)this->index <<
923                        " so has been removed from the latter's neighbor list." << std::endl;
924#endif
925        neighbor.erase(n);
926
927                if (neighbor.empty() && !toBeRemoved)
928                {
929                        // This vertex has been removed through isolation (collapsing around it)
930                        this->notifyRemoved();
931                }
932    }
933    //---------------------------------------------------------------------
934    void ProgressiveMesh::dumpContents(const String& log)
935        {
936                std::ofstream ofdump(log.c_str());
937
938                // Just dump 1st working data for now
939                WorkingDataList::iterator worki = mWorkingData.begin();
940
941                CommonVertexList::iterator vi, vend;
942                vend = worki->mVertList.end();
943                ofdump << "-------== VERTEX LIST ==-----------------" << std::endl;
944                size_t i;
945                for (vi = worki->mVertList.begin(), i = 0; i < mNumCommonVertices; ++vi, ++i)
946                {
947                        ofdump << "Vertex " << (unsigned int)vi->index << " pos: " << vi->position << " removed: " 
948                                << vi->removed << " isborder: " << vi->isBorder() << std::endl;
949                        ofdump << "    Faces:" << std::endl;
950                        PMVertex::FaceList::iterator f, fend;
951                        fend = vi->face.end();
952                        for(f = vi->face.begin(); f != fend; ++f)
953                        {
954                                ofdump << "    Triangle index " << (unsigned int)(*f)->index << std::endl;
955                        }
956                        ofdump << "    Neighbours:" << std::endl;
957                        PMVertex::NeighborList::iterator n, nend;
958                        nend = vi->neighbor.end();
959                        for (n = vi->neighbor.begin(); n != nend; ++n)
960                        {
961                                ofdump << "    Vertex index " << (unsigned int)(*n)->index << std::endl;
962                        }
963
964                }
965
966                TriangleList::iterator ti, tend;
967                tend = worki->mTriList.end();
968                ofdump << "-------== TRIANGLE LIST ==-----------------" << std::endl;
969                for(ti = worki->mTriList.begin(); ti != tend; ++ti)
970                {
971                        ofdump << "Triangle " << (unsigned int)ti->index << " norm: " << ti->normal << " removed: " << ti->removed << std::endl;
972                        ofdump << "    Vertex 0: " << (unsigned int)ti->vertex[0]->realIndex << std::endl;
973                        ofdump << "    Vertex 1: " << (unsigned int)ti->vertex[1]->realIndex << std::endl;
974                        ofdump << "    Vertex 2: " << (unsigned int)ti->vertex[2]->realIndex << std::endl;
975                }
976
977                ofdump << "-------== COLLAPSE COST LIST ==-----------------" << std::endl;
978                for (size_t ci = 0; ci < mNumCommonVertices; ++ci)
979                {
980                        ofdump << "Vertex " << (unsigned int)ci << ": " << mWorstCosts[ci] << std::endl;
981                }
982
983                ofdump.close();
984        }
985
986
987}
Note: See TracBrowser for help on using the repository browser.