source: OGRE/trunk/ogrenew/Tools/XSIExport/src/OgreXSIMeshExporter.cpp @ 657

Revision 657, 39.2 KB checked in by mattausch, 19 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 "OgreXSIMeshExporter.h"
26#include <xsi_model.h>
27#include <xsi_primitive.h>
28#include <xsi_polygonnode.h>
29#include <xsi_material.h>
30#include <xsi_vertex.h>
31#include <xsi_trianglevertex.h>
32#include <xsi_cluster.h>
33#include <xsi_kinematics.h>
34#include <xsi_kinematicstate.h>
35#include <xsi_selection.h>
36#include <xsi_envelope.h>
37#include <xsi_time.h>
38#include <xsi_source.h>
39
40#include "OgreException.h"
41#include "OgreXSIHelper.h"
42#include "OgreLogManager.h"
43#include "OgreMeshManager.h"
44#include "OgreMesh.h"
45#include "OgreSubMesh.h"
46#include "OgreMeshManager.h"
47#include "OgreMeshSerializer.h"
48#include "OgreHardwareBufferManager.h"
49#include "OgreVertexBoneAssignment.h"
50
51using namespace XSI;
52
53
54namespace Ogre {
55    //-----------------------------------------------------------------------
56    XsiMeshExporter::UniqueVertex::UniqueVertex()
57        : position(Vector3::ZERO), normal(Vector3::ZERO), colour(0), nextIndex(0)
58    {
59        for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS; ++i)
60            uv[i] = Vector3::ZERO;
61    }
62    //-----------------------------------------------------------------------
63    bool XsiMeshExporter::UniqueVertex::operator==(const UniqueVertex& rhs) const
64    {
65        bool ret = position == rhs.position &&
66            normal == rhs.normal &&
67            colour == rhs.colour;
68        if (!ret) return ret;
69
70        for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS && ret; ++i)
71        {
72            ret = ret && (uv[i] == rhs.uv[i]);
73        }
74
75        return ret;
76       
77
78    }
79    //-----------------------------------------------------------------------
80    //-----------------------------------------------------------------------
81    XsiMeshExporter::XsiMeshExporter()
82    {
83    }
84    //-----------------------------------------------------------------------
85    XsiMeshExporter::~XsiMeshExporter()
86    {
87                /// Tidy up
88                cleanupDeformerMap();
89                cleanupMaterialMap();
90    }
91    //-----------------------------------------------------------------------
92        DeformerMap& XsiMeshExporter::exportMesh(const String& fileName,
93                bool mergeSubMeshes, bool exportChildren,
94                bool edgeLists, bool tangents, const String& materialPrefix,
95                LodData* lod, const String& skeletonName)
96    {
97
98                LogOgreAndXSI(L"** Begin OGRE Mesh Export **");
99        // Derive the scene root
100        X3DObject sceneRoot(mXsiApp.GetActiveSceneRoot());
101
102        // Construct mesh
103        MeshPtr pMesh = MeshManager::getSingleton().createManual("XSIExport",
104                        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
105
106                mMaterialPrefix = materialPrefix;
107
108                cleanupDeformerMap();
109                cleanupMaterialMap();
110
111                // Find all PolygonMesh objects
112                buildPolygonMeshList(exportChildren);
113                // progress report
114                ProgressManager::getSingleton().progress();
115
116                // notify of skeleton beforehand
117                if (!skeletonName.empty())
118                {
119                        pMesh->setSkeletonName(skeletonName);
120                }
121
122                // write the data into a mesh
123                buildMesh(pMesh.getPointer(), mergeSubMeshes, !skeletonName.empty());
124
125                // progress report
126                ProgressManager::getSingleton().progress();
127
128                if (lod)
129                {
130                        pMesh->generateLodLevels(lod->distances, lod->quota, lod->reductionValue);
131                        // progress report
132                        ProgressManager::getSingleton().progress();
133                }
134
135        if(edgeLists)
136        {
137            LogOgreAndXSI(L"Calculating edge lists");
138            pMesh->buildEdgeList();
139                        // progress report
140                        ProgressManager::getSingleton().progress();
141        }
142
143        if(tangents)
144        {
145            LogOgreAndXSI(L"Calculating tangents");
146            unsigned short src, dest;
147            if (pMesh->suggestTangentVectorBuildParams(src, dest))
148            {
149                pMesh->buildTangentVectors(src, dest);
150            }
151            else
152            {
153                LogOgreAndXSI(L"Could not derive tangents parameters");
154            }
155                        // progress report
156                        ProgressManager::getSingleton().progress();
157
158        }
159
160        MeshSerializer serializer;
161        serializer.exportMesh(pMesh.getPointer(), fileName);
162
163                // progress report
164                ProgressManager::getSingleton().progress();
165
166                cleanupPolygonMeshList();
167
168                LogOgreAndXSI(L"** OGRE Mesh Export Complete **");
169
170                return mXsiDeformerMap;
171    }
172        //-----------------------------------------------------------------------
173        MaterialMap& XsiMeshExporter::getMaterials(void)
174        {
175                return mXsiMaterialMap;
176        }
177        //-----------------------------------------------------------------------
178        TextureProjectionMap& XsiMeshExporter::getTextureProjectionMap(void)
179        {
180                return mTextureProjectionMap;
181        }
182        //-----------------------------------------------------------------------
183        void XsiMeshExporter::buildMesh(Mesh* pMesh, bool mergeSubmeshes, bool lookForBoneAssignments)
184        {
185                /* Iterate over the list of polygon meshes that we've already located.
186                        For each one:
187                                If we're not merging submeshes, bake any protosubmeshes built
188                                  into the mesh and clear the protosubmesh list
189                            Scan the clusters for 'poly' clusters (which can contain material
190                                  discrepancies). Any that use a different material should be
191                                  noted in the polycluster list
192                            Build ProtoSubMeshes by iterating over the triangles in the mesh,
193                                  building the list of UniqueVertices against the material as we
194                                  go. We check each triangle to see if the polygon index is in
195                                  the list of polyclusters & if so it goes into the other lists
196                   
197                        Finally, we bake any remaining protosubmeshes into submeshes.
198                */
199                // Calculate the number of progress updates each mesh must raise
200                float progPerMesh = (float)OGRE_XSI_NUM_MESH_STEPS / (float)(mXsiPolygonMeshList.size());
201                float currProg = 0.0f;
202                for (PolygonMeshList::iterator pm = mXsiPolygonMeshList.begin();
203                        pm != mXsiPolygonMeshList.end(); ++pm)
204                {
205                        currProg += progPerMesh;
206                        unsigned short progUpdates = (unsigned short)currProg;
207                        currProg -= progUpdates;
208                        // build contents of this polymesh into ProtoSubMesh(es)
209                        processPolygonMesh(pMesh, *pm, lookForBoneAssignments, progUpdates);
210
211                        if (!mergeSubmeshes)
212                        {
213                                // export out at the end of every PolygonMesh
214                                exportProtoSubMeshes(pMesh);
215                        }
216                }
217                if (mergeSubmeshes)
218                {
219                        // export out the combined result
220                        exportProtoSubMeshes(pMesh);
221                }
222        }
223        //-----------------------------------------------------------------------
224        XsiMeshExporter::ProtoSubMesh* XsiMeshExporter::createOrRetrieveProtoSubMesh(
225                const String& materialName, const String& name,
226                TextureCoordDimensionList& texCoordDims, bool hasVertexColours)
227        {
228                bool createNew = false;
229                ProtoSubMesh* ret = 0;
230               
231                ProtoSubMeshList::iterator pi = mProtoSubmeshList.find(materialName);
232                if (pi == mProtoSubmeshList.end())
233                {
234                        createNew = true;
235                }
236                else
237                {
238                        // Check format is compatible
239                        bool compat = true;
240                        if (pi->second->textureCoordDimensions.size() != texCoordDims.size())
241                        {
242                                compat = false;
243                        }
244                        if (pi->second->hasVertexColours != hasVertexColours)
245                        {
246                                compat = false;
247                        }
248                        std::vector<ushort>::iterator t = texCoordDims.begin();
249                        std::vector<ushort>::iterator u = pi->second->textureCoordDimensions.begin();
250                        for (;t != texCoordDims.end(); ++t,++u)
251                        {
252                                if (*t != *u)
253                                {
254                                        compat = false;
255                                        break;
256                                }
257                        }
258                       
259                        if (compat)
260                        {
261                                ret = pi->second;
262                        }
263                        else
264                        {
265                                // Can't merge these - create new
266                                createNew = true;
267                        }
268                }
269
270                if (createNew)
271                {
272                        ret = new ProtoSubMesh();
273                        mProtoSubmeshList[materialName] = ret;
274                        ret->materialName = materialName;
275                        ret->name = name;
276                        ret->textureCoordDimensions = texCoordDims;
277                        ret->hasVertexColours = hasVertexColours;
278                }
279
280                return ret;
281               
282        }
283        //-----------------------------------------------------------------------
284        void XsiMeshExporter::processPolygonMesh(Mesh* pMesh, PolygonMeshEntry* xsiMesh,
285                bool lookForBoneAssignments, unsigned short progressUpdates)
286        {
287                // Pre-process the mesh
288                if (!preprocessPolygonMesh(xsiMesh))
289                {
290                        while(progressUpdates--)
291                                ProgressManager::getSingleton().progress();
292
293                        return;
294                }
295               
296        // Retrieve all the XSI relevant summary info
297        CPointRefArray pointArray(xsiMesh->mesh.GetPoints());
298        MATH::CVector3Array srcPosArray = pointArray.GetPositionArray();
299        CPolygonNodeRefArray nodeArray(xsiMesh->mesh.GetNodes());
300        MATH::CVector3Array srcNormArray = nodeArray.GetNormalArray();
301        CTriangleRefArray triArray = xsiMesh->mesh.GetTriangles();
302
303                StringUtil::StrStreamType msg;
304                msg << "-- " << XSItoOgre(xsiMesh->obj.GetName()) << " --" << std::endl;
305                msg << "Points: " << pointArray.GetCount() << std::endl;
306                msg << "Triangles: " << triArray.GetCount() << std::endl;
307                msg << "Normals: " << srcNormArray.GetCount() << std::endl;
308                msg << "Num UVs: " << mCurrentTextureCoordDimensions.size() << std::endl;
309                String str = msg.str();
310                LogOgreAndXSI(str);
311
312                if (mCurrentTextureCoordDimensions.size() > OGRE_MAX_TEXTURE_COORD_SETS)
313                {
314                        // too many texture coordinates!
315                        StringUtil::StrStreamType str;
316                        str << "PolygonMesh '" << XSItoOgre(xsiMesh->mesh.GetName())
317                                << "' has too many texture coordinate sets ("
318                                << mCurrentTextureCoordDimensions.size()
319                                << "); the limit is " << OGRE_MAX_TEXTURE_COORD_SETS;
320
321                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, str.str(),
322                                "XsiMeshExporter::processPolygonMesh");
323
324                }
325               
326                // Save transforms
327                MATH::CTransformation xsiTransform = xsiMesh->obj.GetKinematics().GetGlobal().GetTransform();
328                MATH::CTransformation rotTrans;
329                rotTrans.SetRotation(xsiTransform.GetRotation());
330                // Bounds calculation
331        Real squaredRadius = 0.0f;
332        Vector3 min, max;
333        bool first = true;
334                CPolygonFaceRefArray polys(xsiMesh->mesh.GetPolygons());
335        UniqueVertex vertex;
336
337
338                float progPerTri = (float)progressUpdates / triArray.GetCount();
339                float prog = 0.0f;
340                // Iterate through all the triangles
341        // There will often be less positions than normals and UVs
342        // But TrianglePoint
343        for (long t = 0; t < triArray.GetCount(); ++t)
344        {
345            Triangle tri(triArray[t]);
346                        // derive sampler indices for triangle
347                        size_t samplerIndices[3];
348                        deriveSamplerIndices(tri, polys[tri.GetPolygonIndex()], samplerIndices);
349
350                        // Decide which ProtoSubMesh we're to add this to (assume main)
351                        // If we find this triangle relates to a polygon which is in
352                        // a cluster which has a different material, we change
353                        ProtoSubMesh* currentProto = mMainProtoMesh;
354                        PolygonToProtoSubMeshList::iterator polyi =
355                                mPolygonToProtoSubMeshList.find(tri.GetPolygonIndex());
356                        if (polyi != mPolygonToProtoSubMeshList.end())
357                        {
358                                currentProto = polyi->second;
359                        }
360                        // has this mesh been used in this proto before? if not set offset
361                        size_t positionIndexOffset;
362                        if (currentProto->lastMeshEntry == xsiMesh)
363                        {
364                                positionIndexOffset = currentProto->lastMeshIndexOffset;
365                        }
366                        else
367                        {
368                                // first time this has been used
369                                // since we assume we 100% process each polygon mesh before the next,
370                                // just use last pointer since faster in this section
371                                currentProto->lastMeshEntry = xsiMesh;
372                                positionIndexOffset = currentProto->indices.size();
373                                currentProto->lastMeshIndexOffset = positionIndexOffset;
374                                // Also have to store this for future reference
375                                currentProto->polygonMeshOffsetMap[xsiMesh] = positionIndexOffset;
376                        }
377                       
378            CTriangleVertexRefArray points = tri.GetPoints();
379            for (long p = 0; p < 3; ++p)
380            {
381                TriangleVertex point(points[p]);
382                long posIndex = point.GetIndex(); // unique position index
383                                // adjust index per offset, this makes position indices unique
384                                // per polymesh in teh same protosubmesh
385                                posIndex += positionIndexOffset;
386
387                                // Get position
388                                MATH::CVector3 xsipos = point.GetPosition();
389                                // Apply global SRT
390                                xsipos.MulByTransformationInPlace(xsiTransform);
391                vertex.position = XSItoOgre(xsipos);
392                                // Get normal
393                                MATH::CVector3 xsinorm = point.GetNormal();
394                                // Apply global rotation
395                                xsinorm *= rotTrans;
396                vertex.normal = XSItoOgre(xsinorm);
397
398                                for (size_t i = 0; i < mCurrentTextureCoordDimensions.size(); ++i)
399                                {
400                                        // sampler indices can correctly dereference to sampler-order
401                                        // uv sets we built earlier
402                                        vertex.uv[i] = (mCurrentSamplerSets[i])[samplerIndices[p]];
403                                }
404               
405                if (mCurrentHasVertexColours)
406                    vertex.colour = XSItoOgre(point.GetColor());
407
408                size_t index = createOrRetrieveUniqueVertex(
409                                                                        currentProto, posIndex, true, vertex);
410                currentProto->indices.push_back(index);
411
412                                // bounds
413                                if (first)
414                                {
415                                        squaredRadius = vertex.position.squaredLength();
416                                        min = max = vertex.position;
417                                        first = false;
418                                }
419                                else
420                                {
421                                        squaredRadius =
422                                                std::max(squaredRadius, vertex.position.squaredLength());
423                                        min.makeFloor(vertex.position);
424                                        max.makeCeil(vertex.position);
425                                }
426            }
427               
428                        // Progress
429                        prog += progPerTri;
430                        while (prog >= 1.0f)
431                        {
432                                ProgressManager::getSingleton().progress();
433                                prog -= 1.0f;
434                        }
435
436                }
437
438                // Merge bounds
439                AxisAlignedBox box;
440        box.setExtents(min, max);
441        box.merge(pMesh->getBounds());
442        pMesh->_setBounds(box);
443        pMesh->_setBoundingSphereRadius(
444                        std::max(
445                                pMesh->getBoundingSphereRadius(),
446                                Math::Sqrt(squaredRadius)));
447
448                // Deal with any bone assignments
449                if (lookForBoneAssignments)
450                {
451                        processBoneAssignments(pMesh, xsiMesh);
452                }
453
454
455                // Post-process the mesh
456                postprocessPolygonMesh(xsiMesh);
457
458        }
459        //-----------------------------------------------------------------------
460        bool XsiMeshExporter::preprocessPolygonMesh(PolygonMeshEntry* xsiMesh)
461        {
462        // derive number of UVs
463        int numUVs = 0;
464        CRefArray clusterRefArray;
465        // Filter to 'sample' types
466        xsiMesh->mesh.GetClusters().Filter(
467                        siSampledPointCluster,CStringArray(),L"",clusterRefArray);
468
469        Cluster samplePointClusterUV;
470        CRefArray uvClusterPropertiesRefArray;
471                int i;
472       
473        for(i = 0; i < clusterRefArray.GetCount(); ++i)
474        {
475            Cluster cluster(clusterRefArray[i]);               
476            // Now filter all the 'uvspace' children
477            // there is one of these per UV set
478            if(cluster.GetProperties().Filter(
479                siClsUVSpaceTxtType, CStringArray(), L"",
480                uvClusterPropertiesRefArray) == CStatus::OK)
481            {
482                samplePointClusterUV = cluster;                 
483                break;
484            }
485        }
486
487        // Ok, we now have our array of UV sets
488        numUVs = uvClusterPropertiesRefArray.GetCount();
489                size_t numSamplerPoints = xsiMesh->mesh.GetNodes().GetCount();
490                // list of UVs stored in order of sampler points (use 3D coords by default)
491                mCurrentSamplerSets.reserve(numUVs);
492                mCurrentTextureCoordDimensions.reserve(numUVs);
493        for(i = 0; i < numUVs; ++i)
494        {
495                        // init sampler points
496                        Vector3* samplerUVs = new Vector3[numSamplerPoints];
497                        mCurrentSamplerSets.push_back(samplerUVs);
498
499                        // Detect the dimensions by figuring out if any are all 0
500                        bool hasU, hasV, hasW;
501                        hasU = hasV = hasW = false;
502
503                        // Pull out all the UV data for this set and reorder it based on
504                        // samples, we'll need this for reference later
505                        // get Elements from uvspace Property
506            ClusterProperty uvProp(uvClusterPropertiesRefArray[i]);
507                        CClusterPropertyElementArray uvElements = uvProp.GetElements();
508
509                        // Add this to an map from uv set name to index
510                        String textureProjectionName = XSItoOgre(uvProp.GetName());
511                        mTextureProjectionMap[textureProjectionName] = i;
512
513                        // Now, each Element here is actually a CDoubleArray of the u,v,w values
514                        // However it's not in order of samplers, we need to use the Array
515                        // linked to from the Elements collection under the cluster (not the
516                        // cluster property, confusing I know) to figure out what sampler
517                        // index it is, i.e.
518                        // samplerUVs[Array[j]] = Element[j]
519                        // In all casesmCurrentSamplerSets in XSI element properties are referenced back to
520                        // their original poly index via this array, ie all cluster properties
521                        // in the same cluster are dereferenced in the same way.
522                        CLongArray derefArray = samplePointClusterUV.GetElements().GetArray();
523
524                        for (int j = 0; j < uvElements.GetCount(); ++j)
525                        {
526                                CDoubleArray curUVW(uvElements.GetItem(j));
527                                size_t samplerIndex = derefArray[j];
528                                samplerUVs[samplerIndex].x = curUVW[0];//u
529                                samplerUVs[samplerIndex].y = 1.0f - curUVW[1];//v (invert)
530                                samplerUVs[samplerIndex].z = curUVW[2];//w
531
532                                if (!hasU && curUVW[0] > 0)
533                                        hasU = true;
534                                if (!hasV && curUVW[1] > 0)
535                                        hasV = true;
536                                if (!hasW && curUVW[2] > 0)
537                                        hasW = true;
538
539                        }
540                       
541                        // save dimensions
542                        mCurrentTextureCoordDimensions.push_back(
543                                (hasU?1:0) + (hasV?1:0) + (hasW?1:0));
544
545        }
546
547
548        // do we have vertex colours?
549        ClusterProperty vertexColourClusterProperty = xsiMesh->mesh.GetCurrentVertexColor();
550        if (vertexColourClusterProperty.IsValid())
551            mCurrentHasVertexColours = true;
552                else
553                        mCurrentHasVertexColours = false;
554
555               
556                /* Create any ProtoSubMeshes which don't exist yet for the
557                 * materials in question, and define the PolygonCluster map
558                 */
559                // Main material (will never exist if not merging submeshes)
560                String materialName = mMaterialPrefix +
561                        XSItoOgre(xsiMesh->obj.GetMaterial().GetName());
562                registerMaterial(materialName, xsiMesh->obj.GetMaterial());
563               
564                mMainProtoMesh = createOrRetrieveProtoSubMesh(
565                        materialName,
566                        XSItoOgre(xsiMesh->obj.GetName()),
567                        mCurrentTextureCoordDimensions,
568                        mCurrentHasVertexColours);
569               
570                // For each polygon cluster
571        CRefArray polygonClusters;
572        // Filter to 'poly' types
573        xsiMesh->mesh.GetClusters().Filter(siPolygonCluster, CStringArray(), L"",
574                        polygonClusters);
575                mPolygonToProtoSubMeshList.clear();
576        for(i = 0; i < polygonClusters.GetCount(); ++i)
577        {
578                        Cluster cluster(polygonClusters[i]);   
579                        // Is the material different for this poly cluster?
580                        if (cluster.GetMaterial() != xsiMesh->obj.GetMaterial())
581                        {
582                                String submatName = mMaterialPrefix +
583                                        XSItoOgre(cluster.GetMaterial().GetName());
584                                registerMaterial(submatName, cluster.GetMaterial());
585                                ProtoSubMesh* ps = createOrRetrieveProtoSubMesh(
586                                        submatName,
587                                        XSItoOgre(cluster.GetName()),
588                                        mCurrentTextureCoordDimensions,
589                                        mCurrentHasVertexColours);
590                                // Each element is a polygon index
591                                CLongArray elems = cluster.GetElements().GetArray();
592                                for (int p = 0; p < elems.GetCount(); ++p)
593                                {
594                                        mPolygonToProtoSubMeshList[elems[p]] = ps;
595                                }
596                        }
597                }
598
599                return true;
600
601
602        }
603        //-----------------------------------------------------------------------
604        void XsiMeshExporter::postprocessPolygonMesh(PolygonMeshEntry* xsiMesh)
605        {
606                // clear all position index remaps, incase merged
607                for (ProtoSubMeshList::iterator p = mProtoSubmeshList.begin();
608                        p != mProtoSubmeshList.end(); ++p)
609                {
610                        ProtoSubMesh* ps = p->second;
611                        ps->posIndexRemap.clear();
612                }
613
614                // free temp UV data now
615                for(SamplerSetList::iterator s = mCurrentSamplerSets.begin();
616                        s != mCurrentSamplerSets.end(); ++s)
617                {
618                        // init sampler points
619                        delete [] *s;
620                }
621                mCurrentSamplerSets.clear();
622                mCurrentTextureCoordDimensions.clear();
623               
624        }
625        //-----------------------------------------------------------------------
626        void XsiMeshExporter::processBoneAssignments(Mesh* pMesh, PolygonMeshEntry* xsiMesh)
627        {
628                // We have to iterate over the clusters which have envelope assignments
629                // then, for each protosubmesh which uses this polymesh, we need to create
630                // a bone assignment for each deformer, not forgetting to add one for
631                // each duplicated copy of this vertex too
632                // We build up a global list of deformers as we go which will get passed
633                // back to the top-level caller to build a skeleton from later
634                CRefArray clusterRefArray;
635                // Filter to 'vertex' types
636                xsiMesh->mesh.GetClusters().Filter(
637                        siVertexCluster,CStringArray(),L"",clusterRefArray);
638
639
640
641                for(int i = 0; i < clusterRefArray.GetCount(); ++i)
642                {
643                        Cluster cluster(clusterRefArray[i]);   
644
645                        CRefArray envelopes = cluster.GetEnvelopes();
646                        for (int e = 0; e < envelopes.GetCount(); ++e)
647                        {
648                                Envelope envelope(envelopes[e]);
649
650                                // Get mapping from cluster element index to geometry position index
651                                CLongArray derefArray = envelope.GetElements(CTime().GetTime()).GetArray();
652
653                                CRefArray deformers = envelope.GetDeformers();
654                                for (int d = 0; d < deformers.GetCount(); ++d)
655                                {
656                                        X3DObject deformer(deformers[d]);
657                                        // Has this deformer been allocated a boneID already?
658                                        String deformerName = XSItoOgre(deformer.GetName());
659                                        DeformerMap::iterator di =
660                                                mXsiDeformerMap.find(deformerName);
661                                        DeformerEntry* deformerEntry;
662                                        bool newDeformerEntry = false;
663                                        bool atLeastOneAssignment = false;
664                                        if (di == mXsiDeformerMap.end())
665                                        {
666                                                deformerEntry = new DeformerEntry(mXsiDeformerMap.size(), deformer);
667                                                deformerEntry->hasVertexAssignments = true;
668                                                newDeformerEntry = true;
669                                        }
670                                        else
671                                        {
672                                                deformerEntry = di->second;
673                                        }
674
675                                        // Get the weights for this deformer
676                                        CDoubleArray weights =
677                                                envelope.GetDeformerWeights(deformer, CTime().GetTime());
678                                        // Weights are in order of cluster elements, we need to dereference
679                                        // those to the original point index using the cluster element array
680                                        for (int w = 0; w < weights.GetCount(); ++w)
681                                        {
682                                                size_t positionIndex = derefArray[w];
683                                                float weight = weights[w];
684                                                // Skip zero weights
685                                                if (weight == 0.0f)
686                                                        continue;
687
688                                                // Locate ProtoSubMeshes which use this mesh
689                                                for (ProtoSubMeshList::iterator psi = mProtoSubmeshList.begin();
690                                                        psi != mProtoSubmeshList.end(); ++psi)
691                                                {
692                                                        ProtoSubMesh* ps = psi->second;
693                                                        ProtoSubMesh::PolygonMeshOffsetMap::iterator poli =
694                                                                ps->polygonMeshOffsetMap.find(xsiMesh);
695                                                        if (poli != ps->polygonMeshOffsetMap.end())
696                                                        {
697                                                                // adjust index based on merging
698                                                                size_t adjIndex = positionIndex + poli->second;
699                                                                // look up real index
700                                                                // If it doesn't exist, it's probably on a seam
701                                                                // between clusters and we can safely skip it
702                                                                IndexRemap::iterator remi = ps->posIndexRemap.find(adjIndex);
703                                                                if (remi != ps->posIndexRemap.end())
704                                                                {
705
706                                                                        size_t vertIndex = remi->second;
707                                                                        bool moreVerts = true;
708                                                                        // add UniqueVertex and clones
709                                                                        while (moreVerts)
710                                                                        {
711                                                                                UniqueVertex& vertex = ps->uniqueVertices[vertIndex];
712                                                                                VertexBoneAssignment vba;
713                                                                                vba.boneIndex = deformerEntry->boneID;
714                                                                                vba.vertexIndex = vertIndex;
715                                                                                vba.weight = weight;
716                                                                                ps->boneAssignments.insert(
717                                                                                        Mesh::VertexBoneAssignmentList::value_type(vertIndex, vba));
718                                                                                atLeastOneAssignment = true;
719
720                                                                                if (vertex.nextIndex == 0)
721                                                                                {
722                                                                                        moreVerts = false;
723                                                                                }
724                                                                                else
725                                                                                {
726                                                                                        vertIndex = vertex.nextIndex;
727                                                                                }
728                                                                        }
729                                                                }
730
731                                                        }
732                                                }
733
734
735
736                                        }
737
738                                        // Only add new deformer if we actually had any assignments
739                                        if (newDeformerEntry && atLeastOneAssignment)
740                                        {
741                                                mXsiDeformerMap[deformerName] = deformerEntry;
742                                        }
743
744
745
746                                       
747                                }
748                               
749
750                        }
751                }
752
753
754        }
755        //-----------------------------------------------------------------------
756        void XsiMeshExporter::exportProtoSubMeshes(Mesh* pMesh)
757        {
758                // Take the list of ProtoSubMesh instances and bake a SubMesh per
759                // instance, then clear the list
760
761                for (ProtoSubMeshList::iterator i = mProtoSubmeshList.begin();
762                        i != mProtoSubmeshList.end(); ++i)
763                {
764                        // export each one
765                        exportProtoSubMesh(pMesh, i->second);
766
767                        // free it
768                        delete i->second;
769                }
770                mProtoSubmeshList.clear();
771        }
772        //-----------------------------------------------------------------------
773        void XsiMeshExporter::exportProtoSubMesh(Mesh* pMesh, ProtoSubMesh* proto)
774        {
775                // Skip protos which have ended up empty
776                if (proto->indices.empty())
777                        return;
778
779        SubMesh* sm = 0;
780        if (proto->name.empty())
781        {
782            // anonymous submesh
783            sm = pMesh->createSubMesh();
784        }
785        else
786        {
787            // named submesh
788            sm = pMesh->createSubMesh(proto->name);
789        }
790
791        // Set material
792        sm->setMaterialName(proto->materialName);
793        // never use shared geometry
794        sm->useSharedVertices = false;
795        sm->vertexData = new VertexData();
796        // always do triangle list
797        sm->indexData->indexCount = proto->indices.size();
798               
799                sm->vertexData->vertexCount = proto->uniqueVertices.size();
800        // Determine index size
801        bool use32BitIndexes = false;
802        if (proto->uniqueVertices.size() > 65536)
803        {
804            use32BitIndexes = true;
805        }
806
807        sm->indexData->indexBuffer =
808            HardwareBufferManager::getSingleton().createIndexBuffer(
809            use32BitIndexes ? HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT,
810            sm->indexData->indexCount,
811            HardwareBuffer::HBU_STATIC_WRITE_ONLY);
812        if (use32BitIndexes)
813        {
814            uint32* pIdx = static_cast<uint32*>(
815                sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
816            writeIndexes(pIdx, proto->indices);
817            sm->indexData->indexBuffer->unlock();
818        }
819        else
820        {
821            uint16* pIdx = static_cast<uint16*>(
822                sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
823            writeIndexes(pIdx, proto->indices);
824            sm->indexData->indexBuffer->unlock();
825        }
826
827
828        // define vertex declaration
829        unsigned buf = 0;
830        size_t offset = 0;
831                // always add position and normal
832        sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT3, VES_POSITION);
833        offset += VertexElement::getTypeSize(VET_FLOAT3);
834        sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT3, VES_NORMAL);
835        offset += VertexElement::getTypeSize(VET_FLOAT3);
836        // split vertex data here if animated
837        if (pMesh->hasSkeleton())
838        {
839            buf++;
840            offset = 0;
841        }
842                // Optional vertex colour
843        if(proto->hasVertexColours)
844        {
845            sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_COLOUR, VES_DIFFUSE);
846            offset += VertexElement::getTypeSize(VET_COLOUR);
847        }
848        // Define UVs
849        for (unsigned short uvi = 0; uvi < proto->textureCoordDimensions.size(); ++uvi)
850        {
851                        VertexElementType uvType =
852                                VertexElement::multiplyTypeCount(
853                                        VET_FLOAT1, proto->textureCoordDimensions[uvi]);
854            sm->vertexData->vertexDeclaration->addElement(
855                                buf, offset, uvType, VES_TEXTURE_COORDINATES, uvi);
856            offset += VertexElement::getTypeSize(uvType);
857        }
858
859        // create & fill buffer(s)
860        for (unsigned short b = 0; b <= sm->vertexData->vertexDeclaration->getMaxSource(); ++b)
861        {
862            createVertexBuffer(sm->vertexData, b, proto->uniqueVertices);
863        }
864
865                // deal with any bone assignments
866                if (!proto->boneAssignments.empty())
867                {
868                        // rationalise first (normalises and strips out any excessive bones)
869                        sm->parent->_rationaliseBoneAssignments(
870                                sm->vertexData->vertexCount, proto->boneAssignments);
871
872                        for (Mesh::VertexBoneAssignmentList::iterator bi = proto->boneAssignments.begin();
873                                bi != proto->boneAssignments.end(); ++bi)
874                        {
875                                sm->addBoneAssignment(bi->second);
876                        }
877                }
878               
879        }
880        //-----------------------------------------------------------------------
881        void XsiMeshExporter::buildPolygonMeshList(bool includeChildren)
882        {
883                Selection sel(mXsiApp.GetSelection());
884                if (sel.GetCount() == 0)
885                {
886                        // Whole scene
887                        // Derive the scene root
888                        X3DObject sceneRoot(mXsiApp.GetActiveSceneRoot());
889                        findPolygonMeshes(sceneRoot, true);
890                }
891                else
892                {
893                        // iterate over selection
894                        for (int i = 0; i < sel.GetCount(); ++i)
895                        {
896                                X3DObject obj(sel[i]);
897                                findPolygonMeshes(obj,includeChildren);
898                        }
899                }
900        }
901        //-----------------------------------------------------------------------
902        void XsiMeshExporter::findPolygonMeshes(X3DObject& x3dObj, bool recurse)
903        {
904                // Check validity of current object
905                if (!x3dObj.IsValid())
906                {
907                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
908                                "Invalid X3DObject found",
909                                "XsiMeshExporter::exportX3DObject");
910                }
911                // Log a message in script window
912                CString name = x3dObj.GetName() ;
913                LogOgreAndXSI(L"-- Traversing " +  name) ;
914
915
916                // locate any geometry
917                if (!x3dObj.IsA(siCameraID) &&
918                        !x3dObj.IsA(siLightID) &&
919                        !x3dObj.IsA(siNullID) &&
920                        !x3dObj.IsA(siModelID))
921                {
922                        Primitive prim(x3dObj.GetActivePrimitive());
923                        if (prim.IsValid())
924                        {
925                                Geometry geom(prim.GetGeometry());
926                                if (geom.GetRef().GetClassID() == siPolygonMeshID)
927                                {
928                                        // add it to the list
929                                        PolygonMesh pmesh(geom);
930                                        mXsiPolygonMeshList.insert(
931                                                new PolygonMeshEntry(pmesh, x3dObj));
932
933                                        LogOgreAndXSI(L"-- Queueing " +  name) ;
934                                }
935                        }
936
937                }
938
939                // Cascade into children
940                if (recurse)
941                {
942                        CRefArray children = x3dObj.GetChildren();
943
944                        for(long i = 0; i < children.GetCount(); i++)
945                        {
946                                X3DObject childObj = children[i];
947                                findPolygonMeshes(childObj, recurse);
948                        }
949                }
950
951        }
952    //-----------------------------------------------------------------------
953        void XsiMeshExporter::cleanupPolygonMeshList(void)
954        {
955                for (PolygonMeshList::iterator pm = mXsiPolygonMeshList.begin();
956                        pm != mXsiPolygonMeshList.end(); ++pm)
957                {
958                        delete *pm;
959                }
960                mXsiPolygonMeshList.clear();
961        }
962        //-----------------------------------------------------------------------
963        void XsiMeshExporter::cleanupDeformerMap(void)
964        {
965                for (DeformerMap::iterator d = mXsiDeformerMap.begin();
966                        d != mXsiDeformerMap.end(); ++d)
967                {
968                        delete d->second;
969                }
970                mXsiDeformerMap.clear();
971        }
972        //-----------------------------------------------------------------------
973        void XsiMeshExporter::cleanupMaterialMap(void)
974        {
975                for (MaterialMap::iterator d = mXsiMaterialMap.begin();
976                        d != mXsiMaterialMap.end(); ++d)
977                {
978                        delete d->second;
979                }
980                mXsiMaterialMap.clear();
981        }
982        //-----------------------------------------------------------------------
983        void XsiMeshExporter::deriveSamplerIndices(const Triangle& tri,
984                const PolygonFace& face, size_t* samplerIndices)
985        {
986                //We want to find what is the SampleIndex associated with 3
987                //vertex in a Triangle
988                CPointRefArray facePoints = face.GetPoints();
989
990                //Get the position of the 3 vertex in the triangle
991                MATH::CVector3Array triPos = tri.GetPositionArray();
992
993                //Get the position of the N Points in the polygon
994                MATH::CVector3Array facePos = facePoints.GetPositionArray();
995
996                //To know if the 3 vertex have a point in the same position
997                bool found[3];
998                found[0] = false;
999                found[1] = false;
1000                found[2] = false;
1001
1002                int p,t;
1003                //For the 3 triangle vertices
1004                for(t=0; t<3 ; t++)
1005                {       //for each polygon point
1006                        for(p=0; p<facePos.GetCount() && !found[t]; p++)
1007                        {
1008                                //Check if the position is the same
1009                                if(triPos[t] == facePos[p])
1010                                {
1011                                        //if so, we know the PolygonPointIndex of the TriangleVertex
1012                                        //then, we must find what is the sample index associated
1013                                        //with this Point
1014                                        samplerIndices[t] =
1015                                                getSamplerIndex(Facet(face), facePoints[p]);
1016                                        found[t] = true;
1017                                }
1018                        }
1019
1020                }
1021
1022                if (!found[0] || !found[1] || !found[2] )
1023                {
1024                        // Problem!
1025                        LogOgreAndXSI(L"!! Couldn't find a matching UV point!");
1026                }
1027
1028        }
1029        //-----------------------------------------------------------------------
1030        size_t XsiMeshExporter::getSamplerIndex(const Facet &f, const Point &p)
1031        {
1032                //This function check if a Sample is shared by a Facet and a Point
1033                //just by using the operator=
1034                //Only one Sample can be shared.
1035
1036                Sample curFacetSample;
1037                CSampleRefArray facetSamples( f.GetSamples() );
1038                CSampleRefArray pointSamples( p.GetSamples() );
1039
1040                for(int i = 0; i < facetSamples.GetCount(); i++ )
1041                {
1042
1043                        curFacetSample = Sample( facetSamples[i] );
1044
1045                        for(int j = 0; j < pointSamples.GetCount(); j++)
1046                        {
1047                                if(curFacetSample == Sample(pointSamples[j]))
1048                                {
1049                                        return curFacetSample.GetIndex();
1050                                }
1051                        }
1052                }
1053                // Problem!
1054                mXsiApp.LogMessage(L"!! Couldn't find a matching sample point!");
1055                return 0;
1056        }
1057    //-----------------------------------------------------------------------
1058    template <typename T>
1059    void XsiMeshExporter::writeIndexes(T* buf, IndexList& indexes)
1060    {
1061        IndexList::const_iterator i, iend;
1062        iend = indexes.end();
1063        for (i = indexes.begin(); i != iend; ++i)
1064        {
1065            *buf++ = static_cast<T>(*i);
1066        }
1067    }
1068    //-----------------------------------------------------------------------
1069    void XsiMeshExporter::createVertexBuffer(VertexData* vd,
1070                unsigned short bufIdx, UniqueVertexList& uniqueVertexList)
1071    {
1072        HardwareVertexBufferSharedPtr vbuf =
1073                        HardwareBufferManager::getSingleton().createVertexBuffer(
1074                vd->vertexDeclaration->getVertexSize(bufIdx),
1075                vd->vertexCount,
1076                HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1077        vd->vertexBufferBinding->setBinding(bufIdx, vbuf);
1078        size_t vertexSize = vd->vertexDeclaration->getVertexSize(bufIdx);
1079
1080        char* pBase = static_cast<char*>(
1081                                vbuf->lock(HardwareBuffer::HBL_DISCARD));
1082
1083        VertexDeclaration::VertexElementList elems =
1084                        vd->vertexDeclaration->findElementsBySource(bufIdx);
1085        VertexDeclaration::VertexElementList::iterator ei, eiend;
1086        eiend = elems.end();
1087        float* pFloat;
1088        RGBA* pRGBA;
1089
1090        UniqueVertexList::iterator srci = uniqueVertexList.begin();
1091
1092        for (size_t v = 0; v < vd->vertexCount; ++v, ++srci)
1093        {
1094            for (ei = elems.begin(); ei != eiend; ++ei)
1095            {
1096                VertexElement& elem = *ei;
1097                switch(elem.getSemantic())
1098                {
1099                case VES_POSITION:
1100                    elem.baseVertexPointerToElement(pBase, &pFloat);
1101                    *pFloat++ = srci->position.x;
1102                    *pFloat++ = srci->position.y;
1103                    *pFloat++ = srci->position.z;
1104                    break;
1105                case VES_NORMAL:
1106                    elem.baseVertexPointerToElement(pBase, &pFloat);
1107                    *pFloat++ = srci->normal.x;
1108                    *pFloat++ = srci->normal.y;
1109                    *pFloat++ = srci->normal.z;
1110                    break;
1111                case VES_DIFFUSE:
1112                    elem.baseVertexPointerToElement(pBase, &pRGBA);
1113                    *pRGBA = srci->colour;
1114                    break;
1115                case VES_TEXTURE_COORDINATES:
1116                    elem.baseVertexPointerToElement(pBase, &pFloat);
1117                                        for (int t = 0; t < VertexElement::getTypeCount(elem.getType()); ++t)
1118                                        {
1119                                                Real val = srci->uv[elem.getIndex()][t];
1120                                                *pFloat++ = val;
1121                                        }
1122                    break;
1123                }
1124            }
1125            pBase += vertexSize;
1126        }
1127        vbuf->unlock();
1128
1129    }
1130    //-----------------------------------------------------------------------
1131    size_t XsiMeshExporter::createOrRetrieveUniqueVertex(
1132                ProtoSubMesh* proto, size_t positionIndex,
1133                bool positionIndexIsOriginal, const UniqueVertex& vertex)
1134    {
1135                size_t lookupIndex;
1136                if (positionIndexIsOriginal)
1137                {
1138                        // look up the original index
1139                        IndexRemap::iterator remapi =
1140                                proto->posIndexRemap.find(positionIndex);
1141                        if (remapi == proto->posIndexRemap.end())
1142                        {
1143                                // not found, add
1144                                size_t realIndex = proto->uniqueVertices.size();
1145                                // add remap entry so we can find this again
1146                                proto->posIndexRemap[positionIndex] = realIndex;
1147                                proto->uniqueVertices.push_back(vertex);
1148                                return realIndex;
1149                        }
1150                        else
1151                        {
1152                                // Found existing mapping
1153                                lookupIndex = remapi->second;
1154                        }
1155                }
1156                else
1157                {
1158                        // Not an original index, index is real
1159                        lookupIndex = positionIndex;
1160                }
1161
1162                // If we get here, either the position isn't an original index (ie
1163                // we've already found that it doesn't match, and have cascaded)
1164                // or there is an existing entry
1165                // Get existing
1166            UniqueVertex& orig = proto->uniqueVertices[lookupIndex];
1167                // Compare, do we have the same details?
1168                if (orig == vertex)
1169                {
1170                        // ok, they match
1171                        return lookupIndex;
1172                }
1173                else
1174                {
1175            // no match, go to next or create new
1176                if (orig.nextIndex)
1177                {
1178                // cascade to the next candidate (which is a real index, not an original)
1179                return createOrRetrieveUniqueVertex(
1180                                                proto, orig.nextIndex, false, vertex);
1181            }
1182                        else
1183                        {
1184                                // No more cascades to check, must be a new one
1185                    // get new index
1186                size_t realIndex = proto->uniqueVertices.size();
1187                    orig.nextIndex = realIndex;
1188                // create new (NB invalidates 'orig' reference)
1189                proto->uniqueVertices.push_back(vertex);
1190                                // note, don't add to remap, that's only for finding the
1191                                // first entry, nextIndex is used to chain to the others
1192
1193                return realIndex;
1194                        }
1195                }
1196    }
1197    //-----------------------------------------------------------------------
1198        void XsiMeshExporter::registerMaterial(const String& name,
1199                XSI::Material mat)
1200        {
1201                // Check we have a real-time shader based material first
1202                XSI::Parameter rtParam = mat.GetParameter(L"RealTime");
1203               
1204                if(rtParam.GetSource().IsValid() &&
1205                        rtParam.GetSource().IsA(XSI::siShaderID))
1206                {
1207                        MaterialMap::iterator i = mXsiMaterialMap.find(name);
1208                        if (i == mXsiMaterialMap.end())
1209                        {
1210                                // Add this one to the list
1211                                MaterialEntry* matEntry = new MaterialEntry();
1212                                matEntry->name = name;
1213                                matEntry->xsiShader = XSI::Shader(rtParam.GetSource());
1214                                mXsiMaterialMap[name] = matEntry;
1215                        }
1216                }
1217        }
1218}
Note: See TracBrowser for help on using the repository browser.