Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreSubMesh.cpp @ 3

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

=update

File size: 14.7 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#include "OgreSubMesh.h"
31
32#include "OgreMesh.h"
33#include "OgreException.h"
34#include "OgreMeshManager.h"
35#include "OgreMaterialManager.h"
36#include "OgreStringConverter.h"
37
38namespace Ogre {
39    //-----------------------------------------------------------------------
40    SubMesh::SubMesh()
41        : useSharedVertices(true)
42        , operationType(RenderOperation::OT_TRIANGLE_LIST)
43        , vertexData(0)
44        , mMatInitialised(false)
45        , mBoneAssignmentsOutOfDate(false)
46                , mVertexAnimationType(VAT_NONE)
47    {
48                indexData = new IndexData();
49    }
50    //-----------------------------------------------------------------------
51    SubMesh::~SubMesh()
52    {
53        delete vertexData;
54                delete indexData;
55
56                removeLodLevels();
57    }
58
59    //-----------------------------------------------------------------------
60    void SubMesh::setMaterialName(const String& name)
61    {
62        mMaterialName = name;
63        mMatInitialised = true;
64    }
65    //-----------------------------------------------------------------------
66    const String& SubMesh::getMaterialName() const
67    {
68        return mMaterialName;
69    }
70    //-----------------------------------------------------------------------
71    bool SubMesh::isMatInitialised(void) const
72    {
73        return mMatInitialised;
74
75    }
76    //-----------------------------------------------------------------------
77    void SubMesh::_getRenderOperation(RenderOperation& ro, ushort lodIndex)
78    {
79
80                // SubMeshes always use indexes
81        ro.useIndexes = true;
82                if (lodIndex > 0 && static_cast< size_t >( lodIndex - 1 ) < mLodFaceList.size())
83                {
84                        // lodIndex - 1 because we don't store full detail version in mLodFaceList
85                        ro.indexData = mLodFaceList[lodIndex-1];
86        }
87        else
88        {
89                ro.indexData = indexData;
90        }
91                ro.operationType = operationType;
92                ro.vertexData = useSharedVertices? parent->sharedVertexData : vertexData;
93
94    }
95    //-----------------------------------------------------------------------
96    void SubMesh::addBoneAssignment(const VertexBoneAssignment& vertBoneAssign)
97    {
98        if (useSharedVertices)
99        {
100            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "This SubMesh uses shared geometry,  you "
101                "must assign bones to the Mesh, not the SubMesh", "SubMesh.addBoneAssignment");
102        }
103        mBoneAssignments.insert(
104            VertexBoneAssignmentList::value_type(vertBoneAssign.vertexIndex, vertBoneAssign));
105        mBoneAssignmentsOutOfDate = true;
106    }
107    //-----------------------------------------------------------------------
108    void SubMesh::clearBoneAssignments(void)
109    {
110        mBoneAssignments.clear();
111        mBoneAssignmentsOutOfDate = true;
112    }
113
114    //-----------------------------------------------------------------------
115    void SubMesh::_compileBoneAssignments(void)
116    {
117        unsigned short maxBones =
118            parent->_rationaliseBoneAssignments(vertexData->vertexCount, mBoneAssignments);
119
120        if (maxBones != 0)
121        {
122            parent->compileBoneAssignments(mBoneAssignments, maxBones, 
123                blendIndexToBoneIndexMap, vertexData);
124        }
125
126        mBoneAssignmentsOutOfDate = false;
127    }
128    //---------------------------------------------------------------------
129    SubMesh::BoneAssignmentIterator SubMesh::getBoneAssignmentIterator(void)
130    {
131        return BoneAssignmentIterator(mBoneAssignments.begin(),
132            mBoneAssignments.end());
133    }
134    //---------------------------------------------------------------------
135    SubMesh::AliasTextureIterator SubMesh::getAliasTextureIterator(void) const
136    {
137        return AliasTextureIterator(mTextureAliases.begin(),
138            mTextureAliases.end());
139    }
140    //---------------------------------------------------------------------
141    void SubMesh::addTextureAlias(const String& aliasName, const String& textureName)
142    {
143        mTextureAliases[aliasName] = textureName;
144    }
145    //---------------------------------------------------------------------
146    void SubMesh::removeTextureAlias(const String& aliasName)
147    {
148        mTextureAliases.erase(aliasName);
149    }
150    //---------------------------------------------------------------------
151    void SubMesh::removeAllTextureAliases(void)
152    {
153        mTextureAliases.clear();
154    }
155    //---------------------------------------------------------------------
156    bool SubMesh::updateMaterialUsingTextureAliases(void)
157    {
158        bool newMaterialCreated = false;
159        // if submesh has texture aliases
160        // ask the material manager if the current summesh material exists
161        if (hasTextureAliases() && MaterialManager::getSingleton().resourceExists(mMaterialName))
162        {
163            // get the current submesh material
164            MaterialPtr material = MaterialManager::getSingleton().getByName( mMaterialName );
165            // get test result for if change will occur when the texture aliases are applied
166            if (material->applyTextureAliases(mTextureAliases, false))
167            {
168                // material textures will be changed so copy material,
169                // new material name is old material name + index
170                // check with material manager and find a unique name
171                size_t index = 0;
172                String newMaterialName = mMaterialName + "_" + StringConverter::toString(index);
173                while (MaterialManager::getSingleton().resourceExists(newMaterialName))
174                {
175                    // increment index for next name
176                    newMaterialName = mMaterialName + "_" + StringConverter::toString(++index);
177                }
178
179                Ogre::MaterialPtr newMaterial = Ogre::MaterialManager::getSingleton().create(
180                    newMaterialName, material->getGroup());
181                // copy parent material details to new material
182                material->copyDetailsTo(newMaterial);
183                // apply texture aliases to new material
184                newMaterial->applyTextureAliases(mTextureAliases);
185                // place new material name in submesh
186                setMaterialName(newMaterialName);
187                newMaterialCreated = true;
188            }
189        }
190
191        return newMaterialCreated;
192    }
193    //---------------------------------------------------------------------
194    void SubMesh::removeLodLevels(void)
195    {
196        ProgressiveMesh::LODFaceList::iterator lodi, lodend;
197                lodend = mLodFaceList.end();
198                for (lodi = mLodFaceList.begin(); lodi != lodend; ++lodi)
199                {
200                        delete *lodi;
201                }
202
203        mLodFaceList.clear();
204
205    }
206        //---------------------------------------------------------------------
207        VertexAnimationType SubMesh::getVertexAnimationType(void) const
208        {
209                if(parent->_getAnimationTypesDirty())
210                {
211                        parent->_determineAnimationTypes();
212                }
213                return mVertexAnimationType;
214        }
215        //---------------------------------------------------------------------
216    /* To find as many points from different domains as we need,
217     * such that those domains are from different parts of the mesh,
218     * we implement a simplified Heckbert quantization algorithm.
219     *
220     * This struct is like AxisAlignedBox with some specialized methods
221     * for doing quantization.
222     */
223    struct Cluster
224    {
225        Vector3 mMin, mMax;
226        std::set<uint32> mIndices;
227
228        Cluster ()
229        { }
230
231        bool empty () const
232        {
233            if (mIndices.empty ())
234                return true;
235            if (mMin == mMax)
236                return true;
237            return false;
238        }
239
240        float volume () const
241        {
242            return (mMax.x - mMin.x) * (mMax.y - mMin.y) * (mMax.z - mMin.z);
243        }
244
245        void extend (float *v)
246        {
247            if (v [0] < mMin.x) mMin.x = v [0];
248            if (v [1] < mMin.y) mMin.y = v [1];
249            if (v [2] < mMin.z) mMin.z = v [2];
250            if (v [0] > mMax.x) mMax.x = v [0];
251            if (v [1] > mMax.y) mMax.y = v [1];
252            if (v [2] > mMax.z) mMax.z = v [2];
253        }
254
255        void computeBBox (const VertexElement *poselem, uint8 *vdata, size_t vsz)
256        {
257            mMin.x = mMin.y = mMin.z = Math::POS_INFINITY;
258            mMax.x = mMax.y = mMax.z = Math::NEG_INFINITY;
259
260            for (std::set<uint32>::const_iterator i = mIndices.begin ();
261                 i != mIndices.end (); ++i)
262            {
263                float *v;
264                poselem->baseVertexPointerToElement (vdata + *i * vsz, &v);
265                extend (v);
266            }
267        }
268
269        Cluster split (int split_axis, const VertexElement *poselem,
270                       uint8 *vdata, size_t vsz)
271        {
272            Real r = (mMin [split_axis] + mMax [split_axis]) * 0.5;
273            Cluster newbox;
274
275            // Separate all points that are inside the new bbox
276            for (std::set<uint32>::iterator i = mIndices.begin ();
277                 i != mIndices.end (); )
278            {
279                float *v;
280                poselem->baseVertexPointerToElement (vdata + *i * vsz, &v);
281                if (v [split_axis] > r)
282                {
283                    newbox.mIndices.insert (*i);
284                    std::set<uint32>::iterator x = i++;
285                    mIndices.erase(x);
286                }
287                else
288                    ++i;
289            }
290
291            computeBBox (poselem, vdata, vsz);
292            newbox.computeBBox (poselem, vdata, vsz);
293
294            return newbox;
295        }
296    };
297    //---------------------------------------------------------------------
298    void SubMesh::generateExtremes(size_t count)
299    {
300        extremityPoints.clear();
301
302        /* Currently this uses just one criteria: the points must be
303         * as far as possible from each other. This at least ensures
304         * that the extreme points characterise the submesh as
305         * detailed as it's possible.
306         */
307
308        uint elsz = indexData->indexBuffer->getType () == HardwareIndexBuffer::IT_32BIT ?
309            4 : 2;
310        uint8 *idata = (uint8 *)indexData->indexBuffer->lock (
311            indexData->indexStart * elsz, indexData->indexCount * elsz,
312            HardwareIndexBuffer::HBL_READ_ONLY);
313
314        VertexData *vert = useSharedVertices ?
315            parent->sharedVertexData : vertexData;
316        const VertexElement *poselem = vert->vertexDeclaration->
317            findElementBySemantic (VES_POSITION);
318        HardwareVertexBufferSharedPtr vbuf = vert->vertexBufferBinding->
319            getBuffer (poselem->getSource ());
320        uint8 *vdata = (uint8 *)vbuf->lock (HardwareBuffer::HBL_READ_ONLY);
321        size_t vsz = vbuf->getVertexSize ();
322
323        std::vector<Cluster> boxes;
324        boxes.reserve (count);
325
326        // First of all, find min and max bounding box of the submesh
327        boxes.push_back (Cluster ());
328        for (size_t i = 0; i < indexData->indexCount; i++)
329        {
330            int idx = (elsz == 2) ? ((uint16 *)idata) [i] : ((uint32 *)idata) [i];
331            boxes [0].mIndices.insert (idx);
332        }
333
334        boxes [0].computeBBox (poselem, vdata, vsz);
335
336        // Remember the geometrical center of the submesh
337        Vector3 center = (boxes [0].mMax + boxes [0].mMin) * 0.5;
338
339        // Ok, now loop until we have as many boxes, as we need extremes
340        while (boxes.size () < count)
341        {
342            // Find the largest box with more than one vertex :)
343            Cluster *split_box = NULL;
344            Real split_volume = -1;
345            for (std::vector<Cluster>::iterator b = boxes.begin ();
346                 b != boxes.end (); ++b)
347            {
348                if (b->empty ())
349                    continue;
350                Real v = b->volume ();
351                if (v > split_volume)
352                {
353                    split_volume = v;
354                    split_box = &*b;
355                }
356            }
357
358            // If we don't have what to split, break
359            if (!split_box)
360                break;
361
362            // Find the coordinate axis to split the box into two
363            int split_axis = 0;
364            Real split_length = split_box->mMax.x - split_box->mMin.x;
365            for (int i = 1; i < 3; i++)
366            {
367                Real l = split_box->mMax [i] - split_box->mMin [i];
368                if (l > split_length)
369                {
370                    split_length = l;
371                    split_axis = i;
372                }
373            }
374
375            // Now split the box into halves
376            boxes.push_back (split_box->split (split_axis, poselem, vdata, vsz));
377        }
378
379        // Fine, now from every cluster choose the vertex that is most
380        // distant from the geometrical center and from other extremes.
381        for (std::vector<Cluster>::const_iterator b = boxes.begin ();
382             b != boxes.end (); ++b)
383        {
384            Real rating = 0;
385            Vector3 best_vertex;
386
387            for (std::set<uint32>::const_iterator i = b->mIndices.begin ();
388                 i != b->mIndices.end (); ++i)
389            {
390                float *v;
391                poselem->baseVertexPointerToElement (vdata + *i * vsz, &v);
392
393                Vector3 vv (v [0], v [1], v [2]);
394                Real r = (vv - center).squaredLength ();
395
396                for (std::vector<Vector3>::const_iterator e = extremityPoints.begin ();
397                     e != extremityPoints.end (); ++e)
398                    r += (*e - vv).squaredLength ();
399                if (r > rating)
400                {
401                    rating = r;
402                    best_vertex = vv;
403                }
404            }
405
406            if (rating > 0)
407                extremityPoints.push_back (best_vertex);
408        }
409
410        vbuf->unlock ();
411        indexData->indexBuffer->unlock ();
412    }
413}
414
Note: See TracBrowser for help on using the repository browser.